numpy矢量化方法来计算整数数组中的非零位

Ale*_*arp 3 python arrays numpy vectorization

我有一个整数数组:

[int1, int2, ..., intn]
Run Code Online (Sandbox Code Playgroud)

我想计算这些整数的二进制表示中有多少非零位。

例如:

bin(123) -> 0b1111011, there are 6 non-zero bits
Run Code Online (Sandbox Code Playgroud)

当然,我可以遍历整数、用途bin()count('1')函数的列表,但我正在寻找矢量化的方法来做到这一点。

Mad*_*ist 8

由于 numpy 与 python 不同,整数大小有限,因此您可以将\xc3\x93scar L\xc3\xb3pez提出的位旋转解决方案改编为快速计算正整数中非零位的方法(最初来自此处),以便可移植,快速解决方案:

\n
def bit_count(arr):\n     # Make the values type-agnostic (as long as it\'s integers)\n     t = arr.dtype.type\n     mask = t(-1)\n     s55 = t(0x5555555555555555 & mask)  # Add more digits for 128bit support\n     s33 = t(0x3333333333333333 & mask)\n     s0F = t(0x0F0F0F0F0F0F0F0F & mask)\n     s01 = t(0x0101010101010101 & mask)\n\n     arr = arr - ((arr >> 1) & s55)\n     arr = (arr & s33) + ((arr >> 2) & s33)\n     arr = (arr + (arr >> 4)) & s0F\n     return (arr * s01) >> (8 * (arr.itemsize - 1))\n
Run Code Online (Sandbox Code Playgroud)\n

该函数的第一部分将数量 0x5555...、0x3333...等截断为arr实际组成的整数类型。其余部分仅执行一组位调整操作。

\n

对于 100000 个元素的数组,此函数比 Ehsan 的方法快约 4.5 倍,比 Valdi Bo 的方法快约 60 倍:

\n
a = np.random.randint(0, 0xFFFFFFFF, size=100000, dtype=np.uint32)\n%timeit bit_count(a).sum()\n# 846 \xc2\xb5s \xc2\xb1 16.5 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 1000 loops each)\n%timeit m1(a)\n# 3.81 ms \xc2\xb1 24 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 100 loops each)\n%timeit m2(a)\n# 49.8 ms \xc2\xb1 97.5 \xc2\xb5s per loop (mean \xc2\xb1 std. dev. of 7 runs, 10 loops each)\n
Run Code Online (Sandbox Code Playgroud)\n

m1并按m2原样取自@Ehsan\'s 答案

\n


Ehs*_*san 5

假设您的数组是a,您可以简单地执行以下操作:

np.unpackbits(a.view('uint8')).sum()
Run Code Online (Sandbox Code Playgroud)

例子:

a = np.array([123, 44], dtype=np.uint8)
#bin(a) is [0b1111011, 0b101100]
np.unpackbits(a.view('uint8')).sum()
#9
Run Code Online (Sandbox Code Playgroud)

比较使用benchit

#@Ehsan's solution
def m1(a):
  return np.unpackbits(a.view('uint8')).sum()

#@Valdi_Bo's solution
def m2(a):
  return sum([ bin(n).count('1') for n in a ])

in_ = [np.random.randint(100000,size=(n)) for n in [10,100,1000,10000,100000]]
Run Code Online (Sandbox Code Playgroud)

m1明显更快。

在此处输入图片说明