In [161]: a = np.zeros(3, dtype={'names':['A','B','C'], 'formats':['int','int','
...: float']})
...: for i in range(len(a)):
...: a[i] = i
...:
In [162]: a
Out[162]:
array([(0, 0, 0.), (1, 1, 1.), (2, 2, 2.)],
dtype=[('A', '<i8'), ('B', '<i8'), ('C', '<f8')])
定义新的数据类型:
In [164]: a.dtype.descr
Out[164]: [('A', '<i8'), ('B', '<i8'), ('C', '<f8')]
In [165]: a.dtype.descr+[('test','O')]
Out[165]: [('A', '<i8'), ('B', '<i8'), ('C', '<f8'), ('test', 'O')]
In [166]: dt= a.dtype.descr+[('test','O')]
正确大小和 dtype 的新数组:
In [167]: b = np.empty(a.shape, dt)
按字段名称从a
to复制值: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
功能通过字段复制来完成此字段:
rf.recursive_fill_fields(a,b)
rf.append_fields
output
在初始化它的数组后使用它。
在早期版本中,多字段索引会生成一个副本,因此类似的表达式b[list(a.dtype.names)] = a
不起作用。
我不知道是否值得尝试弄清楚在rf.append_fields
做什么。这些功能有些陈旧,并且没有大量使用(注意特殊导入)。因此,它们完全有可能存在不起作用的错误或边缘情况。我检查过的函数的功能与我演示的差不多——创建一个新的 dtype、结果数组,并按字段名称复制数据。
在最近的版本中,访问多个字段的方式发生了变化。有一些新功能recfunctions
可以促进使用结构化数组,例如repack_fields
.
https://docs.scipy.org/doc/numpy/user/basics.rec.html#accessing-multiple-fields
我不知道这是否适用于这个append_fields
问题。我看到还有一个关于带有对象的结构化数组的部分,但我没有研究过:
https://docs.scipy.org/doc/numpy/user/basics.rec.html#viewing-structured-arrays- contains-objects
为了防止在 numpy.object 类型的字段中破坏对象指针,numpy 当前不允许查看包含对象的结构化数组。
这条线显然是指使用view
方法。由字段索引创建的视图,无论是单名称还是多字段列表,都不会受到影响。
错误append_fields
来自此操作:
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.
使用对象 dtypes 创建复合 dtype 没有问题:
In [186]: np.array([None,None,None], dtype=[('test',object)])
Out[186]: array([(None,), (None,), (None,)], dtype=[('test', 'O')])
但我没有看到任何recfunctions
能够加入a
和data
.
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')])
b
但出于同样的原因尝试这样做失败:
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.
我从一个对象 dtype 数组开始,并尝试view
使用i8
(相同大小的 dtype),我得到了同样的错误。因此,view
对象 dtype 的限制不仅限于结构化数组。在对象指针的情况下需要这样的限制i8
是有道理的。在将对象指针嵌入复合 dtype 的情况下,对这种限制的需求可能并不那么引人注目。它甚至可能是矫枉过正,或者只是简单地玩安全和简单的情况。
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.
请注意,第 493 行中的测试检查hasobject
新旧 dtype 的属性。一个更细微的测试可能会检查是否两者hasobject
,但我怀疑逻辑可能会变得相当复杂。有时,简单的禁止比一组复杂的测试更安全(也更容易)。
在进一步测试中
In [283]: rf.structured_to_unstructured(a)
Out[283]:
array([[ 3., 3., 0.],
[12., 10., 1.],
[ 2., 2., 2.]])
但是尝试对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']]))