DevGang
Авторизоваться

В 4 раза быстрее операции Pandas с минимальным изменением кода

Одним из основных ограничений Pandas является то, что он может быть медленным при работе с большими наборами данных, особенно при выполнении сложных операций. Это может расстроить специалистов по обработке данных и аналитиков, которым в своей работе необходимо обрабатывать и анализировать большие наборы данных.

Есть несколько способов решить эту проблему. Одним из способов является использование параллельной обработки.

Введите Pandarallel

Pandarallel — это библиотека Python с открытым исходным кодом, которая обеспечивает параллельное выполнение операций Pandas с использованием нескольких CPU, что приводит к значительному ускорению.

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

Достижение значительного ускорения с Pandarallel

Вы можете сами убедиться, насколько быстрее pandas apply по сравнению с parallel_apply от pandarallel. Здесь pandarallel распределил нагрузку по 4 ядрам.

Источник: документация Pandarallel.
Источник: документация Pandarallel.

Более конкретно, ускорение видно из диаграммы ниже.

4х ускорение. Источник: документация Pandarallel.
4х ускорение. Источник: документация Pandarallel.

Начало работы с Pandarallel

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

pip install pandarallel

Вы можете импортировать пакет в свой код Python и инициализировать его.

from pandarallel import pandarallel

# Initialize pandarallel
pandarallel.initialize()

Как только это будет сделано, вы можете использовать следующие предоставленные функции.

Пример кода использования Pandarallel

Давайте сначала создадим фиктивный фрейм данных, содержащий покупки на сайте электронной коммерции. Каждая строка соответствует покупке одного продукта в каждую дату. Столбцы:

  • date
  • product_id
  • quantity
import pandas as pd
import numpy as np

# Generate a dataframe.
df = pd.DataFrame()

# Generate a column of random dates from 2019-01-01 to 2019-12-31
df['date'] = pd.date_range('2019-01-01', '2019-12-31', periods=10000)

# Seed numpy random 
np.random.seed(0)

# Generate a column of random product_id from 1 to 5
df['product_id'] = np.random.randint(1, 5, 10000)

# Generate a column of quantity bought from 1 to 100
df['quantity'] = np.random.randint(1, 100, 10000)

Вот первые пять строк.

|    | date                | product_id | quantity |
|---:|:--------------------|-----------:|---------:|
|  0 | 2019-01-01 00:00:00 |          1 |       10 |
|  1 | 2019-01-01 00:52:25 |          4 |       36 |
|  2 | 2019-01-01 01:44:50 |          2 |       79 |
|  3 | 2019-01-01 02:37:15 |          1 |       33 |
|  4 | 2019-01-01 03:29:41 |          4 |       59 |

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

from pandarallel import pandarallel

# Initialize pandarallel
pandarallel.initialize()

Обратите внимание, что у вас есть несколько вариантов инициализации pandarallel.

# Initialize pandarallel with a progress bar
pandarallel.initialize(progress_bar = True)

# Set the number of workers for parallelization. 
# By default, this is the number of cores available.
pandarallel.initialize(nb_workers = 4) 

# Initialize pandarallel with all logs printed.
# By default, this is 2 (display all logs), while 0 display n ologs.
pandarallel.initialize(verbose = 2)

Используйте parallel_apply для применения функции к столбцу

Давайте извлечем месяц из столбца date. Например, январь — это 1, а февраль — это 2. Для этого мы можем использовать функцию parallel_apply.

# Group date by month using parallel_apply
df['month'] = df['date'].parallel_apply(lambda x: x.month)

|    | date                | product_id | quantity | month |
|---:|:--------------------|-----------:|---------:|------:|
|  0 | 2019-01-01 00:00:00 |          1 |       10 |     1 |
|  1 | 2019-01-01 00:52:25 |          4 |       36 |     1 |
|  2 | 2019-01-01 01:44:50 |          2 |       79 |     1 |
|  3 | 2019-01-01 02:37:15 |          1 |       33 |     1 |
|  4 | 2019-01-01 03:29:41 |          4 |       59 |     1 |

Мы также можем использовать функцию lambda в parallel_apply. Давайте назначим цену для каждого product_id. Затем мы можем рассчитать revenue для каждой транзакции.

