Как преодолеть неэшируемый тип: ошибка «список» при попытке получить уникальные значения из столбца фрейма данных pandas в Python

#python #pandas #dataframe #unique-values

Вопрос:

У меня есть фрейм данных Pandas с данными Facebook, собранными с помощью Crowdtangle, где я хотел бы получить уникальные значения некоторых столбцов.

Для большинства столбцов такое выражение отлично работает: df.column_name.unique(). Пример:

 In: df.account_name.unique()

Out: array(['YO TE BANCO VICTOR HUGO MORALES!!!',
       'Lula de novo, com a força do povo',
       'SOCIEDADE CIVIL, LEVANTA E RESISTE !', ..., 'Steemit',
       'BOLSONARO REELEITO EM 2022',
       'WE SUPPORT HUMAN RIGHTS OF SHIAS WORLDWIDE!'], dtype=object)
 

Однако для некоторых столбцов такая команда не работает. Вместо этого я получаю ошибку типа: недоступный тип: «список». Например, когда я набираю этот код: df.country_mentions_domestic.unique().

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

Пример полного сообщения об ошибке:

 In: df.country_mentions_domestic.unique()

Out: TypeError                                 Traceback (most recent call last)
/var/folders/8k/lzt5y36n293d8wkk3svczgnr0000gn/T/ipykernel_2389/3653985748.py in <module>
----> 1 df_fb.country_mentions_domestic.unique()
      2 # print()
      3 # print(df_country_mentions_en.unique())
      4 # print()
      5 # print(df_country_mentions_ru_text.unique())

/usr/local/Cellar/jupyterlab/3.1.10/libexec/lib/python3.9/site-packages/pandas/core/series.py in unique(self)
   2037         Categories (3, object): ['a' < 'b' < 'c']
   2038         """
-> 2039         return super().unique()
   2040 
   2041     @overload

/usr/local/Cellar/jupyterlab/3.1.10/libexec/lib/python3.9/site-packages/pandas/core/base.py in unique(self)
    977                     result = np.asarray(result)
    978         else:
--> 979             result = unique1d(values)
    980 
    981         return result

/usr/local/Cellar/jupyterlab/3.1.10/libexec/lib/python3.9/site-packages/pandas/core/algorithms.py in unique(values)
    429 
    430     table = htable(len(values))
--> 431     uniques = table.unique(values)
    432     uniques = _reconstruct_data(uniques, original.dtype, original)
    433     return uniques

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable.unique()

pandas/_libs/hashtable_class_helper.pxi in pandas._libs.hashtable.PyObjectHashTable._unique()

TypeError: unhashable type: 'list'
 

Ответ №1:

Это означает, что по крайней мере одно (если не больше) из значений в этом столбце list не является строкой.

.unique() Функция сравнивает значения в столбце друг с другом, используя их хэш-значения. Поскольку списки python изменчивы (т. Е. Они могут изменять содержимое), с ними не может быть связано фиксированное хэш-значение.

Вы можете выяснить, какие из них с чем-то подобным:

 df[[isinstance(val, list) for val in df.country_mentions_domestic.values]]
 

Если вам действительно нужно, чтобы у некоторых из них были коллекции значений, вы можете преобразовать свои списки в кортежи (или в строки, разделенные чем-то вроде точки с запятой). Кортежи не изменяются, поэтому их можно хэшировать.

Комментарии:

1. Большое спасибо за ваш ответ! Я попробовал команду «df[[isinstance…», и результатом является длина всего кадра данных (поэтому все значения кажутся «списком»). Поэтому я попытался превратить весь столбец в кортеж. Но следующий код выдает ту же ошибку типа, что и выше (тип без хэша: «список»): «ПЕРВАЯ СТРОКА: df.country_mentions_en = кортеж(df.country_mentions_en), ВТОРАЯ СТРОКА: df.country_mentions_en.уникальный()». У вас есть идея, как поступить вместо этого?

2. Каждый элемент в столбце выглядит как список, поэтому вам нужно изменить их на кортежи по одному за раз. Измените первую строку на: df.country_mentions_en = [tuple(l) for l in df.country_mentions_en.values]

3. Кроме того, если вам нужны уникальные элементы списка в списках, вам необходимо их распаковать. НАПРИМЕР, если в вашем столбце два кортежа: ('A', 'B') и ('B', 'C') , то вывод .unique() будет ('A', 'B'), ('B', 'C') . Но если вы хотите 'A', 'B', 'C' получить выходные данные, один из подходов состоит в том, чтобы использовать chain функцию from itertools для их распаковки и структуру set данных для получения уникальных значений: set(chain(*df.column_name))