在NumPy中命名为元组的等价物?

时间:2011-09-20 18:28:41

标签: python collections numpy namedtuple

是否可以创建一个行为非常类似于collections.namedtuple的NumPy对象,因为可以像这样访问元素:

data[1] = 42
data['start date'] = '2011-09-20'  # Slight generalization of what is possible with a namedtuple

我尝试使用复杂的数据类型:

>>> data = numpy.empty(shape=tuple(), dtype=[('start date', 'S11'), ('n', int)])

这会创建一个带有一种namedtuple类型的0维值;它几乎可以工作:

>>> data['start date'] = '2011-09-20'
>>> data
array(('2011-09-20', -3241474627884561860), 
      dtype=[('start date', '|S11'), ('n', '<i8')])

但是,元素访问不起作用,因为“数组”是0维的:

>>> data[0] = '2011-09-20'
Traceback (most recent call last):
  File "<ipython-input-19-ed41131430b9>", line 1, in <module>
    data[0] = '2011-09-20'
IndexError: 0-d arrays can't be indexed.

有没有办法通过NumPy对象获得上述所需的行为(通过字符串和索引分配项目)?

4 个答案:

答案 0 :(得分:3)

您可以使用numpy.rec模块执行此类操作。你需要的是这个模块的record类,但我不知道如何直接创建这样一个类的实例。一种直接的方法是首先使用单个条目创建recarray

>>> a = numpy.recarray(1, names=["start date", "n"], formats=["S11", "i4"])[0]
>>> a[0] = "2011-09-20"
>>> a[1] = 42
>>> a
('2011-09-20', 42)
>>> a["start date"]
'2011-09-20'
>>> a.n
42

如果您想知道如何直接创建record的实例,请告知我们。

答案 1 :(得分:3)

Pandas包中的“系列”很好地实现了这一点。

例如来自tutorial

>>> from pandas import *
>>> import numpy as np
>>> s = Series(np.random.randn(5), index=['a', 'b', 'c', 'd', 'e'])
>>> s
a    -0.125628696947
b    0.0942011098937
c    -0.71375003803
d    -0.590085433392
e    0.993157363933
>>> s[1]
0.094201109893723267
>>> s['b']
0.094201109893723267

我刚刚玩了几天,但看起来它有很多可供选择。

答案 2 :(得分:2)

好的,我找到了一个解决方案,但我希望看到一个更优雅的解决方案:

data = numpy.empty(shape=1, dtype=[('start date', 'S11'), ('n', int)])[0]

使用单个元素创建一维数组并获取元素。这使得访问元素可以使用字符串和数字索引:

>>> data['start date'] = '2011-09-20'  # Contains a space: more flexible than a namedtuple!
>>> data[1] = 123
>>> data
('2011-09-20', 123)

如果有一种直接构造data的方法会很好,而不必先用一个元素创建一个数组并提取这个元素。由于

>>> type(data)
<type 'numpy.void'>

我不确定可以调用哪些NumPy构造函数...(numpy.void没有文档字符串。)

答案 3 :(得分:2)

(编辑为EOL建议在回答问题时更具体。)

创建0-dim数组(我也没有找到标量构造函数。)

>>> data0 = np.array(('2011-09-20', 0), dtype=[('start date', 'S11'), ('n', int)])
>>> data0.ndim
0

访问0-dim数组中的元素

>>> type(data0[()])
<class 'numpy.void'>
>>> data0[()][0]
b'2011-09-20'
>>> data0[()]['start date']
b'2011-09-20'

>>> #There is also an item() method, which however returns the element as python type
>>> type(data0.item())
<class 'tuple'>

我认为最简单的方法是将结构化数组(或重新排列)视为元组的列表或数组,索引按名称工作,选择列和选择行的整数。

>>> tupleli = [('2011-09-2%s' % i, i) for i in range(5)]
>>> tupleli
[('2011-09-20', 0), ('2011-09-21', 1), ('2011-09-22', 2), ('2011-09-23', 3), ('2011-09-24', 4)]
>>> dt = dtype=[('start date', '|S11'), ('n', np.int64)]
>>> dt
[('start date', '|S11'), ('n', <class 'numpy.int64'>)]

零维数组,元素是元组,即一条记录,已更改:不是标量元素,请参见结尾

>>> data1 = np.array(tupleli[0], dtype=dt)
>>> data1.shape
()
>>> data1['start date']
array(b'2011-09-20', 
      dtype='|S11')
>>> data1['n']
array(0, dtype=int64)

包含一个元素的数组

>>> data2 = np.array([tupleli[0]], dtype=dt)
>>> data2.shape
(1,)
>>> data2[0]
(b'2011-09-20', 0)

1d数组

>>> data3 = np.array(tupleli, dtype=dt)
>>> data3.shape
(5,)
>>> data3[2]
(b'2011-09-22', 2)
>>> data3['start date']
array([b'2011-09-20', b'2011-09-21', b'2011-09-22', b'2011-09-23',
       b'2011-09-24'], 
      dtype='|S11')
>>> data3['n']
array([0, 1, 2, 3, 4], dtype=int64)

直接索引到单个记录中,与EOL的示例相同,我不知道它是否有效

>>> data3[2][1]
2
>>> data3[2][0]
b'2011-09-22'

>>> data3[2]['n']
2
>>> data3[2]['start date']
b'2011-09-22'

试图理解EOL的例子:标量元素和零维数组是不同的

>>> type(data1)
<class 'numpy.ndarray'>
>>> type(data1[()])   #get element out of 0-dim array
<class 'numpy.void'>

>>> data1[0]
Traceback (most recent call last):
  File "<pyshell#98>", line 1, in <module>
    data1[0]
IndexError: 0-d arrays can't be indexed
>>> data1[()][0]
b'2011-09-20'

>>> data1.ndim
0
>>> data1[()].ndim
0

(注意:我在一个开放的python 3.2解释器中偶然输入了这个例子,所以有一个b'...')