在Python 2.7.3中为numpy数组分配字段名

5

我对这个问题感到非常困扰,显然我错过了关键点,解决方案太简单了,我没能看到 :(

我有一个包含x列的np.array,我想给它分配一个字段名。这是我的代码:

data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
a = np.array(data, dtype= {'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})
print a['1st']

为什么会出现这个结果?
[[  1.    2.    3. ]
 [  4.    5.    6. ]
 [ 11.   12.   12.3]]
< p > 与其使用[1, 2, 3],不如……?


我不能告诉你为什么这不起作用,但一个解决方案是改为使用np.rec.fromarraysa = np.rec.fromarray(data, dtype= {'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})。这使得这个问题本质上成为了 http://stackoverflow.com/questions/8220689/how-to-make-a-structured-array-from-multiple-simple-array 的重复。 - user707650
没错,那很完美!我还在想为什么我的例子不起作用。请在你的例子中将 fromarray 改为 fromarrays。非常感谢! - xtlc
这个答案可能会有所帮助,https://dev59.com/9XXYa4cB1Zd3GeqP9bn-,基本上看起来你不能在numpy中为行命名,但是你可以设置具有列名称的结构化数组... - Ed Smith
1
"data" 需要是一个元组列表。 - hpaulj
1
http://docs.scipy.org/doc/numpy/user/basics.rec.html#filling-structured-arrays - hpaulj
1个回答

3
In [1]: data = np.array([[1,2,3], [4.0,5.0,6.0], [11,12,12.3]])
In [2]: dt = np.dtype({'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})

Your attempt:

In [3]: np.array(data,dt)
Out[3]: 
array([[(1.0, 1.0, 1.0), (2.0, 2.0, 2.0), (3.0, 3.0, 3.0)],
       [(4.0, 4.0, 4.0), (5.0, 5.0, 5.0), (6.0, 6.0, 6.0)],
       [(11.0, 11.0, 11.0), (12.0, 12.0, 12.0), (12.3, 12.3, 12.3)]], 
      dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])

这段代码生成一个(3,3)的数组,每个元素都具有相同的值。在此情况下,data.astype(dt)扮演着同样的角色。

但是,view 生成包含每个列数据的(3,1)数组。

In [4]: data.view(dt)
Out[4]: 
array([[(1.0, 2.0, 3.0)],
       [(4.0, 5.0, 6.0)],
       [(11.0, 12.0, 12.3)]], 
      dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])

我需要提醒的是,view 只在所有字段与原始字段具有相同数据类型时才有效。它使用相同的数据缓冲区,仅以不同的方式解释值。

您可以将结果从 (3,1) 重塑为 (3,)。

但是,由于您想要 A['1st'] 成为 [1,2,3] - 一个 data 的行 - 我们必须进行其他操作。

In [16]: data.T.copy().view(dt)
Out[16]: 
array([[(1.0, 4.0, 11.0)],
       [(2.0, 5.0, 12.0)],
       [(3.0, 6.0, 12.3)]], 
      dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [17]: _['1st']
Out[17]: 
array([[ 1.],
       [ 2.],
       [ 3.]])

我进行转置,然后复制(重新排列底层数据缓冲区)。现在一个视图将[1,2,3]放在一个字段中。

请注意,结构化数组的显示使用()而不是[]表示“行”。这是提示它如何接受输入的线索。

我可以通过以下方式将您的data转换为元组列表:

In [19]: [tuple(i) for i in data.T]
Out[19]: [(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.300000000000001)]

In [20]: np.array([tuple(i) for i in data.T],dt)
Out[20]: 
array([(1.0, 4.0, 11.0), (2.0, 5.0, 12.0), (3.0, 6.0, 12.3)], 
      dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])
In [21]: _['1st']
Out[21]: array([ 1.,  2.,  3.])

这是一个包含3个字段的(3,)数组。

使用元组列表是向np.array(...,dt)提供数据的常规方法。请参见我的评论中的文档链接。

您还可以创建一个空数组,逐行或逐个字段填充它。

In [26]: A=np.zeros((3,),dt)
In [27]: for i in range(3):
   ....:     A[i]=data[:,i].copy()

没有使用 copy 我会收到一个错误提示 ValueError: ndarray is not C-contiguous

逐个填充字段:

In [29]: for i in range(3):
   ....:     A[dt.names[i]]=data[i,:]

通常,结构化数组有许多行和少量字段。因此,按字段填充相对较快。这就是recarray函数处理大多数复制任务的方式。


fromiter也可以使用:

In [31]: np.fromiter(data, dtype=dt)
Out[31]: 
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0), (11.0, 12.0, 12.3)], 
     dtype=[('1st', '<f8'), ('2nd', '<f8'), ('3rd', '<f8')])

在不使用复制的情况下使用data.T时出现的错误强烈表明正在进行逐行迭代(我的In[27])。

In [32]: np.fromiter(data.T, dtype=dt)
  ValueError: ndarray is not C-contiguous

zip(*data) 是重新排列输入数组的另一种方式(请参见评论链接中 @unutbu 的答案)。

np.fromiter(zip(*data),dtype=dt)

正如评论中指出的那样,fromarrays可以起作用:

np.rec.fromarrays(data,dt)

这是一个使用by field复制方法的rec函数示例:

arrayList = [sb.asarray(x) for x in arrayList]
....
_array = recarray(shape, descr)
# populate the record array (makes a copy)
for i in range(len(arrayList)):
    _array[_names[i]] = arrayList[i]

在我们的情况下,这是指:
In [8]: data1 = [np.asarray(i) for i in data]
In [9]: data1
Out[9]: [array([ 1.,  2.,  3.]), array([ 4.,  5.,  6.]), array([ 11. ,  12. ,  12.3])]
In [10]: for i in range(3):
    A[dt.names[i]] = data1[i]

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