gpt4 book ai didi

python - 假设您向结构化数组的一维切片添加了一个新字段,为什么不能将新字段的条目设置为列表?

转载 作者:行者123 更新时间:2023-12-01 06:33:48 25 4
gpt4 key购买 nike

标题可能有点令人困惑,所以我希望能通过一个例子让它更清楚。我有一个小辅助函数,可以将新字段添加到现有的结构化数组中:

import numpy as np


def add_field(a, *descr):
b = np.empty(a.shape, dtype=a.dtype.descr + [*descr])
for name in a.dtype.names:
b[name] = a[name]
return b

给定一个结构化数组,我可以简单地使用它来添加新字段:

a = np.array(
[(1, False), (2, False), (3, False), (4, True)],
dtype=[('id', 'i4'), ('used', '?')]
)
print(a)
b = add_field(a, ('new', 'O'))
print(b)

然后我可以毫无问题地将新创建的字段的条目设置为(空)列表:

b[0]['new'] = []

我还可以创建一个新数组,它只是原始数组的一部分,然后向这个新数组添加一个新字段:

c = a[0]
print(c)
d = add_field(c, ('newer', 'O'))
print(d)

但是如果我现在尝试将新字段设置为(空)列表,则它不起作用:

d['newer'] = []

ValueError: assignment to 0-d array

这是为什么呢?根据 add_field 的说法,d 是一个全新的数组,它恰好与 b 一样共享相同的字段和条目。有趣的是,b[0] 的形状是 (),而 d 的形状是 (1,) (type(b)np.voidtype(d)np.array) 。也许这有什么关系?同样有趣的是,所有这些都有效:

d['newer'] = 1.34
d['newer'] = False
d['newer'] = None
d['newer'] = add_field
d['newer'] = set()
d['newer'] = {}
d['newer'] = {'test': []}

但是,使用键 'test' 访问最后一个 dict 中的值不会:

>>> d['newer'] = {'test': []}
>>> d['newer']
>>> array({'test': []}, dtype=object)
>>> d['newer']['test']
>>> IndexError: only integers, slices (`:`), ellipsis (`...`), numpy.newaxis (`None`) and integer or boolean arrays are valid indices
>>> d['newer'][0]
>>> IndexError: too many indices for array

这非常令人困惑。

编辑

好吧,我只是尝试修改 add_field 函数,如下所示:

def add_field(a, *descr):
shape = a.shape if len(a.shape) else (1,)
b = np.empty(shape, dtype=a.dtype.descr + [*descr])
for name in a.dtype.names:
b[name] = a[name]
return b

但这没有帮助:

>>> d = add_field(a[0], ('newer', 'O'))
>>> d
>>> array([(1, False, None)], dtype=[('id', '<i4'), ('used', '?'), ('test', 'O')])
>>> d.shape
>>> (1,)
>>> d['newer'] = []
>>> ValueError: cannot copy sequence with size 0 to array axis with dimension 1

所以我猜这不是它。然而现在这可以工作了:

>>> d['newer'][0] = []

但我不喜欢这种解决方法。我希望它的工作方式与 b[0] 相同。

编辑2

如果我进一步修改 add_field 函数,我可以强制执行所需的行为,尽管我并不 100% 喜欢它:

def add_field(a, *descr):
shape = a.shape if len(a.shape) else (1,)
b = np.empty(shape, dtype=a.dtype.descr + [*descr])
for name in a.dtype.names:
b[name] = a[name]
return b if len(a.shape) else b[0]

d = add_field(a[0], ('newer', 'O'))
d['newer'] = []

最佳答案

总结评论:

原始问题中的问题似乎是返回对象的形状 - 例如,当您这样做时

c = a[0]

对于形状为(n,)a,您不是从数组中获取切片,而是从单个元素中获取。 c.shape 则为 ()。当您将形状为 () 的数组传递到 add_field 时,则由

创建的新数组
b = np.empty(a.shape, dtype=a.dtype.descr + [*descr])

也将具有形状()。但是,结构化数组必须具有形状 (n,) (尽管 documentation 中没有概述)。

与问题的第一次编辑一样,正确的修改是

def add_field(a, *descr):
shape = a.shape if len(a.shape) else (1,)
b = np.empty(shape, dtype=a.dtype.descr + [*descr])
b[list(a.dtype.names)] = a
return b

返回的对象将共享形状(n,) 结构化数组的属性:

  1. 如果在整数位置索引数组,您将获得一个结构(例如 d[0])
  2. 您可以通过使用字段名称进行索引(例如 d['newer'])来访问和修改结构化数组的各个字段

经过上述修改,问题中 d 的行为与 b 相同,例如

d[0]['newer'] = []

有效,原样

b[0]['new'] = []

这给我们带来了问题的真正症结:

<小时/>

为什么我们不能使用 d['newer']=[] 语法为字段的每个元素分配一个空列表?

    当您使用此语法分配可迭代对象而不是标量时,numpy 会尝试按元素分配(或根据可迭代对象进行广播)。这与标量的分配不同,其中标量被分配给该字段的每个元素。 documentation关于这一点尚不清楚,但我们可以通过使用

获得更有用的错误
b['new'] = np.array([])
Traceback (most recent call last):
File "structuredArray.py", line 20, in <module>
b['new'] = np.array([])
ValueError: could not broadcast input array from shape (0) into shape (4)

因此,这里的问题不是如何添加字段,而是如何尝试为该字段的每个元素分配一个空列表。正确的方法是这样的

b['new'] = [[]*b.shape[0]]

对于 (1,)(4,) 形状的结构化数组按预期工作:

import numpy as np

def add_field(a, *descr):
shape = a.shape if len(a.shape) else (1,)
b = np.empty(shape, dtype=a.dtype.descr + [*descr])
for name in a.dtype.names:
b[name] = a[name]
return b

a = np.array(
[(1, False), (2, False), (3, False), (4, True)],
dtype=[('id', 'i4'), ('used', '?')]
)

b = add_field(a, ('new', 'O'))
b['new'] = [[]*b.shape[0]]
print(b)

c = a[0]
d = add_field(c, ('newer', 'O'))
d['newer'] = [[]*d.shape[0]]
print(d)
[(1, False, list([])) (2, False, list([])) (3, False, list([])) (4,  True, list([]))]
[(1, False, list([]))]

关于python - 假设您向结构化数组的一维切片添加了一个新字段,为什么不能将新字段的条目设置为列表?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59766006/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com