Python 添加和访问numpy结构化数组的对象类型字段
我正在使用NUMPY1.16.2 简而言之,我想知道如何将对象类型字段添加到结构化数组。通过Python 添加和访问numpy结构化数组的对象类型字段,python,numpy,structured-array,Python,Numpy,Structured Array,我正在使用NUMPY1.16.2 简而言之,我想知道如何将对象类型字段添加到结构化数组。通过recfunctions模块的标准方法会抛出错误,我想这是有原因的。因此,我想知道我的变通方法是否有问题。此外,我想了解为什么需要这种变通方法,以及在访问新创建的阵列时是否需要格外小心 现在详细信息来了: 我有一个numpy结构阵列: import numpy as np a = np.zeros(3, dtype={'names':['A','B','C'], 'formats':['int','int
recfunctions
模块的标准方法会抛出错误,我想这是有原因的。因此,我想知道我的变通方法是否有问题。此外,我想了解为什么需要这种变通方法,以及在访问新创建的阵列时是否需要格外小心
现在详细信息来了:
我有一个numpy结构阵列:
import numpy as np
a = np.zeros(3, dtype={'names':['A','B','C'], 'formats':['int','int','float']})
for i in range(len(a)):
a[i] = i
我想在数组a
中添加另一个类型为object
的字段“test”。执行此操作的标准方法是使用numpy的recfunctions
模块:
import numpy.lib.recfunctions as rf
b = rf.append_fields(a, "test", [None]*len(a))
此代码引发一个错误:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-38-4a7be4f94686> in <module>
----> 1 rf.append_fields(a, "test", [None]*len(a))
D:\_Programme\Anaconda3\lib\site-packages\numpy\lib\recfunctions.py in append_fields(base, names, data, dtypes, fill_value, usemask, asrecarray)
718 if dtypes is None:
719 data = [np.array(a, copy=False, subok=True) for a in data]
--> 720 data = [a.view([(name, a.dtype)]) for (name, a) in zip(names, data)]
721 else:
722 if not isinstance(dtypes, (tuple, list)):
D:\_Programme\Anaconda3\lib\site-packages\numpy\lib\recfunctions.py in <listcomp>(.0)
718 if dtypes is None:
719 data = [np.array(a, copy=False, subok=True) for a in data]
--> 720 data = [a.view([(name, a.dtype)]) for (name, a) in zip(names, data)]
721 else:
722 if not isinstance(dtypes, (tuple, list)):
D:\_Programme\Anaconda3\lib\site-packages\numpy\core\_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
这很有效。不过,我有以下问题:
问题
- 为什么需要这种解决方法?这只是一个bug吗
- 使用新阵列
与使用b
似乎没有什么不同。变量a
显然是c=b[[“A”,“test”]
数据的视图。那么为什么数组b
上的视图不受支持呢?我必须格外小心地对待b
c
a
复制到b
:
In [168]: for name in a.dtype.names:
...: b[name] = a[name]
...:
In [169]: b
Out[169]:
array([(0, 0, 0., None), (1, 1, 1., None), (2, 2, 2., None)],
dtype=[('A', '<i8'), ('B', '<i8'), ('C', '<f8'), ('test', 'O')])
rf.append\u字段
在初始化其输出
数组后使用它
在早期版本中,多字段索引生成一个副本,因此像b[list(a.dtype.names)]=a
这样的表达式不起作用
我不知道是否值得尝试去弄清楚
rf.append\u字段
在做什么。这些函数有些陈旧,使用不多(请注意特殊导入)。所以他们很可能有bug,或者边缘案例,这些都不起作用。我所研究的函数与我所演示的非常相似——创建一个新的数据类型和结果数组,并按字段名复制数据
在最近的版本中,访问多个字段的方式发生了变化。recfunctions
中有一些新函数,以便于使用结构化数组,例如repack\u字段
我不知道这是否适用于append\u字段
问题。我看到还有一节是关于带对象的结构化数组的,但我没有研究过:
为了防止在numpy.object类型的字段中重击对象指针,numpy当前不允许查看包含对象的结构化数组
这一行显然是指使用view
方法。通过字段索引创建的视图,无论是单字段列表还是多字段列表,都不受影响
append\u字段中的错误来自此操作:
In [183]: data = np.array([None,None,None])
In [184]: data
Out[184]: array([None, None, None], dtype=object)
In [185]: data.view([('test',object)])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-185-c46c4464b53c> in <module>
----> 1 data.view([('test',object)])
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
但是我没有看到任何能够连接a
和数据的recfunctions
view
可用于更改a
的字段名:
In [219]: a.view([('AA',int),('BB',int),('cc',float)])
Out[219]:
array([(0, 0, 0.), (1, 1, 1.), (2, 2, 2.)],
dtype=[('AA', '<i8'), ('BB', '<i8'), ('cc', '<f8')])
我从一个对象数据类型数组开始,尝试使用i8
(相同大小的数据类型)查看view
,我得到了同样的错误。因此,对对象数据类型的视图的限制并不局限于结构化数组。在对象指针指向i8
的情况下,需要这样的限制是有意义的。在将对象指针嵌入复合数据类型的情况下,需要这样的限制可能不是很有说服力。这甚至可能是矫枉过正,或者只是一个简单安全的例子
In [267]: x.dtype
Out[267]: dtype('O')
In [268]: x.shape
Out[268]: (3,)
In [269]: x.dtype.itemsize
Out[269]: 8
In [270]: x.view('i8')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-270-30c78b13cd10> in <module>
----> 1 x.view('i8')
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
但尝试在b
或其字段的子集上执行相同操作会产生常见错误:
rf.structured_to_unstructured(b)
rf.structured_to_unstructured(b[['A','B','C']])
我必须首先使用repack
制作无对象副本:
rf.structured_to_unstructured(rf.repack_fields(b[['A','B','C']]))
我不认为recfunctions
是标准的。它们是可以使用的实用程序,但您不必使用它们。它们没有被编译,因此不能做任何没有它们不能做的事情。-基本上是相同的问题,尝试使用对象数据类型的append\u fields
。另一种方法是附加一个datetime64
字段。谢谢您的回答。你能指出你的解决方案和我最初的不同吗?numpy最近的变化正是我不得不问这个问题的原因。你介意回答我提出的其他问题吗?到目前为止,对我来说唯一新的信息是,recfunctions
是旧的和非标准的。在您的解决方案和我的解决方案之间可能没有任何真正的区别。我只是想自己思考一下这个问题。谢谢你更新你的答案。我知道错误是在哪里产生的;我把错误信息放在我的问题里。(我真的很感谢您的努力,但您真的读过这个问题吗?)生成的数组的行为是否会与标准数组不同(由于提到的“视图”问题)?您是否在寻求更深入的答案b.view(b.dtype)
似乎是唯一有效的.view
表达式。使用a.view(…)
我可以更改字段名。我不能用b
。它会引发相同的\u内部错误。通过b
的字段索引创建的视图
是另一回事。您对b[list(a.dtype.names)]=a
的使用取决于最新版本,其中多字段索引生成视图。以前的版本复制了一份。我迭代了字段名,这在前面的代码中起作用。参见rf.递归填充字段(a,b)
In [183]: data = np.array([None,None,None])
In [184]: data
Out[184]: array([None, None, None], dtype=object)
In [185]: data.view([('test',object)])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-185-c46c4464b53c> in <module>
----> 1 data.view([('test',object)])
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
In [186]: np.array([None,None,None], dtype=[('test',object)])
Out[186]: array([(None,), (None,), (None,)], dtype=[('test', 'O')])
In [219]: a.view([('AA',int),('BB',int),('cc',float)])
Out[219]:
array([(0, 0, 0.), (1, 1, 1.), (2, 2, 2.)],
dtype=[('AA', '<i8'), ('BB', '<i8'), ('cc', '<f8')])
In [220]: b.view([('AA',int),('BB',int),('cc',float),('d',object)])
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-220-ab0a6e4dd57f> in <module>
----> 1 b.view([('AA',int),('BB',int),('cc',float),('d',object)])
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
In [267]: x.dtype
Out[267]: dtype('O')
In [268]: x.shape
Out[268]: (3,)
In [269]: x.dtype.itemsize
Out[269]: 8
In [270]: x.view('i8')
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-270-30c78b13cd10> in <module>
----> 1 x.view('i8')
/usr/local/lib/python3.6/dist-packages/numpy/core/_internal.py in _view_is_safe(oldtype, newtype)
492
493 if newtype.hasobject or oldtype.hasobject:
--> 494 raise TypeError("Cannot change data-type for object array.")
495 return
496
TypeError: Cannot change data-type for object array.
In [283]: rf.structured_to_unstructured(a)
Out[283]:
array([[ 3., 3., 0.],
[12., 10., 1.],
[ 2., 2., 2.]])
rf.structured_to_unstructured(b)
rf.structured_to_unstructured(b[['A','B','C']])
rf.structured_to_unstructured(rf.repack_fields(b[['A','B','C']]))