【问题标题】:Assigning field names to numpy array in Python 2.7.3在 Python 2.7.3 中将字段名称分配给 numpy 数组
【发布时间】:2015-12-05 02:26:34
【问题描述】:

我要疯了,因为我显然没有抓住重点,而且解决方案太简单了:(

我有一个带有 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]]

而不是[1, 2, 3]

【问题讨论】:

  • 我无法告诉您为什么这不起作用,但一种解决方案是改用 np.rec.fromarraysa = np.rec.fromarray(data, dtype= {'names': ['1st', '2nd', '3rd'], 'formats':['f8','f8', 'f8']})。这使得这个问题本质上与stackoverflow.com/questions/8220689/… 重复。
  • 是的。那是完美的!仍然想知道为什么我的示例不起作用。请在您的示例中正确fromarray -> fromarrays。非常感谢!
  • 这个答案可能会有所帮助,stackoverflow.com/questions/18256220/…,基本上你似乎无法在 numpy 中命名行,但你可以使用列名设置结构化数组...
  • data 需要是tuples 的列表。

标签: python arrays python-2.7 numpy user-defined-types


【解决方案1】:
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']})

你的尝试:

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's 答案)。

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]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-09-21
    • 2019-10-11
    • 2020-11-01
    • 2013-08-28
    • 2019-10-24
    • 2020-09-01
    • 1970-01-01
    • 2017-07-06
    相关资源
    最近更新 更多