当向大小为1的结构化数组中添加字段时出现TypeError错误。

4

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

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"] )

I'm getting the error:

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

同样,如果我“反转”附加操作的顺序,那么具有两个字段附加的语句将失败:
# 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时,我没有遇到这个问题。如何解决类型错误?谢谢。


这是 numpy 代码中轻度使用的区域 - 请注意您需要单独导入 rcfuncs - hpaulj
2个回答

3

当将可选参数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)

我刚刚发现了这个问题。默认情况下会生成一个掩码数组,但是显然在对掩码数组进行进一步追加时存在一个错误。这就是为什么第一次追加总是成功的,但第二次失败的原因。除非你需要掩码,否则可以保持不变,否则请考虑提交错误报告。或者我们可以深入研究append_fields代码。 - hpaulj
我会填写一个错误报告。 - stackoverflower
我找到了另一个解决方法,将第一个参数放入列表中:rcfuncs.append_fields( [numpy_array], "field_f", data=['12345'])。我会在我的答案中解释为什么这样做有效。 - hpaulj
@hpaulj:似乎检查原始数组是否具有大小为1的解决方案更好。我遇到了几种情况,使用可选参数usemask是不够的。谢谢。 - stackoverflower

2

供参考,以下是完整的回溯信息:

从一个结构化数组开始,其中包含一条记录:

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

首先它会检查它的长度是否为1

# 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,) 或更长,则不会通过此语句。

我还没有想到解决方法 - 除了将掩码数组传递到列表中的用户级别修补程序之外。


一个可能的解决方法是简单地删除 append_fields 中的 base=merge_arrays(base...) 这一行。但我需要知道它首先出现的原因。其目的可能是清理某些 base 数组输入。

单元测试文件 test/test_recfunctions.py 在注释掉此行后可以正常运行。

我已在旧的 numpy 问题上添加了评论。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接