Python 将Numpy数组转换为稀疏字典的最快方法?
我对尽快将numpy数组转换为稀疏字典感兴趣。让我详细说明: 给定阵列:Python 将Numpy数组转换为稀疏字典的最快方法?,python,performance,numpy,Python,Performance,Numpy,我对尽快将numpy数组转换为稀疏字典感兴趣。让我详细说明: 给定阵列: numpy.array([12,0,0,0,3,0,0,1]) 我想出版这本词典: {0:12, 4:3, 7:1} 如您所见,我们只是将序列类型转换为从非零索引到其值的显式映射 为了让这更有趣,我提供了以下测试工具来尝试替代方案: from timeit import Timer if __name__ == "__main__": s = "import numpy; from itertools impor
numpy.array([12,0,0,0,3,0,0,1])
我想出版这本词典:
{0:12, 4:3, 7:1}
如您所见,我们只是将序列类型转换为从非零索引到其值的显式映射
为了让这更有趣,我提供了以下测试工具来尝试替代方案:
from timeit import Timer
if __name__ == "__main__":
s = "import numpy; from itertools import izip; from numpy import nonzero, flatnonzero; vector = numpy.random.poisson(0.1, size=10000);"
ms = [ "f = flatnonzero(vector); dict( zip( f, vector[f] ) )"
, "f = flatnonzero(vector); dict( izip( f, vector[f] ) )"
, "f = nonzero(vector); dict( izip( f[0], vector[f] ) )"
, "n = vector > 0; i = numpy.arange(len(vector))[n]; v = vector[n]; dict(izip(i,v))"
, "i = flatnonzero(vector); v = vector[vector > 0]; dict(izip(i,v))"
, "dict( zip( flatnonzero(vector), vector[flatnonzero(vector)] ) )"
, "dict( zip( flatnonzero(vector), vector[nonzero(vector)] ) )"
, "dict( (i, x) for i,x in enumerate(vector) if x > 0);"
]
for m in ms:
print " %.2fs" % Timer(m, s).timeit(1000), m
我使用泊松分布来模拟我感兴趣的数组类型
以下是我目前的结果:
0.78s f = flatnonzero(vector); dict( zip( f, vector[f] ) )
0.73s f = flatnonzero(vector); dict( izip( f, vector[f] ) )
0.71s f = nonzero(vector); dict( izip( f[0], vector[f] ) )
0.67s n = vector > 0; i = numpy.arange(len(vector))[n]; v = vector[n]; dict(izip(i,v))
0.81s i = flatnonzero(vector); v = vector[vector > 0]; dict(izip(i,v))
1.01s dict( zip( flatnonzero(vector), vector[flatnonzero(vector)] ) )
1.03s dict( zip( flatnonzero(vector), vector[nonzero(vector)] ) )
4.90s dict( (i, x) for i,x in enumerate(vector) if x > 0);
正如你所看到的,我找到的最快的解决方案是
n = vector > 0;
i = numpy.arange(len(vector))[n]
v = vector[n]
dict(izip(i,v))
有没有更快的办法
编辑:
台阶
看起来特别笨拙-在只选择某些元素之前生成整个数组,特别是当我们知道它可能只有被选择元素的1/10左右时。我认为这可能仍有待改进 试过这个吗
从哪里进口
i=其中(向量>0)[0]使用scipy中的稀疏矩阵作为桥接:
from scipy.sparse import *
import numpy
a=numpy.array([12,0,0,0,3,0,0,1])
m=csr_matrix(a)
d={}
for i in m.nonzero()[1]:
d[i]=m[0,i]
print d
以下似乎是一项重大改进:
i = np.flatnonzero(vector)
dict.fromkeys(i.tolist(), vector[i].tolist())
时间:
import numpy as np
from itertools import izip
vector = np.random.poisson(0.1, size=10000)
%timeit f = np.flatnonzero(vector); dict( izip( f, vector[f] ) )
# 1000 loops, best of 3: 951 µs per loop
%timeit f = np.flatnonzero(vector); dict.fromkeys(f.tolist(), vector[f].tolist())
# 1000 loops, best of 3: 419 µs per loop
我还尝试了scipy.sparse.dok_matrix
和pandas.DataFrame.to_dict
,但在我的测试中,它们比原来的慢。您可以使用return\u index=True
:
>>> import numpy as np
>>> arr = np.array([12,0,0,0,3,0,0,1])
>>> val, idx = np.unique(arr, return_index=True)
>>> mask = val != 0 # exclude zero
>>> dict(zip(idx[mask], val[mask])) # create the dictionary
{0: 12, 4: 3, 7: 1}
通常在list
s上迭代比在numpy.array
s上迭代要快,因此使用tolist
将它们转换为列表时可以更快:
>>> dict(zip(idx[mask].tolist(), val[mask].tolist()))
时机
对于短阵列,此方法可能较慢,但根据我的计时,它比其他用于大阵列的方法更快:
import numpy as np
from scipy.sparse import csr_matrix
arr = np.random.randint(0, 10, size=10000) # 10k items
arr[arr < 7] = 0 # make it sparse
# ----------
%timeit {i:arr[i] for i in np.nonzero(arr)[0]}
# 3.7 ms ± 51 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# ----------
%%timeit
val, idx = np.unique(arr, return_index=True)
mask = val != 0
dict(zip(idx[mask].tolist(), val[mask].tolist()))
# 844 µs ± 42.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# ----------
%%timeit
m=csr_matrix(a)
d={}
for i in m.nonzero()[1]:
d[i]=m[0,i]
# 1.52 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
将numpy导入为np
从scipy.sparse导入csr_矩阵
arr=np.random.randint(0,10,大小=10000)#10k项
arr[arr<7]=0#使其稀疏
# ----------
%timeit{i:arr[i]在np.nonzero(arr)[0]}
#每个回路3.7 ms±51µs(7次运行的平均值±标准偏差,每个100个回路)
# ----------
%%时间
val,idx=np.unique(arr,return\u index=True)
掩码=val!=0
dict(zip(idx[mask].tolist(),val[mask].tolist())
#每个回路844µs±42.7µs(7次运行的平均值±标准偏差,每个1000个回路)
# ----------
%%时间
m=csr_矩阵(a)
d={}
对于m.nonzero中的i()[1]:
d[i]=m[0,i]
#每个回路1.52 s±57.4 ms(7次运行的平均值±标准偏差,每个回路1次)
这与flatnonzero不一样吗?还有,你为什么不试试(他甚至张贴了他的测试工具)?如果你真的证明它更快,你会从我这里得到+1。
>>> dict(zip(idx[mask].tolist(), val[mask].tolist()))
import numpy as np
from scipy.sparse import csr_matrix
arr = np.random.randint(0, 10, size=10000) # 10k items
arr[arr < 7] = 0 # make it sparse
# ----------
%timeit {i:arr[i] for i in np.nonzero(arr)[0]}
# 3.7 ms ± 51 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# ----------
%%timeit
val, idx = np.unique(arr, return_index=True)
mask = val != 0
dict(zip(idx[mask].tolist(), val[mask].tolist()))
# 844 µs ± 42.7 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
# ----------
%%timeit
m=csr_matrix(a)
d={}
for i in m.nonzero()[1]:
d[i]=m[0,i]
# 1.52 s ± 57.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)