Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/288.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 既然在结构化数组的一维切片中添加了一个新字段,为什么不能将新字段的条目设置为列表?_Python_List_Numpy_Field_Structured Array - Fatal编程技术网

Python 既然在结构化数组的一维切片中添加了一个新字段,为什么不能将新字段的条目设置为列表?

Python 既然在结构化数组的一维切片中添加了一个新字段,为什么不能将新字段的条目设置为列表?,python,list,numpy,field,structured-array,Python,List,Numpy,Field,Structured Array,标题可能有点混乱,所以我希望通过一个例子可以让它更清楚。Image我有一个小助手函数,它可以将新字段添加到现有的结构化数组中: 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 给定一个结构化数组,

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

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,)
(而且
类型(b)
np.void
,而
类型(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”
访问上一个
命令中的vaues不会:

>>> 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_字段
函数,如下所示:

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
但我不喜欢这种变通方法。我希望它的工作原理与
b[0]
相同

编辑2

如果我进一步修改
add_字段
函数,我可以强制执行想要的行为,尽管我不是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]
如果
a
具有形状
(n,)
,则不是从数组中获取一个切片,而是从单个元素中获取<代码>c.shape
然后是
()
。当您将形状数组
()
传递到
添加字段中时,则

b=np.empty(a.shape,dtype=a.dtype.descr+[*descr])
还将具有形状
()
。但是,结构化数组必须具有shape
(n,)
(尽管在中没有列出)

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

def add_字段(a,*descr):
shape=a.shape如果len(a.shape)else(1,)
b=np.empty(shape,dtype=a.dtype.descr+[*descr])
b[列表(a.dtype.names)]=a
返回b
然后,返回的对象将共享形状
(n,)
结构化数组的属性,其中:

  • 如果在整数位置对数组进行索引,则会得到一个结构(例如
    d[0]
  • 您可以通过使用字段名(例如
    d['newer']
    )编制索引来访问和修改结构化数组的各个字段
  • 通过上述修改,问题中
    d
    的行为与
    b
    相同,例如

    d[0]['newer']=[]
    
    是有效的

    b[0]['new']=[]
    
    这就引出了问题的真正症结:


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

        使用此语法指定iterable而不是标量时,numpy会尝试按元素分配(或广播,具体取决于iterable)。这与标量赋值不同,标量赋值给该字段的每个元素。关于这一点,我们还不清楚,但是我们可以通过使用

    b['new']=np.array([]
    
    回溯(最近一次呼叫最后一次):
    文件“structuredArray.py”,第20行,在
    b['new']=np.array([]
    ValueError:无法将输入数组从形状(0)广播到形状(4)
    
    因此,这里的问题不是如何添加字段,而是如何尝试将空列表分配给该字段的每个元素。正确的方法是

    b['new']=[[]*b.shape[0]]
    
    对于
    (1,)
    (4,)
    形状的结构化数组,其工作原理与预期相同:

    将numpy导入为np
    def add_字段(a,*descr):
    shape=a.shape如果len(a.shape)else(1,)
    b=np.empty(shape,dtype=a.dtype.descr+[*descr])
    对于a.dtype.names中的名称:
    b[姓名]=a[姓名]
    返回b
    a=np.array(
    [(1,假)、(2,假)、(3,假)、(4,真)],
    数据类型=[('id','i4'),('used','?')]
    )
    b=添加_字段(a,('new','O'))
    b['new']=[[]*b.shape[0]]
    印刷品(b)
    c=a[0]
    d=添加_字段(c,('newer','O'))
    d['newer']=[[]*d.shape[0]]
    印刷品(d)
    
    [(1,False,list([])(2,False,list([]))(3,False,list([])(4,True,list([]))]
    [(1,False,列表([])]
    
    如果在结构化数组中占据较大的一部分,是否会发生同样的情况?例如,
    a[:2]
    你的意思是如果
    c=a[:2]
    ?在这种情况下,它是有效的。我觉得它与形状有关,因为
    add_field
    使用了输入数组的形状,并且由于某种原因
    a[0]
    的形状是
    ()
    ,尽管我猜它应该是
    (1,)
    ?当我测试它时
    d[0]['newer']=[/code>没有错误-在我看来
    d[0]
    与该编辑器的行为类似
    b[0]
    如果
    d.shape
    ()
    ,0d,则只能对其进行索引
    d[()]
    。对对象数据类型数组的列表分配可能会有广播问题哇,我甚至不知道
    [()]
    是一个有效的索引!疯了
    d['newer'][()]=[]
    实际上与原始添加字段版本一起工作。不过我还是很困惑。我只是想提一个我想出的小调整,可能会快一点。而不是for-yo循环
    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'] = []