# Assign a price to each product_id 
df['price'] = df['product_id'].parallel_apply(lambda x: 5.59 if x == 1 else 1.29 if x == 2 else 3.49 if x == 3 else 6.99)

# Get the revenue
df['revenue'] = df.parallel_apply(lambda x: x['quantity']* x['price'], axis=1)
|   | date                |product_id |quantity |month |price |revenue |
|--:|:--------------------|----------:|--------:|-----:|-----:|-------:|
| 0 | 2019-01-01 00:00:00 |         1 |      10 |    1 | 5.59 |  55.9  |
| 1 | 2019-01-01 00:52:25 |         4 |      36 |    1 | 6.99 | 251.64 |
| 2 | 2019-01-01 01:44:50 |         2 |      79 |    1 | 1.29 | 101.91 |
| 3 | 2019-01-01 02:37:15 |         1 |      33 |    1 | 5.59 | 184.47 |
| 4 | 2019-01-01 03:29:41 |         4 |      59 |    1 | 6.99 | 412.41 |

Используйте parallel_apply для применения функции к группе

Вы также можете сгруппировать по определенному столбцу перед применением parallel_apply. В приведенном ниже примере мы можем сгруппировать по определенному month и получить сумму revenue за каждый месяц.

# Get the sum of revenue for every month
monthly_revenue_df = df.groupby('month').parallel_apply(np.sum)[['revenue']]

Еще лучше, мы можем вычислить скользящую сумму, используя parallel_apply.

# Generate 3-month rolling revenue by month
monthly_revenue_df['rolling_3_mth_rev'] = monthly_revenue_df['revenue'].rolling(3, min_periods=3).parallel_apply(np.sum)
|   month |   revenue |   rolling_3_mth_rev |
|--------:|----------:|--------------------:|
|       1 |    188268 |                 nan |
|       2 |    164251 |                 nan |
|       3 |    176198 |              528717 |
|       4 |    178021 |              518470 |
|       5 |    188940 |              543159 |

Используйте parallel_applymap для применения функции ко всему фрейму данных

Если есть функция, которую можно применить ко всему фрейму данных, applymap — идеальная функция. Например, чтобы преобразовать все элементы df в строку, мы можем использовать эту функцию.

# Convert every element of df to a string
df.parallel_applymap(lambda x: str(x))

Полный код

import pandas as pd
import numpy as np
from pandarallel import pandarallel

# Generate a dataframe.
df = pd.DataFrame()

# Generate a column of random dates from 2019-01-01 to 2019-12-31
df['date'] = pd.date_range('2019-01-01', '2019-12-31', periods=10000)

# Seed numpy random 
np.random.seed(0)

# Generate a column of random product_id from 1 to 5
df['product_id'] = np.random.randint(1, 5, 10000)

# Generate a column of quantity bought from 1 to 100
df['quantity'] = np.random.randint(1, 100, 10000)

# Initialize pandarallel
pandarallel.initialize()

# Group date by month using parallel_apply
df['month'] = df['date'].parallel_apply(lambda x: x.month)

# Assign a price to each product_id 
df['price'] = df['product_id'].parallel_apply(lambda x: 5.59 if x == 1 else 1.29 if x == 2 else 3.49 if x == 3 else 6.99)

# Get the revenue
df['revenue'] = df.parallel_apply(lambda x: x['quantity']* x['price'], axis=1)

# print(df.head().to_markdown())

# Get the sum of revenue for every month
monthly_revenue_df = df.groupby('month').parallel_apply(np.sum)[['revenue']]

# Generate 3-month rolling revenue by month
monthly_revenue_df['rolling_3_mth_rev'] = monthly_revenue_df['revenue'].rolling(3, min_periods=3).parallel_apply(np.sum)

# print(monthly_revenue_df.head().to_markdown())

Когда НЕ использовать Pandarallel

Мы не должны использовать Pandarallel, когда данные не помещаются в память. В этом случае используйте spark, pyspark или vaex.

Тем не менее, есть несколько вариантов использования pandarallel, которые принесут пользу ученым, работающим с данными. Хватит ждать операций с пандами и распараллелить их.

#Python #Pandas #Machine Learning
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

В этом месте могла бы быть ваша реклама

Разместить рекламу