Numpy,如何将列名称添加到Numpy数组

时间:2019-04-08 15:50:47

标签: python arrays numpy

这可能有一些重复的线程,但老实说我找不到合适的解决方案。熊猫将是一个简单的解决方案,但是在我正在从事的项目中,熊猫不会作为依赖项。

我试图将列名称添加到Numpy数组中,即使数据类型相同,也基本上将其转换为结构化数组。

我尝试过:

signal = np.array([[1,2,3],[1,2,3],[1,2,3]])
col_names = ('left','right','center')
signal = np.array(signal, dtype = [(n, 'int16') for n in col_names])

但这返回:

array([[(1, 1, 1), (2, 2, 2), (3, 3, 3)],
       [(1, 1, 1), (2, 2, 2), (3, 3, 3)],
       [(1, 1, 1), (2, 2, 2), (3, 3, 3)]],
      dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])

基本上,我有一个代表多通道信号的Numpy数组。我希望能够使用列名对通道进行子集化:

signal['left'] == signal[:,0] # True
signal[['left','center']] == signal[:,[0,2]] # True

我还看到有人建议不要使用结构化数组。有潜在的负面影响吗?是说这会使数组访问速度变慢?

2 个答案:

答案 0 :(得分:1)

结构化数组的正确数据输入形式是元组列表:

In [71]: signal = [(1,2,3),(2,3,1),(3,2,1)] 
    ...: col_names = ('left','right','center') 
    ...: signal = np.array(signal, dtype = [(n, 'int16') for n in col_names])   
In [72]:                                                                        
In [72]: signal                                                                 
Out[72]: 
array([(1, 2, 3), (2, 3, 1), (3, 2, 1)],
      dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])

1.16添加了两个函数,这些函数使在结构化数组之间来回转换变得更加容易:

In [73]: import numpy.lib.recfunctions as rfn                                   
In [74]: signal = np.array([[1,2,3],[1,2,3],[1,2,3]])                           
In [75]: dt = np.dtype([(n, 'int16') for n in col_names])                       
In [76]: dt                                                                     
Out[76]: dtype([('left', '<i2'), ('right', '<i2'), ('center', '<i2')])
In [77]: rfn.unstructured_to_structured(signal, dt)                             
Out[77]: 
array([(1, 2, 3), (1, 2, 3), (1, 2, 3)],
      dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])

将此dt应用于signal有一个问题:

In [82]: signal.view(dt)                                                        
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-82-f0fa01ce8128> in <module>
----> 1 signal.view(dt)

ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype

我们可以通过首先将signal转换为兼容的dtype来解决此问题:

In [83]: signal.astype('i2').view(dt)                                           
Out[83]: 
array([[(1, 2, 3)],
       [(1, 2, 3)],
       [(1, 2, 3)]],
      dtype=[('left', '<i2'), ('right', '<i2'), ('center', '<i2')])

但是请注意,Out[83]的形状为(3,1)。其他阵列为形状(3,)。 view在与结构化数组之间进行转换时始终会遇到此形状问题。这就是为什么较新功能更易于使用的部分原因。

答案 1 :(得分:0)

通过查看即可获得正确的结果

>>> signal.view(dtype=[(n, signal.dtype) for n in col_names])

array([[(1, 2, 3)],
   [(1, 2, 3)],
   [(1, 2, 3)]],
  dtype=[('left', '<i8'), ('right', '<i8'), ('center', '<i8')])

就性能而言,不必担心。结构化数组是ndarrays,您将获得具有更复杂的数据类型的额外好处。另一方面,记录数组是结构化的数组,允许将字段名称作为对象属性进行查找-这给属性查找带来了一些开销,但与对数据进行计算相比,开销通常仍然很小。