Как преобразовать целочисленный массив в двоичный массив определенной длины - PullRequest
3 голосов
/ 11 апреля 2019

Я пытаюсь преобразовать массив целых чисел, скажем, A=[3,5,2], в двоичный массив пустых чисел с первым младшим битовым форматом и определенной длиной. То есть результат для длины 6 должен быть следующим:

A' = [1 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0]

Первые 6 значений относятся к первому элементу A, вторые 6 относятся к второму элементу A, а последние 6 к последнему элементу A.

Мое текущее решение выглядит следующим образом:

np.multiply( np.delete( np.unpackbits( np.abs(A.astype(int)).view("uint8")).reshape(-1,8)[:,::-1].reshape(-1,64), np.s_[ln::],1).astype("float64").ravel(), np.repeat(np.sign(A), ln))

, где ln представляет конкретный ln (в примере это было 6)

Есть ли более быстрый способ сделать это?

Заранее спасибо.

РЕДАКТИРОВАТЬ: Я должен был указать ранее. A также может иметь отрицательные значения. Например, если A=[-11,5] и ln=6, то возвращаемый массив должен быть:

A'=[-1 -1 0 -1 0 0 1 0 1 0 0 0]

Обратите внимание, что ln=6 это только пример. Это может быть даже 60.

Извините, что пропустил эту часть требования.

Ответы [ 3 ]

2 голосов
/ 11 апреля 2019

Вот векторизованный -

((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')

Другой с np.unpackbits -

np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()

Пример выполнения -

In [197]: A
Out[197]: array([3, 5, 2])

In [198]: ln = 6

In [199]: ((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')
Out[199]: array([1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], dtype=int8)

In [200]: np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()
Out[200]: array([1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0], dtype=uint8)

Синхронизация большого массива -

In [201]: A = np.random.randint(0,6,1000000)

In [202]: ln = 6

In [203]: %timeit ((A[:,None] & (1 << np.arange(ln)))!=0).ravel().view('i1')
10 loops, best of 3: 32.1 ms per loop

In [204]: %timeit np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1].ravel()
100 loops, best of 3: 8.14 ms per loop

Если у вас все в порядке с выводом массива 2D, где каждая строка содержит двоичную информацию для каждого элемента на входе, это намного лучше -

In [205]: %timeit np.unpackbits(A.view(np.uint8)[::8]).reshape(-1,8)[:,ln-7:1:-1]
1000 loops, best of 3: 1.04 ms per loop

Другие опубликованные подходы -

# @aburak's soln
In [206]: %timeit np.multiply( np.delete( np.unpackbits( np.abs(A.astype(int)).view("uint8")).reshape(-1,8)[:,::-1].reshape(-1,64), np.s_[ln::],1).astype("float64").ravel(), np.repeat(np.sign(A), ln))
10 loops, best of 3: 180 ms per loop

# @Jacques Gaudin's soln
In [208]: %timeit np.array([int(c) for i in A for c in np.binary_repr(i, width=6)[::-1]])
1 loop, best of 3: 3.34 s per loop

# @Paul Panzer's soln
In [209]: %timeit np.unpackbits(A[:, None].view(np.uint8)[..., ::-1] if sys.byteorder=='little' else A[:, None].view(np.uint8), axis=-1)[..., :-ln-1:-1].reshape(-1)
10 loops, best of 3: 35.4 ms per loop

Лучшее, что сработало в пользу второго подхода из этого поста, - это то, что у нас есть версия ввода uint8 dtype, которая представляет собой просто представление ввода и, следовательно, экономит память -

In [238]: A
Out[238]: array([3, 5, 2])

In [239]: A.view(np.uint8)[::8]
Out[239]: array([3, 5, 2], dtype=uint8)

In [240]: np.shares_memory(A,A.view(np.uint8)[::8])
Out[240]: True

Итак, когда мы используем np.unpackbits, мы вводим то же количество элементов, что и исходный.

Кроме того, A.view(np.uint8)[::8] кажется хорошим трюком для просмотрамассив int dtype как uint8 one!


Чтобы решить для общего случая, мы могли бы расширить ранее перечисленные подходы.

Подход № 1 (для ln до 63):

(((np.abs(A)[:,None] & (1 << np.arange(ln)))!=0)*np.sign(A)[:,None]).ravel()

Подход № 2:

a = np.abs(A)
m = ((ln-1)//8)+1
b = a.view(np.uint8).reshape(-1,8)[:,:m]
U = np.unpackbits(b,axis=1)
out = U.reshape(-1,m,8)[...,::-1].reshape(len(A),-1)[...,:ln]
out = (out*np.sign(A)[:,None]).ravel()
2 голосов
/ 11 апреля 2019

Вы можете сделать это, используя binary_repr:

arr = np.array([3,5,2])
res = np.array([int(c) for i in arr for c in np.binary_repr(i, width=6)[::-1]])

>>>[1 1 0 0 0 0 1 0 1 0 0 0 0 1 0 0 0 0]

[::-1] - это способ перебора строки в обратном порядке: шаг итерации равенустановите на -1.Для получения более подробной информации обратитесь к документам с расширенными слайсами .

Или со строкой форматирования (хотя это начинает выглядеть как код гольф):

res = np.array([int(c) for i in arr for c in f'{i:06b}'[::-1]])

f'{i:06b}'является строкой, представляющей i в двоичном виде с 6 цифрами и ведущими нулями.

По скорости, это очень медленно ... Извините, я не понял этого вопроса!

1 голос
/ 11 апреля 2019

Может быть, я ничего не знаю о полной мощи вашего решения, но, похоже, в нем есть несколько несущественных ингредиентов.

Вот упрощенная версия. Он проверяет порядок байтов и должен работать до 64 бит на типовых платформах.

A = np.arange(-2, 3)*((2**40)-1)
ln = 60

np.unpackbits(np.abs(A[..., None]).view(np.uint8)[..., ::-1] if sys.byteorder=='little' else np.abs(A[..., None]).view(np.uint8), axis=-1)[..., :-ln-1:-1].view(np.int8) * np.sign(A[:, None]).astype(np.int8)

выход

array([[ 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
        -1, -1, -1, -1, -1, -1, -1, -1,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0],
       [ 0,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
         1,  1,  1,  1,  1,  1,  1,  1,  1,  0,  0,  0,  0,  0,  0,  0,
         0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0]], dtype=int8)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...