Как создать массив двоичных цифр заданных беззнаковых целых чисел с Numpy? - PullRequest
1 голос
/ 20 марта 2020

У меня есть массив чисел от 0 до 3, и я хочу создать двумерный массив из их двоичных цифр.

в будущем может потребоваться массив чисел от 0 до 7 или 0 до 15.

В настоящее время мой массив определен так:

a = np.array([[0], [1], [2], [3]], dtype=np.uint8)

Я использовал numpy unpackbits Функция:

b = np.unpackbits(a, axis=1)

, и результат такой :

array([[0, 0, 0, 0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 1],
       [0, 0, 0, 0, 0, 0, 1, 0],
       [0, 0, 0, 0, 0, 0, 1, 1]], dtype=uint8)

Как вы можете видеть, он создал 2-мерный массив с 8 элементами в столбце, в то время как я ищу 2-мерный массив из 2 столбцов.

вот мой нужный массив:

array([[0, 0],
       [0, 1],
       [1, 0],
       [1, 1]])

Это связано с типом данных uint8?

какова ваша идея?

Ответы [ 4 ]

1 голос
/ 20 марта 2020

Вы можете использовать ключевое слово count. Он обрезается справа, поэтому вам также нужно сдвинуть биты перед применением unpackbits.

b = np.unpackbits(a<<6, axis=1, count=2)
b
# array([[0, 0],
#        [0, 1],
#        [1, 0],
#        [1, 1]], dtype=uint8)

. Это создаст «чистый» массив:

b.flags
#  C_CONTIGUOUS : True
#  F_CONTIGUOUS : False
#  OWNDATA : True
#  WRITEABLE : True
#  ALIGNED : True
#  WRITEBACKIFCOPY : False
#  UPDATEIFCOPY : False

В отличие от этого, нарезка полного Вывод из 8 столбцов unpackbits в некотором смысле является утечкой памяти, поскольку отброшенные столбцы будут оставаться в памяти в течение всего срока жизни среза.

1 голос
/ 20 марта 2020

Один из способов решения этой проблемы - просто адаптировать ваш b для соответствия желаемому результату с помощью простого среза, аналогично тому, что предложено в @ GrzegorzSkibinski answer :

import numpy as np


def gen_bits_by_val(values):
    n = int(max(values)).bit_length()
    return np.unpackbits(values, axis=1)[:, -n:].copy()


print(gen_bits_by_val(a))
# [[0 0]
#  [0 1]
#  [1 0]
#  [1 1]]

В качестве альтернативы, вы можете создать справочную таблицу, аналогично предложенной в @ WarrenWeckesser answer , используя следующее:

import numpy as np


def gen_bits_by_num(n):
    values = np.arange(2 ** n, dtype=np.uint8).reshape(-1, 1)
    return np.unpackbits(values, axis=1)[:, -n:].copy()


bits2 = gen_bits_by_num(2)
print(bits2)
# [[0 0]
#  [0 1]
#  [1 0]
#  [1 1]]

, которая допускает все виды использования таким образом указано, например:

bits4 = gen_bits_by_num(4)
print(bits4[[1, 3, 12]])
# [[0 0 0 1]
#  [0 0 1 1]
#  [1 1 0 0]]

РЕДАКТИРОВАТЬ

Учитывая @ PaulPanzer ответ строка:

return np.unpackbits(values, axis=1)[:, -n:]

была заменена на :

return np.unpackbits(values, axis=1)[:, -n:].copy()

, что более эффективно для памяти.

Его можно заменить на:

return np.unpackbits(values << (8 - n), axis=1, count=n)

с аналогичными эффектами.

0 голосов
/ 20 марта 2020

Для такого небольшого количества битов вы можете использовать справочную таблицу.

Например, здесь bits2 - это массив с формой (4, 2), который содержит биты целых чисел 0, 1, 2 и 3. Индекс bits2 со значениями от a для получения битов:

In [43]: bits2 = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])

In [44]: a = np.array([[0], [1], [2], [3]], dtype=np.uint8)

In [45]: bits2[a[:, 0]]
Out[45]: 
array([[0, 0],
       [0, 1],
       [1, 0],
       [1, 1]])

Это также работает для 3 или 4 битов:

In [46]: bits4 = np.array([[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 0, 1, 1], [0, 1, 0, 0], [
    ...: 0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [1, 0, 0, 0], [1, 0, 0, 1], [1, 0, 1, 0], [1, 0,
    ...:  1, 1], [1, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0], [1, 1, 1, 1]])

In [47]: bits4
Out[47]: 
array([[0, 0, 0, 0],
       [0, 0, 0, 1],
       [0, 0, 1, 0],
       [0, 0, 1, 1],
       [0, 1, 0, 0],
       [0, 1, 0, 1],
       [0, 1, 1, 0],
       [0, 1, 1, 1],
       [1, 0, 0, 0],
       [1, 0, 0, 1],
       [1, 0, 1, 0],
       [1, 0, 1, 1],
       [1, 1, 0, 0],
       [1, 1, 0, 1],
       [1, 1, 1, 0],
       [1, 1, 1, 1]])

In [48]: x = np.array([0, 1, 5, 14, 9, 8, 15])

In [49]: bits4[x]
Out[49]: 
array([[0, 0, 0, 0],
       [0, 0, 0, 1],
       [0, 1, 0, 1],
       [1, 1, 1, 0],
       [1, 0, 0, 1],
       [1, 0, 0, 0],
       [1, 1, 1, 1]])
0 голосов
/ 20 марта 2020

Вы можете усечь b, чтобы сохранить только столбцы с первого столбца с 1:

b=b[:, int(np.argwhere(b.max(axis=0)==1)[0]):]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...