我正在使用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 特别是非常慢,并逐个添加行号似乎是如此老派。我们将非常感激您的想法。
答案 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