如何使用numpy对复杂的结构化数据进行排序?

时间:2018-07-16 23:41:06

标签: python numpy

我有一个文件,其行由2个整数和一个浮点数组成。 我用numpy读取文件:

dt = np.dtype([('pre', np.dtype('i4'), 2),('data', np.float64, 1)])
a = np.fromfile("myfile", dtype=dt)

array([([65536, 65536], 0.2       ), ([65536,     1], 1.33566434),
       ([65536,     2], 2.06068931), ..., ([65535,   479], 0.33333333),
       ([65535,  2295], 0.09090909), ([65535,   249], 0.07692308)],
      dtype=[('pre', '<i4', (2,)), ('data', '<f8')])

我实际上有两个问题: 例如,当我用np.nditer迭代a时,我无法访问a [0] [0] [0] 为什么会这样以及如何使用np.nditer? 第二个问题:如何在['pre']列表中的第一个条目之后然后在['pre']中的第二个条目之后对元素进行排序 所需的输出如下所示:

array([([1, 1], 0.2       ), ([1,     2], 1.33566434),
       ([1,     3], 2.06068931), ..., ([2,   1], 0.33333333),
       ([2,  2], 0.09090909), ([2,   3], 0.07692308)],
      dtype=[('pre', '<i4', (2,)), ('data', '<f8')])

欢迎提出任何建议,即使更改读取文件的数据类型会有所帮助。还需要性能,因为我的文件很大。 谢谢

1 个答案:

答案 0 :(得分:1)

您有一个一维结构化数组:

In [56]: arr = np.array([([65536, 65536], 0.2       ), ([65536,     1], 1.3356
    ...: 6434),
    ...:        ([65536,     2], 2.06068931), ([65535,   479], 0.33333333),
    ...:        ([65535,  2295], 0.09090909), ([65535,   249], 0.07692308)],
    ...:       dtype=[('pre', '<i4', (2,)), ('data', '<f8')])
    ...:       
In [57]: arr
Out[57]: 
array([([65536, 65536], 0.2       ), ([65536,     1], 1.33566434),
       ([65536,     2], 2.06068931), ([65535,   479], 0.33333333),
       ([65535,  2295], 0.09090909), ([65535,   249], 0.07692308)],
      dtype=[('pre', '<i4', (2,)), ('data', '<f8')])
In [58]: arr.shape
Out[58]: (6,)
In [59]: arr.dtype
Out[59]: dtype([('pre', '<i4', (2,)), ('data', '<f8')])
In [60]: arr['pre']
Out[60]: 
array([[65536, 65536],
       [65536,     1],
       [65536,     2],
       [65535,   479],
       [65535,  2295],
       [65535,   249]], dtype=int32)
In [61]: arr['data']
Out[61]: 
array([0.2       , 1.33566434, 2.06068931, 0.33333333, 0.09090909,
       0.07692308])

它有2个字段。 pre字段包含2个元素,因此arr['pre']是2d数值数组。

一般而言,您不需要使用nditer来遍历数组。在开发cython代码时很有用,但在Python代码中不需要。

如果使用nditer,则将获得具有原始dtype的()形状数组:

In [70]: for x in np.nditer(arr):
    ...:     print(x)

([65536, 65536], 0.2)
([65536,     1], 1.33566434)
([65536,     2], 2.06068931)
([65535,   479], 0.33333333)
([65535,  2295], 0.09090909)
([65535,   249], 0.07692308)

直接迭代之间的区别很细微。 type情况下的nditer<class 'numpy.ndarray'>。在直接迭代的情况下,<class 'numpy.void'>

对于排序,听起来好像您想使用'pre'字段的两列来np.lexsort

In [76]: np.lexsort((arr['pre'][:,1], arr['pre'][:,0]))
Out[76]: array([5, 3, 4, 1, 2, 0])
In [77]: arr[_]
Out[77]: 
array([([65535,   249], 0.07692308), ([65535,   479], 0.33333333),
       ([65535,  2295], 0.09090909), ([65536,     1], 1.33566434),
       ([65536,     2], 2.06068931), ([65536, 65536], 0.2       )],
      dtype=[('pre', '<i4', (2,)), ('data', '<f8')])

刚刚为numpy sort 2d: rearrange rows without changing values in row推荐了类似的lexsort