Как декодировать массив закодированных литералов/строк в Python3? AttributeError: объект «numpy.ndarray» не имеет атрибута «декодировать»

В Python 3 у меня есть следующий массив NumPy из strings.

Каждый string в массиве NumPy имеет форму b'MD18EE вместо MD18EE.

Например:

import numpy as np
print(array1)
(b'first_element', b'element',...)

Обычно для декодирования этих элементов используется .decode('UTF-8').

Однако, если я попытаюсь:

array1 = array1.decode('UTF-8')

Я получаю следующую ошибку:

AttributeError: 'numpy.ndarray' object has no attribute 'decode'

Как мне декодировать эти элементы из массива NumPy? (То есть я не хочу b'')

ИЗМЕНИТЬ:

Допустим, я имел дело с Pandas DataFrame только с определенными столбцами, которые были закодированы таким образом. Например:

import pandas as pd
df = pd.DataFrame(...)

df
        COL1          ....
0   b'entry1'         ...
1   b'entry2'
2   b'entry3'
3   b'entry4'
4   b'entry5'
5   b'entry6'

person ShanZhengYang    schedule 02.11.2016    source источник


Ответы (2)


У вас есть массив строк байтов; тип S:

In [338]: arr=np.array((b'first_element', b'element'))
In [339]: arr
Out[339]: 
array([b'first_element', b'element'], 
      dtype='|S13')

astype легко преобразует их в unicode, тип строки по умолчанию для Py3.

In [340]: arr.astype('U13')
Out[340]: 
array(['first_element', 'element'], 
      dtype='<U13')

Также есть библиотека строковых функций — применение соответствующего метода str к элементам строкового массива

In [341]: np.char.decode(arr)
Out[341]: 
array(['first_element', 'element'], 
      dtype='<U13')

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

См. также Как декодировать массив numpy dtype=numpy .строка_?

person hpaulj    schedule 03.11.2016

Если вы хотите, чтобы результатом был список строк (Python), вы можете использовать понимание списка:

>>> l = [el.decode('UTF-8') for el in array1]
>>> print(l)
['element', 'element 2']
>>> print(type(l))
<class 'list'>

В качестве альтернативы, если вы хотите сохранить его как массив Numpy, вы можете использовать np.vectorize для создания функции векторизованного декодера:

>>> decoder = np.vectorize(lambda x: x.decode('UTF-8'))
>>> array2 = decoder(array1)
>>> print(array2)
['element' 'element 2']
>>> print(type(array2))
<class 'numpy.ndarray'>
person Wander Nauta    schedule 02.11.2016
comment
Спасибо! Я беру массив numpy и помещаю его в кадр данных pandas. Может быть, есть более быстрые способы? Преобразовать по столбцу? - person ShanZhengYang; 02.11.2016
comment
Вы имеете в виду быстрее, как «работает быстрее», или быстрее, как «меньше кода»? Поскольку оба метода являются однострочными, операторы печати просто показывают, что они работают :) - person Wander Nauta; 02.11.2016
comment
:) Я думал бежать быстрее. Тем не менее, я думаю, что этот метод работает нормально — похоже, это побочный эффект Python2/Python3, поэтому я подозреваю, что другие столкнулись с этой проблемой. - person ShanZhengYang; 02.11.2016
comment
В любом случае, использование decoder дает мне эту ошибку: AttributeError: 'numpy.void' object has no attribute 'decode' - person ShanZhengYang; 02.11.2016
comment
Хм, в таком случае похоже, что ваш массив вовсе не массив строк, а скорее массив строк и void, но я уверен, что вы сможете модифицировать декодер для их обработки. В любом случае, я думаю, что лучший (и, вероятно, самый быстрый) способ приблизиться к этому — убедиться, что вы везде используете строки, а не байты. То, как вы это сделаете, зависит от того, откуда берутся ваши данные и как вы их читаете. - person Wander Nauta; 02.11.2016
comment
Вы будете декодировать только байты и игнорировать пустоты: lambda x: x.decode('UTF-8') if isinstance(x, bytes) else x Однако, как я уже сказал, было бы лучше иметь дело с чем-то другим. - person Wander Nauta; 03.11.2016
comment
np.void, вероятно, является записью из структурированного массива, составного dtype. Что такое dtype вашего массива. - person hpaulj; 03.11.2016