在Python中将2d二进制列表转换为十进制数的算法

时间:2017-10-15 16:16:50

标签: python algorithm list

当我尝试将二进制数据的巨大二维数据列表转换为十进制数时,我遇到了这个性能问题。

给出一个清单:

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

这个循环对于数千行的列表来说很慢,是否有更好的解决方案?

3 个答案:

答案 0 :(得分:1)

首先,使用join使用string to int转换很方便,但速度很慢。使用sumenumerate计算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.Counternp.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)