python数组的小数转换成二进制数的效率

时间:2014-12-05 08:56:58

标签: python python-3.x binary data-conversion

我制作了一个代码,在一个文件中读取256x256矩阵,将它们转换为二进制数,读取它们的一部分,制作另外两个256x256矩阵的文件。我认为它正在做我想要的,但处理一个文件需要几分钟。有关更高效代码的任何建议吗?

这是我的代码。

#Read in file
f = open(path, 'r')
l = [list(map(int, line.split(' '))) for line in f]
a = np.array(l)
A = a.ravel()

#Convert to binary
bnry = ()
for data in A:
    bnry = np.append(bnry, bin(data))

#Extract two data from each number and store them to 'THL' and 'THH'
thl = ()
thh = ()
THL = ()
THH = ()
for ths in bnry:
    thl = int(ths[2:14], 2)
    THL = np.append(THL, thl)
    thh = int(ths[-12:], 2)
    THH = np.append(THH, thh)

#Save 'THL' and 'THH' to text files
np.savetxt('THL.txt', np.reshape(THL, (256,256)), fmt='%.4g', delimiter=' ')
np.savetxt('THH.txt', np.reshape(THH, (256,256)), fmt='%.4g', delimiter=' ')

解 非常感谢Oliver W.,我能够比我的几分钟长的代码更快地获得更快的代码。他们基本上是

thl = np.bitwise_and(a, 2**12 - 1)
thh = np.bitwise_and(a, (2**12-1) << (12+4)) >> (12+4)

我仍然需要学习更多并熟悉它们的工作原理,但它们工作得很好!

1 个答案:

答案 0 :(得分:0)

你试图提取一系列整数的前12位以及最后12位。这是2个不同的问题。后者是最简单的。

首先,让我们首先使用numpy的便捷方法来读取文本文件中的数据,而不是编写我们自己的(更可能不太理想的)函数:

a = np.fromfile(file, dtype=np.uint32, sep=' ')  # alternative: np.genfromtxt

接下来,让我们解决一个简单的问题:从a:

中提取最低的12位
THH = np.bitwise_and(a, 2**12 - 1)

这是一个矢量化操作,所以它非常高效且速度极快。

获得前12位是另一个问题,因为它取决于数字本身。我的猜测是,这实际上并不是你想要做的,而是有人要求你从一些整数中提取12个“最高”位,当它们被解释为具有固定数量的位时。 “3位最高位”的解释将更清楚:

如果你需要一个数字的3个最高位,比如20,你可以将20解释为像0b10100一样写,在这种情况下,3个最高位是101,这是小数但是,如果您将20解释为0b0010100,那么使用2个前导零,则3个最高位将是001,即十进制数1.实际上不需要很多操作你考虑(最小的)二进制表示的长度,我想这也是你说“我认为它正在做我想要的”的原因。

因此,更有可能的是,您的数字将以固定长度的二进制格式进行解释。看看你提到的最大值,268374015,这个长度大概是28位数(甚至看起来不太可能,32位更常见)。但是,假设它是28位,而你只想提取前12位,你可以使用与以前相同的技巧:

np.logical_and(a, (2**12 - 1)<<16) >> 16

请注意,>><<bitshift operations

我对你的数据做了几个假设(你只处理整数是明确的,因为你用int()转换所有内容)当然,你的真实问题

但是,如果确实希望这些数字的前12位,从最高位开始,则以下代码显示:

  1. 重新实现for循环,效率稍高(method_old()
  2. 该算法的矢量化实现(method_new()
  3. 他们在我的机器上的执行时间。

    import numpy as np
    
    a = np.random.random_integers(0, 268374016, (512,512))
    
    def method_new(nbr_select_bits=12):
        high_bits = np.empty_like(a)
        for bit in range(32, nbr_select_bits -1, -1):
            mask = a < 2**bit
            shift = bit - nbr_select_bits
            bitmask = (2**nbr_select_bits - 1) << shift
            high_bits[mask] = np.bitwise_and(a[mask], bitmask) >> shift
        low_bits = np.bitwise_and(a, 2**nbr_select_bits - 1)
        return high_bits, low_bits
    
    def method_old(nbr_select_bits=12):
        thl = np.empty(a.size, dtype=np.uint32)
        thh = np.empty(a.size, dtype=np.uint32)
        for enu, data in enumerate(a.ravel()):
            thl[enu] = int(bin(data)[2:2+nbr_select_bits], 2)
            try:
                thh[enu] = int(bin(data)[-nbr_select_bits:], 2)
            except ValueError:  # because 'int("b11", 2)' fails
                thh[enu] = int(bin(data)[-(nbr_select_bits+1):], 2)
        return thl.reshape(a.shape), thh.reshape(a.shape)
    
    from timeit import timeit
    new_t = timeit('method_new()', setup='from __main__ import method_new', number=1)
    old_t = timeit('method_old()', setup='from __main__ import method_old', number=1)
    print('Old method ran in {:.2f}ms,\nNew method ran in {:.2f}ms.\n'
        'Speedup: {:.1f}x'.format(old_t*1000, new_t*1000, old_t/new_t))))
    # Output:
    # Old method ran in 473.97ms,
    # New method ran in 60.18ms.
    # Speedup: 7.9x