PYTHON/NUMPY:与常见的 numpy 数组相比,处理结构化数组 Python2.7

PYTHON/NUMPY: Handling structured arrays compared to common numpy-arrays Python2.7

我问这个问题的主要原因是因为我不太清楚结构化数组与普通数组相比如何工作,而且我无法在网上找到适合我的案例的示例。此外,我可能首先错误地填充了我的结构化数组。

所以,在这里我想展示 'normal' numpy-array 版本(以及我需要用它做什么)和新的 'structured' 数组版本。我的(最大)数据集包含大约 200e6 objects/rows,最多 40-50 properties/columns。它们都具有相同的数据类型,除了一些特殊的列:'haloid'、'hostid'、'type'。它们是 ID 号或标志,我必须将它们与其余数据一起保存,因为我必须用它们来识别我的对象。

数据集名称:

data_array: ndarray shape: (42648, 10)

数据类型:

dt = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), 
('mstar', '<f8'), ('x_pos', '<f8'), ('y_pos', '<f8'), 
('z_pos', '<f8'), ('x_vel', '<f8'), ('y_vel', '<f8'), ('z_vel', '<f8')]

正在将数据从 .hdf5 文件格式读取到数组

大部分数据存储在 hdf5 文件中(其中 2000 个对应于我必须立即处理的一个快照)应该读入单个数组

import numpy as np
import h5py as hdf5

mydict={'name0': 'haloid', 'name1': 'hostid', ...} #dictionary of column names
nr_rows     = 200000                               # approximated
nr_files    = 100                                  # up to 2200
nr_entries  = 10                                   # up to 50   
size        = 0
size_before = 0
new_size    = 0

# normal array:
data_array=np.zeros((nr_rows, nr_entries), dtype=np.float64)
# structured array:
data_array=np.zeros((nr_rows,), dtype=dt)

i=0
while i<nr_files:
    size_before=new_size

    f = hdf5.File(path, "r")
    size=f[mydict['name0']].size

    new_size+=size                

    a=0
    while a<nr_entries:
        name=mydict['name'+str(a)]
        # normal array: 
        data_array[size_before:new_size, a] = f[name] 
        # structured array:
        data_array[name][size_before:new_size] = f[name]                 
        a+=1                
    i+=1

EDIT:我编辑了上面的代码,因为 hpaulj 幸运地评论了以下内容:

First point of confusion. You show a dt definition with names like dt = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'),.... But the h5 load is data_array['name'+str(a)][size_before:new_size] = f['name'+str(a)] In other words, the file has datasets with names like name0, name1, and you are downloading those to an array with fields with the same names.

这是一个 'I-simplify-code' copy/paste 错误,我更正了它

问题 1:这是填充结构化数组的正确方法吗?

data_array[name][size_before:new_size] = f[name]

问题 2:如何对结构化数组中的列进行寻址?

data_array[name] #--> column with a certain name

问题 3:如何寻址结构化数组中的整行?

data_array[0] #--> first row

问题4:如何寻址3行全列?

# normal array:
print data_array[0:3,:]
[[  1.21080866e+10   1.21080866e+10   0.00000000e+00   5.69363234e+08
    1.28992369e+03   1.28894614e+03   1.32171442e+03  -1.08210000e+02
    4.92900000e+02   6.50400000e+01]
 [  1.21080711e+10   1.21080711e+10   0.00000000e+00   4.76329837e+06
    1.29058079e+03   1.28741361e+03   1.32358059e+03  -4.23130000e+02
    5.08720000e+02  -6.74800000e+01]
 [  1.21080700e+10   1.21080700e+10   0.00000000e+00   2.22978043e+10
    1.28750287e+03   1.28864306e+03   1.32270418e+03  -6.13760000e+02
    2.19530000e+02  -2.28980000e+02]]

# structured array:    
print data_array[0:3]
#it returns a lot of data ...
[[ (12108086595L, 12108086595L, 0, 105676938.02998888, 463686295.4907876,.7144191943337, -108.21, 492.9, 65.04)
  (12108071103L, 12108071103L, 0, 0.0, ... more data ...
  ... 228.02) ... more data ...
  (8394715323L, 8394715323L, 2, 0.0, 823505.2374262045, 0798, 812.0612163877823, -541.61, 544.44, 421.08)]]

问题5:为什么data_array[0:3]不仅return前3行还有10列?

问题6:第一列的前两个元素如何寻址?

# normal array:
print data_array[0:1,0]
[  1.21080866e+10   1.21080711e+10]
# structured array:  
print data_array['haloid']][0][0:1]  
[12108086595 12108071103]

好的!我明白了!

问题 7:如何按名称寻址三个特定的列,以及它们在该列中的前 3 行?

