当我尝试将二进制数据的巨大二维数据列表转换为十进制数时,我遇到了这个性能问题。
给出一个清单:
biglist = [
[[1,0],[0,0],[1,1]],
[[0,0],[1,1],[1,0]],
#...
#easily go to thousands of rows
]
在每一行中,我想要合并每列的所有第一个元素并将其转换为十进制数字:
E.g。
在第0行,我想要int('101',2)
,即5
在第1行中,我想要int('011',2)
,即3
我的最终目标是创建一个字典,计算整数出现的次数。考虑到上面示例中的给定数据,最终结果应该是{key:value}
对的字典,如{a_int : appearance_count}
,如下所示:
{{5:1},{3:1}}
现在我的解决方案就是:
result = {}
for k in biglist:
num = int("".join(str(row[0]) for row in k), 2)
#count
if num not in result:
result[num] = 1
else:
result[num] += 1
这个循环对于数千行的列表来说很慢,是否有更好的解决方案?
答案 0 :(得分:1)
首先,使用join
使用string to int转换很方便,但速度很慢。使用sum
,enumerate
计算2经典幂的值,并对其进行位移(跳过零)
其次,您应该使用collections.Counter
来实现此目标
在一行中:
result = collections.Counter(sum(v[0]<<(len(k)-i-1) for i,v in enumerate(k) if v[0]) for k in biglist)
此代码的运行速度比我机器上的原始代码快30%。
答案 1 :(得分:1)
只收集整数值的位而不是string-int转换:(伪代码)
for every row:
value = 0
for every col:
value = (value << 1) | biglist[row][col][0] # bitwise shift left and OR
#equivalent operation:
value = value * 2 + biglist[row][col][0]
答案 2 :(得分:1)
如果你需要性能,你应该使用numpy或numba,所有低级例程都以接近C的速度完成:
import numpy as np
bigarray=np.random.randint(0,2,10**4*3*2).reshape(10**4,3,2)
biglist=[[[e for e in B] for B in A] for A in bigarray]
# [[[1, 0], [0, 0], [1, 0]],
# [[0, 0], [0, 1], [0, 1]],
# [[1, 0], [1, 0], [0, 0]], ...
def your_count(biglist):
integers=[]
for k in biglist:
num = int("".join(str(row[0]) for row in k), 2)
integers.append(num)
return integers
def count_python(big):
m=len(big)
integers=np.empty(m,np.int32)
for i in range(m):
n=len(big[i])
b=1
s=0
for j in range(n-1,-1,-1):
s = s+big[i][j][0]*b
b=b*2
integers[i]=s
return integers
def count_numpy(bigarray):
integers=(bigarray[:,:,0]*[4,2,1]).sum(axis=1)
return integers
from numba import njit
count_numba =njit(count_python)
还有一些测试:
In [125]: %timeit your_count(biglist)
145 ms ± 22.1 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [126]: %timeit count_python(biglist)
29.6 ms ± 1.13 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
In [127]: %timeit count_numpy(bigarray)
354 µs ± 10.2 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [128]: %timeit count_numba(bigarray)
73 µs ± 938 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Numba允许你编译一些python代码的低级版本(不是你的,因为Numba不管理字符串和列表,只有numpy数组)。 Numpy为您提供了特殊的语法,可以在一条指令中制作精彩的东西,以获得良好的表现。
Numba解决方案比你的速度快2000倍。
计数由collections.Counter
或np.unique
:
In [150]: %timeit {k:v for k,v in zip(*np.unique(integers,return_counts=True))}
46.4 µs ± 1.55 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [151]: %timeit Counter(integers)
218 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)