Оптимизация производительности Pandas

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

Чтобы повысить эффективность Pandas при обработке крупномасштабных данных, необходимо понимать и применять некоторые методы оптимизации производительности.

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

Ниже мы подробно рассмотрим несколько методов оптимизации производительности Pandas.


Используйте подходящие типы данных

Типы данных в Pandas (dtype) напрямую влияют на использование памяти и скорость вычислений. Выбор подходящих типов данных может значительно уменьшить использование памяти и ускорить вычисления.

1. Используйте подходящие числовые типы

Стандартный числовой тип в Pandas —int64иfloat64, но для большинства данных это может привести к излишнему расходу памяти. Можно использовать меньшие типы, напримерint8, int16, float32и т. д.

Метод Описание
astype() Используется для преобразования типа данных столбца
downcast Понизить тип данных, например, преобразоватьint64с понижением доint32илиint16

Пример

import pandas as pd

# Пример данных
df = pd.DataFrame({'A': [100, 200, 300, 400], 'B': [1000, 2000, 3000, 4000]})

# Преобразовать типы данных столбцов в меньшие типы данных
df['A'] = df['A'].astype('int16')
df['B'] = df['B'].astype('int32')

print(df.dtypes)

Вывод:

A    int16
B    int32
dtype: object

2. Используйте для символьных данныхcategorytype

Для строковых столбцов с повторяющимися значениями можно использоватьcategoryтип для сокращения потребления памяти.categoryЭтот тип хранит в памяти целочисленные индексы, а не сами строки.

Пример

# Пример данных
df = pd.DataFrame({'Category': ['A', 'B', 'A', 'C', 'B', 'A']})

# Используйте тип category
df['Category'] = df['Category'].astype('category')

print(df.dtypes)

Вывод:

Category    category
dtype: object

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

Одно из главных преимуществ Pandas — возможность использовать векторизованные операции для быстрых пакетных вычислений. В Pandas старайтесь избегать нативных циклов Python и использовать встроенные функции Pandas, которые могут задействовать внутренние оптимизации для быстрых вычислений.

Пример

import pandas as pd

# Пример данных
df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]})

# Используйте векторизованные операции, избегайте циклов
df['C'] = df['A'] + df['B']
print(df)

Вывод:

   A  B  C
0  1  5  6
1  2  6  8
2  3  7  10
3  4  8  12

По сравнению с обработкой данных строка за строкой использование векторизованных операций Pandas может значительно повысить скорость вычислений.


3. Используйтеapply()иapplymap()Оптимизация

Pandas предоставляетapply()иapplymap()методы, которые позволяют применять функции к строкам или столбцам в DataFrame и более эффективны, чем циклы.

Пример

# Используйте apply() для применения пользовательской функции к столбцу
df['D'] = df['A'].apply(lambda x: x ** 2)
print(df)

Вывод:

   A  B   C   D
0  1  5   6   1
1  2  6   8   4
2  3  7  10   9
3  4  8  12  16

apply()Он подходит для обработки одномерных данных,applymap()тогда как он применяет функцию к каждому элементу в DataFrame и подходит для двумерных данных.

Пример

# Используйте applymap() для применения функции к каждому элементу DataFrame
df = df.applymap(lambda x: x * 10)
print(df)

Вывод:

    A   B   C   D
0  10  50  60  10
1  20  60  80  40
2  30  70 100  90
3  40  80 120 160

Используйте подходящие индексы

Индексы Pandas могут повысить скорость поиска данных, особенно когда требуется множество поисков или объединений данных, и индексы могут значительно повысить эффективность. Для больших наборов данных обеспечение подходящих индексов и сокращение ненужных операций с индексами может повысить производительность.

Пример

# Создайте индекс и выполните поиск
df = pd.DataFrame({'A': [1, 2, 3, 4], 'B': [5, 6, 7, 8]})
df.set_index('A', inplace=True)

# Быстрый поиск по индексу
print(df.loc[2])

Вывод:

B    6
Name: 2, dtype: int64

Загружайте большие наборы данных частями

Когда набор данных слишком велик, загрузка всего набора данных может потреблять много памяти и даже привести к переполнению памяти. В этом случае можно снизить нагрузку на память, считывая данные частями.

Pandas предоставляетchunksizeпараметр, который позволяет загружать данные частями при чтении файлов CSV или Excel.

Пример

# Чтение CSV-файла частями
chunksize = 10000
for chunk in pd.read_csv('large_file.csv', chunksize=chunksize):
    # Обработать каждый фрагмент данных
    process(chunk)

Dask и Vaex — это две библиотеки, которые могут обрабатывать наборы данных, размер которых превышает объём памяти. Они совместимы с Pandas, поддерживают многопоточность и распределённые вычисления, а также могут эффективно обрабатывать очень большие наборы данных.

Пример

import dask.dataframe as dd

# Использовать Dask для чтения большого набора данных
df = dd.read_csv('large_file.csv')

# Выполнить вычислительные операции
df.groupby('category').sum().compute()

ЧерезnumbaУскорение вычислений

numba— это JIT-компилятор, который может ускорить код Python. За счёт ускорения кода для обработки данных можно значительно повысить производительность. Особенно для вычислительно интенсивных операций, таких как циклы и численные расчёты,numbaэто может значительно увеличить скорость.

Пример

import numba
import pandas as pd

# Пример функции
@numba.jit
def calculate_square(x):
    return x ** 2

# Использовать numba для ускорения вычислений
df = pd.DataFrame({'A': [1, 2, 3, 4]})
df['B'] = df['A'].apply(calculate_square)
print(df)

Избегайте цепочного присваивания

Цепочное присваивание — одна из распространённых ловушек производительности в Pandas. Оно может вызывать ненужные побочные эффекты и обычно замедляет выполнение. Лучше всего использовать явное присваивание и избегать множественных присваиваний в одной строке.

Пример

# Цепочное присваивание: может вызывать предупреждения и влиять на производительность
df['A'][df['A'] > 2] = 0

# Правильный способ присваивания:
df.loc[df['A'] > 2, 'A'] = 0

Оптимизируйте операции слияния

При слиянии нескольких DataFrame используйтеmerge()илиconcat()нужно уделить внимание оптимизации операции слияния, особенно при обработке больших наборов данных. Можно использоватьonиhowпараметр, чтобы явно указать метод слияния и избежать ненужных вычислений.

Пример

import pandas as pd

# Используйте подходящий метод слияния
df1 = pd.DataFrame({'ID': [1, 2, 3], 'Value': ['A', 'B', 'C']})
df2 = pd.DataFrame({'ID': [1, 2, 3], 'Value': ['X', 'Y', 'Z']})

# Используйте параметр on для слияния
merged_df = pd.merge(df1, df2, on='ID', how='inner')
print(merged_df)

Вывод:

   ID Value_x Value_y
0   1       A       X
1   2       B       Y
2   3       C       Z
Другие расширения