不丢失recarray特性的叠加numpy recarrays

12 投票
3 回答
4583 浏览
提问于 2025-04-15 16:20

假设我创建了两个具有相同数据类型的记录数组(recarray),然后把它们叠加在一起:

>>> import numpy as np
>>> dt = [('foo', int), ('bar', float)]
>>> a = np.empty(2, dtype=dt).view(np.recarray)
>>> b = np.empty(3, dtype=dt).view(np.recarray)
>>> c = np.hstack((a,b))

虽然 ab 是记录数组,但 c 不是:

>>> c.foo
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'numpy.ndarray' object has no attribute 'foo'
>>> d = c.view(np.recarray)
>>> d.foo
array([                  0,     111050731618561,                   0,
                   7718048, 8246760947200437872])

我当然可以像上面用 d 展示的那样,把它重新变成记录数组,但这样做不太方便。难道叠加两个记录数组不产生另一个记录数组是有原因的吗?

3 个回答

-2

顺便提一下,你还可以使用:

c = np.concatenate((a,b))

或者

c = np.r_[a, b]

( 来源:这个邮件列表的消息 )

13

另外,我发现了在 numpy.lib.recfunctions 中有一些辅助工具,这个模块里有一些函数可以用来合并和堆叠 recarrays

from numpy.lib.recfunctions import stack_arrays
c = stack_arrays((a, b), asrecarray=True, usemask=False)
c.foo
>>> array([     140239282560000,           4376479720, -4611686018427387904,
                     4358733828,           4365061216])

如果你想给一个 recarray 添加额外的列,可以使用 merge_arrays 来实现:

import numpy as np
from numpy.lib.recfunctions import merge_arrays
dt1 = [('foo', int), ('bar', float)]
dt2 = [('foobar', int), ('barfoo', float)]
aa = np.empty(6, dtype=dt1).view(np.recarray)
bb = np.empty(6, dtype=dt2).view(np.recarray)

cc = merge_arrays((aa, bb), asrecarray=True, flatten=True)
type(cc)
>>> numpy.core.records.recarray

(虽然这不是问题的答案,但我把这个例子发出来作为参考)

9

我也不太清楚。很可能这是一个bug,或者是一个从来没有实现的功能。numpy.hstack其实就是一个函数的包装器,这个函数在numpy.core.fromnumeric里。Numeric是numpy的两个前身之一。大多数numpy的函数都有一个约定,就是输出的类型和输入的类型要一致,方法是调用输入的__array_wrap__方法在输出上,这样得到的输出应该有相同的数据,但“包装”成了新的类。也许在numeric中没有“包装”这个概念,所以这个函数就没有添加这个功能。

你可以用这个技巧来制作一个更智能的堆叠函数。

def hstack2(arrays) :
  return arrays[0].__array_wrap__(numpy.hstack(arrays))

这个方法适用于结构数组和普通数组。

>>> f = hstack2((a,b))
>>> type(f)
<class 'numpy.core.records.recarray'>
>>> f.foo
array([    140633760262784,     111050731618561,     140633760262800,
                   7536928, 8391166428122670177])
>>> x = numpy.random.rand(3)
>>> y = numpy.random.rand(2)
>>> z = hstack2((x,y))
>>> type(z)
<type 'numpy.ndarray'>

我不太确定你打算怎么做,但你可能想在numpy邮件列表上问问,看看有没有比使用文档中提到的双下划线方法更好的办法,以及他们为什么不自己进行包装。

撰写回答