Pandas никуда не денется: почему он по-прежнему остается моим основным инструментом для обработки данных.
Возможно, миллиарды строк — это исключение, но во всех остальных случаях Pandas остается очень надежным инструментом.
Делиться

Когда я только начинал изучать науку о данных в 2020 году, Pandas был одним из самых популярных инструментов. Хотя новые инструменты сосредоточены на устранении недостатков Pandas в обработке очень больших наборов данных, я по-прежнему использую Pandas для многих задач очистки, обработки и анализа данных. Да, Pandas доставляет мне немало хлопот при работе с миллиардами строк, но его определенно более чем достаточно для работы с любыми меньшими объемами данных.
Я вижу, что Pandas будет использоваться не только для проектирования электронных схем или в ноутбуках, но и в производственных системах.
В этой статье я рассмотрю некоторые операции по очистке и обработке данных, чтобы продемонстрировать возможности Pandas.
Начнём с набора данных, который содержит артикулы товаров (SKU) и ответы API поиска для этих артикулов.
import pandas as pd search_results = pd.read_csv("search_results.csv") search_results.head()

В результате поиска отображается список словарей, который выглядит следующим образом:
search_results.loc[0, "search_result"] "[{'my_id': 'HBCV00007F5Y2B', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00007UPQBM', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00008I29IH', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00006U3ZYB', 'distance': 0.8961254358291626, 'entity': {}}, {'my_id': 'HBCV0000AFA4H6', 'distance': 0.8702399730682373, 'entity': {}}, {'my_id': 'HBCV00009CDGD4', 'distance': 0.86175537109375, 'entity': {}}, {'my_id': 'HBCV000046336T', 'distance': 0.8594968318939209, 'entity': {}}, {'my_id': 'HBCV00009QDZRT', 'distance': 0.8572311997413635, 'entity': {}}, {'my_id': 'HBCV00008E11P3', 'distance': 0.8553324937820435, 'entity': {}}, {'my_id': 'HBV00000C4IY6', 'distance': 0.8539167642593384, 'entity': {}}] ... and 5 entities remaining"
Как видно из результата, это не корректный список в формате словаря из-за последней части («… и осталось 5 сущностей»). Кроме того, он сохранен как одна строка.
Для более эффективного использования нам необходимо преобразовать его в корректный список словарей. Следующая строка кода удаляет последнюю часть, разделяя строку по символу «…» и используя первое разделение.
search_results.loc[0, "search_result"].split("...")[0].strip()
Однако на выходе по-прежнему получается одна строка. Мы можем использовать встроенный модуль `ast` в Python для преобразования её в список:
import ast res = ast.literal_eval(search_results.loc[0, "search_result"].split("...")[0].strip()) res [{'my_id': 'HBCV00007F5Y2B', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00007UPQBM', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00008I29IH', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00006U3ZYB', 'distance': 0.8961254358291626, 'entity': {}}, {'my_id': 'HBCV0000AFA4H6', 'distance': 0.8702399730682373, 'entity': {}}, {'my_id': 'HBCV00009CDGD4', 'distance': 0.86175537109375, 'entity': {}}, {'my_id': 'HBCV000046336T', 'distance': 0.8594968318939209, 'entity': {}}, {'my_id': 'HBCV00009QDZRT', 'distance': 0.8572311997413635, 'entity': {}}, {'my_id': 'HBCV00008E11P3', 'distance': 0.8553324937820435, 'entity': {}}, {'my_id': 'HBV00000C4IY6', 'distance': 0.8539167642593384, 'entity': {}}]
Теперь у нас есть результаты поиска в виде корректного списка словарей. Это касалось только одной строки. Нам нужно применить ту же операцию ко всем артикулам (т.е. ко всему столбцу артикулов).
Один из вариантов — пройтись по всем строкам в цикле for и выполнить ту же операцию. Однако это не лучший вариант. По возможности следует отдавать предпочтение векторизованным операциям. Векторизованная операция, по сути, означает выполнение кода для всех строк одновременно.
При обработке одной строки я использовал разделение, чтобы удалить последнюю часть строки, но это не сработало в векторизованной операции. Более надежным вариантом, по-видимому, является использование регулярных выражений.
search_results.loc[:, 'search_result'] = search_results['search_result'].str.replace(r"....*", "", regex=True).str.strip()
Этот код выбирает «…» и всё, что идёт после него, и заменяет это пустым местом. Другими словами, он удаляет часть «… и осталось 5 сущностей».
Теперь все строки в столбце результатов поиска представлены в виде корректного списка словарей.
search_results.loc[10, "search_result"] "[{'my_id': 'HBCV00007F5Y2B', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00007UPQBM', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00008I29IH', 'distance': 1.0, 'entity': {}}, {'my_id': 'HBCV00006U3ZYB', 'distance': 0.8961254358291626, 'entity': {}}, {'my_id': 'HBCV0000AFA4H6', 'distance': 0.8702399730682373, 'entity': {}}, {'my_id': 'HBCV00009CDGD4', 'distance': 0.86175537109375, 'entity': {}}, {'my_id': 'HBCV000046336T', 'distance': 0.8594968318939209, 'entity': {}}, {'my_id': 'HBCV00009QDZRT', 'distance': 0.8572311997413635, 'entity': {}}, {'my_id': 'HBCV00008E11P3', 'distance': 0.8553324937820435, 'entity': {}}, {'my_id': 'HBV00000C4IY6', 'distance': 0.8539167642593384, 'entity': {}}]"
Они по-прежнему сохранены как строка, но я могу легко преобразовать их в список с помощью модуля ast, что я и сделаю на следующем шаге.
Меня интересуют артикулы товаров (SKU), отображаемые в результатах поиска. Я создам новый столбец, извлекая артикулы из словарей. Я смогу получить к ним доступ, используя ключ «my_id» словаря.
Эта операция состоит из 3 частей:
- Преобразуйте строку результатов поиска в список, используя функцию literal_eval.
- Извлеките артикул (SKU) из ключа my_id словаря.
- Используйте для этого генератор списков (list comply), чтобы получить артикулы (SKU) из всех словарей в списке.
Все эти операции можно выполнить, применив лямбда-функцию ко всем строкам следующим образом:
search_results.loc[:, "result_skus"] = search_results["search_result"].apply(lambda x: [item['my_id'] for item in ast.literal_eval(x)]) search_results.head()

Каждая строка в столбце result_skus содержит список из 10 артикулов (SKU). Допустим, мне нужно разместить эти 10 артикулов в разных строках. Для каждой строки в столбце sku будет создано 10 строк из списка в столбце result_skus. В Pandas это можно сделать очень просто — с помощью функции explode.
data = search_results[["sku", "result_skus"]].explode("result_skus", ignore_index=True) data.head()

Мы создали новый датафрейм со столбцами sku и result_skus. На рисунке ниже показано, что делает функция explode:

Рассмотрим обратную ситуацию. У нас есть датафрейм, как показано выше, но мы хотим отобразить все результаты для определенного артикула в одной строке.
Мы можем использовать функцию groupby для группировки строк по артикулу (sku), а затем применить функцию list к столбцу result_skus:
new_data = data.groupby("sku", as_index=False)["result_skus"].apply(list) new_data.head()
Это вернет нас к предыдущему шагу:

Используя функцию explode, мы создали датафрейм с отдельной строкой для каждого артикула в столбце result_skus. А что, если нам нужно разделить их на разные столбцы, а не на строки?
Один из вариантов — применить функцию pd.Series к столбцу result_skus и объединить полученные столбцы с исходным датафреймом.
new_cols = new_data["result_skus"].apply(pd.Series) new_data = pd.concat([new_data, new_cols], axis=1) new_data.head()

В столбцах с 0 по 9 содержатся 10 артикулов (SKU) из столбца result_skus. Данный код, использующий функцию apply, не является векторизованной операцией.
У нас есть еще один вариант, который является векторизованным и намного быстрее.
new_cols = pd.DataFrame(new_data["result_skus"].tolist()) new_data = pd.concat([new_data, new_cols], axis=1)
Этот код позволит получить тот же датафрейм, что и выше, но гораздо быстрее.
Я продемонстрировал типичную задачу очистки и обработки данных, с которой может столкнуться специалист по анализу данных в своей работе. Я работаю в этой области более 5 лет, и Pandas всегда был достаточен для решения моих задач, за исключением случаев работы с очень большими наборами данных (например, миллиардами строк).
Инструменты, лучше подходящие для работы с такими большими наборами данных, имеют синтаксис, схожий с Pandas. Например, PySpark представляет собой нечто среднее между Pandas и SQL. Polars очень похож на Pandas по синтаксису. Таким образом, изучение и практика работы с Pandas по-прежнему являются очень ценным навыком для любого, кто работает в области анализа данных и искусственного интеллекта.
Спасибо за прочтение.
Сонер Йылдырым Посмотреть все магазины Сонер Йылдырым
Источник: towardsdatascience.com

Добавить комментарий
Для отправки комментария вам необходимо авторизоваться.