将1D数组堆叠成结构化数组的numpy方法

9

我正在使用Python 2.7中的Numpy 1.6,并从另一个模块获取一些1D数组。我希望将这些数组打包成结构化数组,以便可以通过名称索引原始1D数组。我无法弄清楚如何将1D数组转换为2D数组并使dtype访问正确的数据。我的最小工作示例如下:

>>> import numpy as np
>>> 
>>> x = np.random.randint(10,size=3)
>>> y = np.random.randint(10,size=3)
>>> z = np.random.randint(10,size=3)
>>> x
array([9, 4, 7])
>>> y
array([5, 8, 0])
>>> z
array([2, 3, 6])
>>> 
>>> w = np.array([x,y,z])
>>> w.dtype=[('x','i4'),('y','i4'),('z','i4')]
>>> w
array([[(9, 4, 7)],
       [(5, 8, 0)],
       [(2, 3, 6)]], 
      dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')])
>>> w['x']
array([[9],
       [5],
       [2]])
>>> 
>>> u = np.vstack((x,y,z))
>>> u.dtype=[('x','i4'),('y','i4'),('z','i4')]
>>> u
array([[(9, 4, 7)],
       [(5, 8, 0)],
       [(2, 3, 6)]],    
      dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')]) 

>>> u['x']
array([[9],
       [5],
       [2]])

>>> v = np.column_stack((x,y,z))
>>> v
array([[(9, 4, 7), (5, 8, 0), (2, 3, 6)]], 
      dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')])

>>> v.dtype=[('x','i4'),('y','i4'),('z','i4')]
>>> v['x']
array([[9, 5, 2]])

正如您所看到的,尽管我的原始 x 数组包含 [9,4,7],但我尝试堆叠数组并按 'x' 索引返回的结果都与原始的 x 数组不同。有没有办法实现这一点,或者我的方法存在问题?


你需要对二维数组进行操作吗?为什么不使用字典呢? - OregonTrail
我想我只是假设不混合数据类型并使用ndarray会更好,因为它支持类似字典的索引,但实际上没有真正的合理理由。 - Thav
回答第一个问题,不,在这种情况下我不需要对二维数组进行操作。 - Thav
5个回答

17

有一种方式是

wtype=np.dtype([('x',x.dtype),('y',y.dtype),('z',z.dtype)])
w=np.empty(len(x),dtype=wtype)
w['x']=x
w['y']=y
w['z']=z

请注意,randint返回的每个数字的大小取决于您的平台,因此在我的机器上,它不是一个int32(即“i4”),而是一个int64(即“i8”)。 另一种方法更加可移植。


3
这实际上是将具有不同数据类型的数组合并成单个结构化数组的唯一方法。 - Jaime
当 x、y、z 具有不同数量的元素时,是否有一种方法可以实现它? - Stefano

3
您想使用 np.column_stack
import numpy as np

x = np.random.randint(10,size=3)
y = np.random.randint(10,size=3)
z = np.random.randint(10,size=3)

w = np.column_stack((x, y, z))
w = w.ravel().view([('x', x.dtype), ('y', y.dtype), ('z', z.dtype)])

>>> w
array([(5, 1, 8), (8, 4, 9), (4, 2, 6)], 
      dtype=[('x', '<i4'), ('y', '<i4'), ('z', '<i4')])
>>> x
array([5, 8, 4])
>>> y
array([1, 4, 2])
>>> z
array([8, 9, 6])
>>> w['x']
array([5, 8, 4])
>>> w['y']
array([1, 4, 2])
>>> w['z']
array([8, 9, 6])

我在我的示例中使用了 column_stack,但是没有得到与您相同的结果。我猜想差异在于 w.rave1()... 行,但我不太理解那里发生了什么。 - Thav
2
如果1D数组的数据类型占用不同数量的字节,则此操作将失败。 - Brecht Machiels

1
为了在所选答案的基础上进行改进,您可以使这个过程变得动态:
  • 首先循环遍历您的数组(可以是单列)
  • 然后循环遍历您的列以获取数据类型
  • 使用这些数据类型创建空数组
  • 然后我们重复这些循环来填充数组

设置

# First, let's build a structured array
rows = [
    ("A", 1),
    ("B", 2),
    ("C", 3),
]
dtype = [
    ("letter", str, 1),
    ("number", int, 1),
]
arr = np.array(rows, dtype=dtype)

# Then, let's create a standalone column, of the same length:
rows = [
    1.0,
    2.0,
    3.0,
]
dtype = [
    ("float", float, 1)
]
new_col = np.array(rows, dtype=dtype)

解决问题。
# Now, we dynamically create an empty array with the dtypes from our structured array and our new column:
dtypes = []
for array in [arr, new_col]:
    for name in array.dtype.names:
        dtype = (name, array[name].dtype)
        dtypes.append(dtype)
new_arr = np.empty(len(new_col), dtype=dtypes)

# Finally, put your data in the empty array:
for array in [arr, new_col]:
    for name in array.dtype.names:
        new_arr[name] = array[name]

希望它有所帮助。

0
你可能想要研究一下numpy的记录数组来实现这个用途:
"Numpy提供了强大的功能来创建结构体或记录的数组。这些数组允许通过结构体或结构体字段来操作数据。"
这里是关于记录数组的文档: http://docs.scipy.org/doc/numpy/user/basics.rec.html 你可以使用你的变量名作为字段名。

-2

使用字典

#!/usr/bin/env python

import numpy

w = {}
for key in ('x', 'y', 'z'):
    w[key] = np.random.randint(10, size=3)

print w

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