# normal array: 
print data_array[0:3, [0,2,1]]
[[  1.21080866e+10   0.00000000e+00   1.21080866e+10]
 [  1.21080711e+10   0.00000000e+00   1.21080711e+10]
 [  1.21080700e+10   0.00000000e+00   1.21080700e+10]]

# structured array:  
print data_array[['haloid','type','hostid']][0][0:3]  
[(12108086595L, 0, 12108086595L) (12108071103L, 0, 12108071103L)
 (12108069992L, 0, 12108069992L)]

好的,最后一个例子似乎可行!!!

问题8:有什么区别:

(a) data_array['haloid'][0][0:3] 和 (b) data_array['haloid'][0:3]

其中 (a) return 确实是前三个光环和 (b) return 很多光环 (10x3)。

[[12108086595 12108071103 12108069992 12108076356 12108075899 12108066340
   9248632230 12108066342 10878169355 10077026070]
 [ 6093565531 10077025463  8046772253  7871669276  5558161476  5558161473
  12108068704 12108068708 12108077435 12108066338]
 [ 8739142199 12108069995 12108069994 12108076355 12108092590 12108066312
  12108075900  9248643751  6630111058 12108074389]]

问题 9: data_array['haloid'][0:3] 实际上 return 是什么?

问题 10: 如何使用 np.where()

屏蔽结构化数组
# NOTE: col0,1,2 are some integer values of the column I want to address 
# col_name0,1,2 are corresponding names e.g. mstar, type, haloid

# normal array
mask = np.where(data[:,col2] > data[:,col1])
data[mask[:][0]]

mask = np.where(data[:,col2]==2)
data[:,col0][[mask[:][0]]]=data[:,col2][[mask[:][0]]]

#structured array
mask = np.where(data['x_pos'][0] > data['y_pos'][0]])
data[mask[:][0]]

mask = np.where(data[:,col2]==2)
data['haloid'][:,col0][[mask[:][0]]]=data['hostid'][:,col1][[mask[:][0]]]

这似乎可行,但我不确定!

问题 11: 我还能使用 np.resize() 吗:data_array = np.resize(data_array,(new_size, nr_entries))resize/reshape我的数组?

问题 12:如何排序一个结构化数组?

# normal array: 
data_sorted = data[np.argsort(data[:,col2])]
# structured array: 
data_sorted = data[np.argsort(data['mstar'][:,col3])]

谢谢,感谢任何帮助或建议!

根据你的描述,我认为天真的方法是只将有用的数据读入具有不同名称的数组(可能每个类型一种?) 如果你想将所有数据读入一个数组,也许 Pandas 是你的选择: http://pandas.pydata.org http://pandas.pydata.org/pandas-docs/stable/ 但我还没有尝试过。玩得开心试试。

第一点混乱。您显示一个 dt 定义,其名称如 dt = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'),...。但是 h5 负载 是

data_array['name'+str(a)][size_before:new_size] = f['name'+str(a)] 

换句话说,该文件包含名称为 name0name1 的数据集,您正在将这些数据集下载到具有相同名称字段的数组中。

您可以使用

迭代dt定义的数组的字段
for name in dt.names:
    data[name] = ...

例如

In [20]: dt = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), 
    ...: ('mstar', '<f8'), ('x_pos', '<f8'), ('y_pos', '<f8'), 
    ...: ('z_pos', '<f8'), ('x_vel', '<f8'), ('y_vel', '<f8'), ('z_vel', '<f8')]
