如何在不改变其维度的情况下为numpy数组添加名称?

时间:2014-06-11 17:03:10

标签: python arrays numpy

我有一个现有的两列numpy数组,我需要添加列名。通过via dtype传递这些内容适用于下面 Block 1 中显示的玩具示例。但是,使用我的实际数组,如 Block 2 所示,同样的方法是出现意外(对我而言)更改数组维度的副作用。

如何将我的实际数组(下面第二个块中名为Y的数组)转换为具有命名列的数组,就像我在第一个块中为数组A所做的那样?

第1区:A列未命名重塑维度)

import numpy as np
A = np.array(((1,2),(3,4),(50,100)))
A
# array([[  1,   2],
#        [  3,   4],
#        [ 50, 100]])
dt = {'names':['ID', 'Ring'], 'formats':[np.int32, np.int32]}
A.dtype=dt
A
# array([[(1, 2)],
#        [(3, 4)],
#        [(50, 100)]], 
#       dtype=[('ID', '<i4'), ('Ring', '<i4')])

第2块:(命名我实际数组的列Y,重塑其维度)

import numpy as np
## Code to reproduce Y, the array I'm actually dealing with
nRings = 3
nn = [[nRings+1-n] * n for n in range(nRings+1)]
RING = reduce(lambda x, y: x+y, nn)
ID = range(1,len(RING)+1)
X = numpy.array([ID, RING])
Y = X.T
Y
# array([[1, 3],
#        [2, 2],
#        [3, 2],
#        [4, 1],
#        [5, 1],
#        [6, 1]])

## My unsuccessful attempt to add names to the array's columns    
dt = {'names':['ID', 'Ring'], 'formats':[np.int32, np.int32]}
Y.dtype=dt
Y
# array([[(1, 2), (3, 2)],
#        [(3, 4), (2, 1)],
#        [(5, 6), (1, 1)]], 
#       dtype=[('ID', '<i4'), ('Ring', '<i4')])

## What I'd like instead of the results shown just above
# array([[(1, 3)],
#        [(2, 2)],
#        [(3, 2)],
#        [(4, 1)],
#        [(5, 1)],
#        [(6, 1)]],
#       dtype=[('ID', '<i4'), ('Ring', '<i4')])

5 个答案:

答案 0 :(得分:2)

首先因为你的问题要求给数组命名,我觉得有必要指出使用&#34;结构化数组&#34;为了给出名字可能不是最好的方法。当我们使用表格时,我们经常喜欢为行/列命名,如果是这种情况,我建议您尝试类似pandas的内容,这很棒。如果您只想在代码中组织一些数据,那么数组字典通常比结构化数组好得多,例如,您可以这样做:

Y = {'ID':X[0], 'Ring':X[1]}

如果你想使用结构化数组,那么在我看来这是最明智的方法:

import numpy as np

nRings = 3
nn = [[nRings+1-n] * n for n in range(nRings+1)]
RING = reduce(lambda x, y: x+y, nn)
ID = range(1,len(RING)+1)
X = np.array([ID, RING])

dt = {'names':['ID', 'Ring'], 'formats':[np.int, np.int]}
Y = np.zeros(len(RING), dtype=dt)
Y['ID'] = X[0]
Y['Ring'] = X[1]

答案 1 :(得分:1)

尝试重写X的定义:

X = np.array(zip(ID, RING))

然后你不需要定义Y = X.T

答案 2 :(得分:1)

您是否完全确定AY的输出?我使用Python 2.7.6和numpy 1.8.1获得了不同的东西。

A的初始输出与您的初始输出相同。为第一个示例运行以下代码后

dt = {'names':['ID', 'Ring'], 'formats':[np.int32, np.int32]}
A.dtype=dt

数组A的内容实际上是

array([[(1, 0), (3, 0)],
   [(2, 0), (2, 0)],
   [(3, 0), (2, 0)],
   [(4, 0), (1, 0)],
   [(5, 0), (1, 0)],
   [(6, 0), (1, 0)]], 
  dtype=[('ID', '<i4'), ('Ring', '<i4')])

这对我来说比你添加的输出更有意义,因为dtype确定数组中每个元素的数据类型,而新定义声明每个元素应该包含两个字段,所以它确实如此,但是第二个字段的值设置为0,因为第二个字段没有预先存在的值。

但是,如果您想为现有数组创建numpy group列,以便每行只包含一个元素,但每个元素包含两个字段,则可以引入一个小代码更改。

由于需要使用元组将numpy组元素转换为更复杂的数据类型,因此可以通过创建新数组并将现有数组的每一行转换为元组来实现。这是一个简单的工作示例

import numpy as np
A = np.array(((1,2),(3,4),(50,100)))
dt = np.dtype([('ID', np.int32), ('Ring', np.int32)])
B = np.array(list(map(tuple, A)), dtype=dt)

使用这段短代码,数组B变为

array([(1, 2), (3, 4), (50, 100)], 
  dtype=[('ID', '<i4'), ('Ring', '<i4')])

要使B成为2D数组,只需编写

即可
B.reshape(len(B), 1) # in this case, even B.size would work instead of len(B)

对于第二个例子,需要做类似的事情才能使Y成为结构化数组:

Y = np.array(list(map(tuple, X.T)), dtype=dt)

在为第二个例子执行此操作后,数组Y看起来像这样

array([(1, 3), (2, 2), (3, 2), (4, 1), (5, 1), (6, 1)], 
  dtype=[('ID', '<i4'), ('Ring', '<i4')])

您可以注意到输出与您期望的输出不同,但是这个输出更简单,因为您可以只编写{{1}而不是编写Y[0,0]来获取第一个元素。 }。要同时制作此数组2D,您也可以使用Y[0],就像使用reshape一样。

答案 3 :(得分:1)

这是因为Y不是C_CONTIGUOUS,你可以Y.flags检查:

  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : False
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

您可以先致电Y.copy()Y.ravel()

dt = {'names':['ID', 'Ring'], 'formats':[np.int32, np.int32]}
print Y.ravel().view(dt) # the result shape is (6, )
print Y.copy().view(dt)  # the result shape is (6, 1)

答案 4 :(得分:1)

store-different-datatypes-in-one-numpy-array 另一个页面包括一个很好的解决方案,可以将名称添加到一个可以用作列的数组 例如:

r = np.core.records.fromarrays([x1,x2,x3],names='a,b,c')
# x1, x2, x3 are flatten array
# a,b,c are field name