当数组名称是 unicode 时,numpy recfunctions append_fields 会失败吗?

Does numpy recfunctions append_fields fail when when array names are unicode?

我正在尝试使用 numpy.lib.recfunctions append_fields 函数将数组附加到 numpy recarray。

如果 recarray 字段名称是 unicode,我会收到 "TypeError: data type not understood" 错误。

此行为是否符合设计?如果是,是否有解决方法?

在 Win32 计算机上使用 python 2.7。

下面的代码演示了这个问题(请原谅额外的日期时间操作 - 我想尽可能接近我原来的错误):

from datetime import datetime
import numpy as np
import numpy.lib.recfunctions as RF

x1=np.array([1,2,3,4])
x2=np.array(['a','dd','xyz','12'])
x3=np.array([1.1,2,3,4])

# this works
FileData = np.core.records.fromarrays([x1,x2,x3],names=['a','b','c'])
# this doesnt
#FileData = np.core.records.fromarrays([x1,x2,x3],names=[u'a',u'b',u'c'])

sDT = ['1/1/2000 12:00:00','1/1/2000 13:00:00','1/1/2000     14:00:00','1/1/2000 15:00:00']
pDT = [datetime.strptime(x, '%d/%m/%Y %H:%M:%S') for x in sDT]

# convert to unix timestamp
DT = [ (np.datetime64(dt) - np.datetime64('1970-01-01T00:00:00Z')) /     np.timedelta64(1, 's')  for dt in pDT]

# add datetime to recaray
print FileData.dtype
FileData = RF.append_fields(FileData,'DateTime', data=DT)  #, dtypes='f8'
print FileData.dtype

带有 unicode 名称的代码在 Python3 下运行良好,其中 unicode 是默认字符串类型。


编辑:最初我认为问题在于屏蔽数组。但是通过进一步测试,我得出结论 真正的问题是 dtype 是否可以接受 unicode(在 py2 情况下)名称。 通常名称必须是字符串(但是版本定义了它们)。但是定义 dtype 的字典样式允许使用 unicode 名称。这就是为什么您的 fromarrays 有效但 append_fields 无效的根本原因。

我将保留掩码数组的讨论,因为这是你接受的。

是否是掩码数组的问题?

2.7下,全错误栈为:

  File "stack28586238.py", line 22, in <module>
    FileData = RF.append_fields(FileData,'DateTime', data=DT)  #, dtypes='f8'
  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 403, in merge_arrays
    return seqarrays.view(dtype=seqdtype, type=seqtype)
  File "/usr/local/lib/python2.7/site-packages/numpy/core/records.py", line 501, in view
    return ndarray.view(self, dtype, type)
  File "/usr/local/lib/python2.7/site-packages/numpy/ma/core.py", line 2782, in __array_finalize__
    _mask = getattr(obj, '_mask', make_mask_none(obj.shape, odtype))
  File "/usr/local/lib/python2.7/site-packages/numpy/ma/core.py", line 1566, in make_mask_none
    result = np.zeros(newshape, dtype=make_mask_descr(dtype))
  File "/usr/local/lib/python2.7/site-packages/numpy/ma/core.py", line 1242, in make_mask_descr
    return np.dtype(_recursive_make_descr(ndtype, np.bool))
TypeError: data type not understood

错误发生在屏蔽数组函数中,调用如下:

np.ma.make_mask_none((3,),dtype=[(u'value','f4')])

我在之前的 SO 问题(不久前)中遇到了屏蔽数组的问题。我得看看有没有关系。


Is the mask of a structured array supposed to be structured itself?

没有直接关系,但它确实指出了混合掩码数组和结构化数组时的一些错误。

Adding datetime field to recarray 是你之前关于 add_fields 的 SO 问题,重点是 datetime 类型。

或者使用 unicode 名称定义 dtype 时出现问题?

通过添加 usemask=False 我将错误转移到另一点,它试图从两个组件 dtype 列表构造一个 dtypenp.dtype(base.dtype.descr + data.dtype.descr).

在2.7中,我们可以用unicode名称构造一个record array

In [11]: np.core.records.fromarrays([[0,1]],names=[u'test'])
Out[11]: 
rec.array([(0,), (1,)], 
      dtype=[(u'test', '<i4')])

但是我不能直接用unicode名称构造一个dtype:

In [12]: np.dtype([(u'test', int)])
...    
TypeError: data type not understood

似乎通常数据类型名称必须是字符串。在 python3 中,np.dtype([(b'test', int)]) 产生相同的错误。

也在py3中

np.core.records.fromarrays([[0,1]],names=[b'test'])

产生 ValueError: field names must be strings.

np.core.records.fromarrays 允许 unicode 因为它使用 format_parser:

p=np.format_parser(['int'],[u'test'],[])
p.dtype
# dtype([(u'test', '<i4')])

这是有效的,因为 dtype 定义的字典样式接受 unicode:

np.dtype({'names':[u'test'],'formats':['int']})

这是一个合并两个具有 unicode 名称的结构化数组的示例(在 py2 中工作):

In [53]: dt1 = np.dtype({'names':[u'test1'],'formats':['int']})
In [54]: dt2 = np.dtype({'names':[u'test2'],'formats':['float']})
In [55]: dt12 = np.dtype({'names':[u'test1',u'test2'],'formats':['int','float']})

In [56]: arr1 = np.array([(x,) for x in [1,2,3]],dtype=dt1)
In [57]: arr2 = np.array([(x,) for x in [1,2,3]],dtype=dt2)
In [58]: arr12 = np.zeros((3,),dtype=dt12)

In [59]: RF.recursive_fill_fields(arr1,arr12)
...

In [60]: RF.recursive_fill_fields(arr2,arr12)
Out[60]: 
array([(1, 1.0), (2, 2.0), (3, 3.0)], 
      dtype=[(u'test1', '<i4'), (u'test2', '<f8')])

append_fields 基本上就是这样做的(添加了一些花里胡哨的东西)。


我已经在 https://github.com/numpy/numpy/issues/2407 中添加了评论 dtype field names cannot be unicode (Trac #1814)