Преобразовать список массивов NumPy np.uint8 в массив np.unicode_ - PullRequest
1 голос
/ 15 июня 2019

У меня есть список массивов переменного размера NumPy с dtype=np.uint8 (они представляют строки в кодировке UTF-8).Как эффективно и быстро преобразовать этот список в один массив dtype=np.unicode_?

l = [np.frombuffer(b'asd', dtype = np.uint8), np.frombuffer(b'asdasdas', dtype = np.uint8)]

# The following will work, but will first create a temporary string which is inefficient. 
# I'm looking for a method that would directly allocate a target np.unicode_-typed array 
# and encode the data into it.
a = np.array([s.tostring().decode('utf-8') for s in l])

Массивы не просто кодируются в ASCII, они содержат другие символы:

s = b'8 \xd0\x93\xd0\xbe\xd1\x80\xd0\xbe\xd0\xb4 \xd0\x91\xd0\xb0\xd0\xb9\xd0\xba\xd0\xbe\xd0\xbd\xd1\x83\xd1\x80 (\xd0\xa0\xd0\xb5\xd1\x81\xd0\xbf\xd1\x83\xd0\xb1\xd0\xbb ...: \xd0\xb8\xd0\xba\xd0\xb0 \xd0\x9a\xd0\xb0\xd0\xb7\xd0\xb0\xd1\x85\xd1\x81\xd1\x82\xd0\xb0\xd0\xbd)' 

s.decode('utf-8') # works

1 Ответ

0 голосов
/ 17 июня 2019

update

Оказывается, кодек Python utf-8 можно использовать для непосредственного декодирования ndarray, без необходимости копировать его содержимое в строку байтов с помощью .tostring(): сначала с помощьюМодуль кодеков позволяет извлекать вызываемый файл, который охватывает последовательности байтов utf-8, в строки Unicode без необходимости проходить через str.decode

lst = [np.frombuffer(b'asd', dtype = np.uint8), np.frombuffer(b'asdasdas', dtype = np.uint8)]

import codecs

decoder = codes.getdecoder("utf-8")    
data = np.array([decoder(item)[0] for item in lst], dtype="unicode")

Это позволяет избежать одного шага преобразования - есть еще один шаг, которыйможно было бы избежать, потому что это все равно создаст список всех строк в памяти перед вызовом последнего конструктора .array - numpy имеет конструктор массива .fromiter - но он не может создать массив с произвольными объектами Unicode - ему нуженфиксированная ширина символа.Это потребовало бы больше памяти, чем вы сейчас:

data = np.fromiter((decoder(item) for item in lst), count=len(lst), dtype="U120")  # For max-length of 120 characters.

оригинал-ответ (главным образом Рим),

Современная Python внутренняя обработка текста Unicode - этодовольно эффективный, с внутренним представлением точек Unicode, зависящим от самого широкого символа в строке.

Numpy, с другой стороны, просто хранит 32-битное значение для каждого символа Unicode - и у него нет делового "понимания" utf-8.Язык Python делает это очень хорошо - и это быстро.Хотя Python не будет использовать многопоточные, многоядерные или аппаратно-ускоренные стратегии при декодировании байтов utf-8 в текст, декодирование происходит в собственном коде и выполняется так же быстро, как и в одном ядре ЦП.

Декодирование текста размером 4 МБ в Unicode с использованием простого Python заняло менее 30 мс в моей системе.

Другими словами: вас беспокоит не та проблема - если только то, что вы кодируете, не нуждается в устойчивом преобразовании примерно 100-битного текстового корпуса в секунду.

Просто позвольте Python выполнить декодирование utf-8 и обработать результат обратно в numpy (который снова закодирует его в 32-битном формате) - тратится на это столь незначительно для подавляющего большинства реальныхВ мире задач, например, библиотека Pandas выполняет практически все свои действия с данными: создает новые копии после каждой операции.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...