将字段追加到大小为ONE的结构化数组时发生TypeError



当我试图将字段附加到大小为ONE的结构化数组时,遇到了一个运行时错误。我在下面写了一个简单的例子:

import numpy as np
import numpy.lib.recfunctions as rcfuncs
dtype_ = np.dtype( { 'names': ["field_a","field_b","field_c"]
                  , 'formats': ['S32', 'i4', 'f8']}
                  )
data_ = [("1",17, 123.45)]
numpy_array = np.array(data_, dtype_)            
# append 2 fields
numpy_array = rcfuncs.append_fields( numpy_array,["field_d","field_e"],data=[ "1","3" ] )
# append 1 field fails :(
numpy_array = rcfuncs.append_fields( numpy_array, "field_f", data=["123456"] )

我得到错误:

TypeError: descriptor 'ravel' requires a 'numpy.ndarray' object but received a 'numpy.void'

同样,如果我"反转"append,那么带有两个append字段的语句将失败:

# append 1 field
numpy_array = rcfuncs.append_fields( numpy_array, "field_f", data=["123456"] )
# append 2 fields fails :(
numpy_array = rcfuncs.append_fields( numpy_array,["field_d","field_e"],data=[ "1", "3" ] )

我运行的是python 2.7.11和numpy 1.11.0,当初始数组的大小大于2时,我没有问题。

如何解决类型错误?

感谢

当将可选参数usemask设置为False 时,我们不会得到TypeError

numpy_array = 
  rcfuncs.append_fields(numpy_array, "field_f", data=["123456"], usemask=False)
numpy_array = 
  rcfuncs.append_fields(numpy_array,["field_d","field_e"],data=[ "1", "3" ], usemask=False)

为了参考,这里有完整的回溯

从一个结构化数组开始,有一条记录:

array([('1', 17, 123.45)], 
      dtype=[('field_a', 'S32'), ('field_b', '<i4'), ('field_c', '<f8')])

在第一次附加之后,我们有一个掩码数组,仍然有1个记录:

masked_array(data = [('1', 17, 123.45, '1', '3')],
             mask = [(False, False, False, False, False)],
       fill_value = ('N/A', 999999, 1e+20, 'N', 'N'),
            dtype = [('field_a', 'S32'), ('field_b', '<i4'), ('field_c', '<f8'), ('field_d', 'S1'), ('field_e', 'S1')])

这个错误看起来更多地与屏蔽数组代码有关,而不是与recfunctions有关——尽管我必须查看代码以了解它为什么使用ravel

Traceback (most recent call last):
  File "stack36440557.py", line 15, in <module>
    numpy_array2 = rcfuncs.append_fields( numpy_array1, "field_f", data=["123456"] ,usemask=False)
  File "/usr/local/lib/python2.7/site-packages/numpy/lib/recfunctions.py", line 633, in append_fields
    base = merge_arrays(base, usemask=usemask, fill_value=fill_value)
  File "/usr/local/lib/python2.7/site-packages/numpy/lib/recfunctions.py", line 389, in merge_arrays
    seqarrays = seqarrays.ravel()
  File "/usr/local/lib/python2.7/site-packages/numpy/ma/core.py", line 4022, in ravel
    r = ndarray.ravel(self._data).view(type(self))
TypeError: descriptor 'ravel' requires a 'numpy.ndarray' object but received a 'numpy.void'

因此,一个解决方案是关闭masked_arrays的使用。除非添加的字段缺少一些数据,否则不需要这样做。

另一种是将第一个参数放在列表中:

rcfuncs.append_fields( [numpy_array1], "field_f", data=['12345'])

append_fields(base, ....)调用

merge_arrays(base, usemask=usemask, fill_value=fill_value)

它又调用

base.ravel()  # now call seq_arrays

但首先它检查它的长度是一个

# Only one item in the input sequence ?
if (len(seqarrays) == 1):
    seqarrays = np.asanyarray(seqarrays[0])

对于简单结构的阵列y及其屏蔽等效物ym:

In [405]: y
Out[405]: 
array([(b'xxx', 1)], 
      dtype=[('f0', 'S5'), ('f1', '<i4')])
In [406]: ym=np.ma.masked_array(y)

这个长度为1的动作为规则结构的数组生成另一个数组:

In [407]: np.asanyarray(y[0])
Out[407]: 
array((b'xxx', 1), 
      dtype=[('f0', 'S5'), ('f1', '<i4')])

但是对于掩蔽的一个:的void(结构化阵列记录/元素)

In [408]: np.asanyarray(ym[0])
Out[408]: (b'xxx', 1)
In [409]: type(np.asanyarray(ym[0]))
Out[409]: numpy.ma.core.mvoid

np.asanyarray(ym[0]).ravel()产生此TypeError。

如果基是一个列表,[ym],这只是提取ym。如果基数是(2,)或更长,则它不会通过此语句。

我还没有想过修复——除了在列表中传递屏蔽数组的用户级笨拙。


一个可能的解决方案是简单地删除此base=merge_arrays(base...)行(在append_fields中)。但我首先需要知道它为什么会在那里。其目的可能是清除某些base阵列输入。

单元测试文件test/test_recfunctions.py运行良好,注释掉了这一行。

我已经在一个旧的numpy问题中添加了对此的评论

https://github.com/numpy/numpy/issues/2346

最新更新