如何在结构化的numpy数组中添加“RowNumber”字段?

时间:2016-02-19 00:01:48

标签: python arrays numpy

我正在使用genfromtxt将大型csv文件加载到结构化数组中。我需要对数据进行排序(使用多个字段),做一些工作,然后将数据恢复到原始排序。我的计划是在数据中添加另一个字段,并在应用第一个排序之前将行号放入此字段。然后它可以用于在结束时恢复订单。我认为可能有一种优雅的方式来添加这个记录数字的领域,但经过几个小时的尝试和搜索想法,我没有什么特别光滑。

import numpy
import numpy.lib.recfunctions as rfn
def main():
    csvDataFile = 'C:\\File1.csv'
    csvData = numpy.genfromtxt(csvDataFile, delimiter=',',names = True, dtype='f8')
    rowNums = numpy.zeros(len(csvData),dtype=[('RowID','f8')])
    #populate and add column for RowID
    for i in range (0, len(csvData)):
        rowNums['RowID'][i]=i
    csvDataWithID = rfn.merge_arrays((csvData, rowNums), asrecarray=True, flatten=True)

在     recfunctions.merge_arrays 特别是非常慢,并逐个添加行号似乎是如此老派。我们将非常感激您的想法。

2 个答案:

答案 0 :(得分:0)

您不需要迭代填写rowNums

In [93]: rowNums=np.zeros(10,dtype=[('RowID','f8')])
In [94]: for i in range(0,10):
   ....:     rowNums['RowID'][i]=i
   ....:     
In [95]: rowNums
Out[95]: 
array([(0.0,), (1.0,), (2.0,), (3.0,), (4.0,), (5.0,), (6.0,), (7.0,),
       (8.0,), (9.0,)], 
      dtype=[('RowID', '<f8')])

只需将范围值分配给字段:

In [96]: rowNums['RowID']=np.arange(10)
In [97]: rowNums
Out[97]: 
array([(0.0,), (1.0,), (2.0,), (3.0,), (4.0,), (5.0,), (6.0,), (7.0,),
       (8.0,), (9.0,)], 
      dtype=[('RowID', '<f8')])

rfn.merge_arrays不应该那么慢 - 除非csvData.dtype有大量字段。此函数创建一个新的dtype,它合并2个输入的字段,然后逐字段复制数据。对于许多行,只有几个字段,这是非常快的。

但是你应该可以在不添加额外字段的情况下获得原始订单。

2场1d阵列:

In [118]: x = np.array([(4,2),(1, 0), (0, 1),(1,2),(3,1)], dtype=[('x', '<i4'), ('y', '<i4')])
In [119]: i = np.argsort(x, order=('y','x'))
In [120]: i
Out[120]: array([1, 2, 4, 3, 0], dtype=int32)
In [121]: x[i]
Out[121]: 
array([(1, 0), (0, 1), (3, 1), (1, 2), (4, 2)], 
      dtype=[('x', '<i4'), ('y', '<i4')])

现在,相同的值首先在y上排序,然后排在x上。

In [122]: j=np.argsort(i)
In [123]: j
Out[123]: array([4, 0, 1, 3, 2], dtype=int32)
In [124]: x[i][j]
Out[124]: 
array([(4, 2), (1, 0), (0, 1), (1, 2), (3, 1)], 
      dtype=[('x', '<i4'), ('y', '<i4')])

返回原始订单

我本可以向x添加一个行索引数组,然后对其进行排序。但为什么要添加它;为什么不将i应用于单独的数组:

In [127]: np.arange(5)[i]
Out[127]: array([1, 2, 4, 3, 0])

但排序与排序i完全相同。

merge_arrays基本上做了以下事情:

联盟dtype:

In [139]: dt=np.dtype(rowNums.dtype.descr+x.dtype.descr)
In [140]: y=np.zeros((5,),dtype=dt)

填写值:

In [141]: y['RowID']=np.arange(5)
In [143]: for name in x.dtype.names:
    y[name]=x[name]
In [144]: y
Out[144]: 
array([(0.0, 4, 2), (1.0, 1, 0), (2.0, 0, 1), (3.0, 1, 2), (4.0, 3, 1)], 
      dtype=[('RowID', '<f8'), ('x', '<i4'), ('y', '<i4')])

并测试我的argsort argsort想法:

In [145]: y[i]
Out[145]: 
array([(1.0, 1, 0), (2.0, 0, 1), (4.0, 3, 1), (3.0, 1, 2), (0.0, 4, 2)], 
      dtype=[('RowID', '<f8'), ('x', '<i4'), ('y', '<i4')])
In [146]: np.argsort(y[i],order=('RowID'))
Out[146]: array([4, 0, 1, 3, 2], dtype=int32)
In [147]: j
Out[147]: array([4, 0, 1, 3, 2], dtype=int32)

对重新排序的RowID进行排序与​​对i进行排序相同。

奇怪的是merge_arrays比我的重建慢得多:

In [163]: rfn.merge_arrays([rowNums,x],flatten=True)
Out[163]: 
array([(0.0, 4, 2), (1.0, 1, 0), (2.0, 0, 1), (3.0, 1, 2), (4.0, 3, 1)], 
      dtype=[('RowID', '<f8'), ('x', '<i4'), ('y', '<i4')])
In [164]: timeit rfn.merge_arrays([rowNums,x],flatten=True)
10000 loops, best of 3: 161 µs per loop

In [165]: %%timeit 
dt=np.dtype(rowNums.dtype.descr+x.dtype.descr)
y=np.zeros((5,),dtype=dt)
y['RowID']=rowNums['RowID']
for name in x.dtype.names:
    y[name]=x[name]
10000 loops, best of 3: 38.4 µs per loop

答案 1 :(得分:0)

rowNums = np.zeros(len(csvData),dtype=[('RowID','f8')])
rowNums['RowID']=np.arange(len(csvData))

以上使用我正在使用的csv文件可以节省大约半秒的文件。到目前为止非常好。

但关键是如何有效地获取排序顺序的记录。这是使用;

最优雅地解决的
sortorder = np.argsort(csvData, 'col_1','col_2','col_3','col_4','col_5')

给出一个数组,列出按照cols 1到5排序时CsvData中项目的顺序。 这消除了制作,填充和合并RowID列的需要,每个csv文件节省了大约15秒(在整个数据集中超过6小时。)

非常感谢@hpaulj