In [21]: arr = np.zeros((3,), dtype=dt)
In [22]: arr
Out[22]: 
array([(0, 0, 0,  0.,  0.,  0.,  0.,  0.,  0.,  0.),
       (0, 0, 0,  0.,  0.,  0.,  0.,  0.,  0.,  0.),
       (0, 0, 0,  0.,  0.,  0.,  0.,  0.,  0.,  0.)], 
      dtype=[('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), ('mstar', '<f8'), ('x_pos', '<f8'), ('y_pos', '<f8'), ('z_pos', '<f8'), ('x_vel', '<f8'), ('y_vel', '<f8'), ('z_vel', '<f8')])
In [23]: for name in arr.dtype.names:
    ...:     print(name)
    ...:     arr[name] = 1
    ...:     
haloid
hostid
 ....
In [24]: arr
Out[24]: 
array([(1, 1, 1,  1.,  1.,  1.,  1.,  1.,  1.,  1.),
       (1, 1, 1,  1.,  1.,  1.,  1.,  1.,  1.,  1.),
       (1, 1, 1,  1.,  1.,  1.,  1.,  1.,  1.,  1.)], 
      dtype=[('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), ('mstar', '<f8'), ('x_pos', '<f8'), ('y_pos', '<f8'), ('z_pos', '<f8'), ('x_vel', '<f8'), ('y_vel', '<f8'), ('z_vel', '<f8')])
In [25]: arr[0]     # get one record
Out[25]: (1, 1, 1,  1.,  1.,  1.,  1.,  1.,  1.,  1.)
In [26]: arr[0]['hostid']     # get one field, one record
In [27]: arr['hostid']       # get all values of a field
Out[27]: array([1, 1, 1], dtype=uint64)
In [28]: arr['hostid'][:2]    # subset of records
Out[28]: array([1, 1], dtype=uint64)

因此按字段名填充结构化数组应该可以正常工作:

arr[name][n1:n2] = file[dataset_name]

像这样打印:

structured array:
print data_array[['haloid','type','hostid']][0][0:3]
[(12108086595L, 0, 12108086595L) (12108071103L, 0, 12108071103L) (12108069992L, 0, 12108069992L)]

[[ (12108086595L, 12108086595L, 0,

在我看来,结构化的 data_array 实际上是二维的,是用类似的东西创建的(参见问题 8)

data_array = np.zeros((10, nr_rows), dtype=dt)

这是 [0][0:3] 索引工作的唯一方法,

对于二维数组:

mask = np.where(data[:,col2] > data[:,col1])

比较 2 列。如有疑问,请首先查看布尔值 data[:,col2] > data[:,col1]where 只是 return 布尔数组为 True 的索引。

屏蔽索引的简单示例:

In [29]: x = np.array((np.arange(6), np.arange(6)[::-1])).T
In [33]: mask = x[:,0]>x[:,1]
In [34]: mask
Out[34]: array([False, False, False,  True,  True,  True], dtype=bool)
In [35]: idx = np.where(mask)
In [36]: idx
Out[36]: (array([3, 4, 5], dtype=int32),)
In [37]: x[mask,:]
Out[37]: 
array([[3, 2],
       [4, 1],
       [5, 0]])
In [38]: x[idx,:]
Out[38]: 
array([[[3, 2],
        [4, 1],
        [5, 0]]])

在此结构化示例中,data['x_pos'] select 是字段。 [0] 需要 select 该二维数组的第一行(大小为 10 维)。其余的比较和位置应该与二维数组一样工作。

mask = np.where(data['x_pos'][0] > data['y_pos'][0]])
可能不需要 where 元组上的

mask[:][0]mask 是一个元组,[:] 进行复制,[0] select 是第一个元素,它是一个数组。有时可能需要 arr[idx[0],:] 而不是 arr[idx,:],但不要经常这样做。

我的第一条评论建议使用单独的数组

 dt1 = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1')]
 data_id = np.zeros((n,), dtype=dt1)

 data = np.zeros((n,m), dtype=float)    # m float columns

甚至

 haloid = np.zeros((n,), '<u8')
 hostid = np.zeros((n,), '<u8')
 type = np.zeros((n,), 'i1')

对于这些数组,data_array['hostid'][0]data_id['hostid']hostid 都应该 return 相同的一维数组,并且在 mask 表达式中同样可用。

有时将 id 和数据保存在一个结构中会很方便。如果 writing/reading 到 csv 格式文件尤其如此。但是对于掩码 selection 来说,它并没有多大帮助。对于跨数据字段的数据计算,这可能会很痛苦。

我还可以建议一个复合数据类型,一个

dt2 = [('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), ('data', 'f8', (m,))]

In [41]: np.zeros((4,), dtype=dt2)
Out[41]: 
array([(0, 0, 0, [ 0.,  0.,  0.]), (0, 0, 0, [ 0.,  0.,  0.]),
       (0, 0, 0, [ 0.,  0.,  0.]), (0, 0, 0, [ 0.,  0.,  0.])], 
      dtype=[('haloid', '<u8'), ('hostid', '<u8'), ('type', 'i1'), ('data', '<f8', (3,))])
In [42]: _['data']
Out[42]: 
array([[ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.],
       [ 0.,  0.,  0.]])

按列号或 'x_coor' 之类的名称访问浮点数据更好吗?您需要同时对多个浮点列进行计算,还是总是单独访问它们?

问题 11 的答案:

Question 11: Can I still use np.resize() like: data_array = np.resize(data_array,(new_size, nr_entries)) to resize/reshape my array?

如果我像这样调整我的数组大小,我将为 dt 中的每个字段再创建 10 列。所以我得到了 问题 8b 的 'weird' 结果:一个结构 (10x3) 卤素

trim 我的数组的正确方法,因为我只想保留 if 的填充部分(我将数组设计得足够大以包含我随后读取的各种数据块。 ..) 是:

data_array = data_array[:newsize]

print np.info(data_array)

class:  ndarray
shape:  (42648,)
strides:  (73,)
type: [('haloid', '<u8'), ('hostid', '<u8'), ('orphan', 'i1'), 
('mstar', '<f8'), ('x_pos', '<f8'), ('y_pos', '<f8'), 
('z_pos', '<f8'), ('x_vel', '<f8'), ('y_vel', '<f8'), ('z_vel', '<f8')]