Python 如何用反向二进制表示法重新索引numpy数组?

Python 如何用反向二进制表示法重新索引numpy数组?,python,pandas,numpy,Python,Pandas,Numpy,如何改进以下代码? 1)->传递长度为2**n的一维数组 2)->对于数组的每个索引,获取二进制表示 3)->反转二进制表示,并将其用作相应值的新整数索引 示例: def order_in_reversed_bits(data: np.ndarray) -> np.ndarray: tobinary = lambda t: np.binary_repr(t, width=len(np.binary_repr(data.shape[0]-1)))[::-1] func = n

如何改进以下代码?

1)->传递长度为
2**n的一维数组

2)->对于数组的每个索引,获取二进制表示

3)->反转二进制表示,并将其用作相应值的新整数索引

示例:

def order_in_reversed_bits(data: np.ndarray) -> np.ndarray:
    tobinary = lambda t: np.binary_repr(t, width=len(np.binary_repr(data.shape[0]-1)))[::-1]
    func = np.vectorize(tobinary)
    a = func(np.arange(0,data.shape[0]))
    t = np.zeros(data.shape,dtype='float64')

    for i,k in enumerate(a):
        t[int(k,2)] = data[i]

    return t
[56209,81,42]

[00,01,10,11](指数的二进制表示)

->反面:[00,10,01,11]

->成为:[56,81209,42]

代码:

def order_in_reversed_bits(data: np.ndarray) -> np.ndarray:
    tobinary = lambda t: np.binary_repr(t, width=len(np.binary_repr(data.shape[0]-1)))[::-1]
    func = np.vectorize(tobinary)
    a = func(np.arange(0,data.shape[0]))
    t = np.zeros(data.shape,dtype='float64')

    for i,k in enumerate(a):
        t[int(k,2)] = data[i]

    return t

Numpy或Python的哪些内置功能比较方便?

例如,您可以将
sorted
与自定义密钥一起使用(感谢@hpaulj使用
bin()改进了密钥函数
):

印刷品:

[56, 81, 209, 42]
0.05821935099811526
0.22723246600071434

时间:

import timeit
from random import randint

def order_in_reversed_bits_python(lst):
    return [v for _, v in sorted(enumerate(lst), key=lambda k: bin(k[0])[:1:-1])]

def order_in_reversed_bits(data):
    tobinary = lambda t: np.binary_repr(t, width=len(np.binary_repr(data.shape[0]-1)))[::-1]
    func = np.vectorize(tobinary)
    a = func(np.arange(0,data.shape[0]))
    t = np.zeros(data.shape,dtype='float64')

    for i,k in enumerate(a):
        t[int(k,2)] = data[i]

    return t

# create some large array:
lst = np.array([randint(1, 100) for _ in range(2**16)])

t1 = timeit.timeit(lambda: order_in_reversed_bits_python(lst), number=1)
t2 = timeit.timeit(lambda: order_in_reversed_bits(lst), number=1)

print(t1)
print(t2)
印刷品:

[56, 81, 209, 42]
0.05821935099811526
0.22723246600071434
这就是改进~3.9x

这个问题被称为。唯一困难的部分是反转索引的二进制表示形式。你会找到办法的。我选择最简单的一个:

def bit_reversal_permutation(n):
    indices = range(2**n)
    rev_bits = lambda x: int(format(x, f'0{n}b')[::-1], 2)
    return np.fromiter(map(rev_bits, indices), dtype=int)
更快的版本,基于以下观察:

此序列中的每个置换可以通过连接两个数字序列来生成:前一个置换加倍,以及相同的序列,每个值增加一

例如:

n = 4
a = np.random.randn(2**n)
inds_rev = bit_reversal_permutation(n)

a[inds_rev]

vectorize
不会使应用
np.binary\u repr
更快。它仍然会为每个数字生成一个字符串。@hpaulj谢谢!这些提示总是有用的!这表明我对所发生的事情和我所做的事情缺乏理解。
np.vectorize
的名字引起了很多误解。它确实可以在整个阵列上运行,但不是以理想的方式产生10倍的加速比。其他人使用
vectorize
来表示使用多处理和快速硬件引擎。你被接受的答案之所以快速,是因为
'{:b}'。格式
np.binary\u repr
快。我刚刚意识到
np.binary\u repr
是Python代码,我们可以研究并可能修改它。核心操作是
bin(n)
,它生成一个类似“0b10001”的字符串。它只是清理并调整宽度。@hpaulj我不知道np.fft()是如何实现的,但这个请求是计算itI的一部分,我不知道我是否以正确的方式比较了代码,但它运行得比较慢,而且我还遇到了一个高n的prolem:'值:lst=np.array([randint(1100)表示范围内的u(2**8)])'我收到:rev_index=np.fromiter(map(rev_位,index),dtype=int)溢出错误:Python int太大,无法转换为C long,可能是因为dtype。@user2853437您是如何测试它的?对于n=8,应该没有任何问题。对于
lst=np.array([randint(1100)用于范围内(2**8)])
您应该使用
n=8
inds\u rev=bit\u reversion\u置换(n)
lst[inds\u rev]
。当然,对于n>64,您将有numpy问题。我通过在
键中使用
bin
键=lambda k:bin(k[0]来进一步加速[:1:-1]
。反转后,宽度就不重要了。@hpaulj谢谢,这似乎太明显了(我编辑了我的答案)!
bin()
确实是我的第一个想法,但是使用了
str.format
(我不知道如何使用
排序后的
格式,但你的版本做到了:)