Pandas apply / map / applymap

apply, map и applymap — три основные функции в Pandas для преобразования данных. Они позволяют выполнять гибкие поэлементные или пакетные операции над DataFrame или Series.


Series.map

mapЭто метод Series, используемый для преобразования каждого элемента в Series.

Базовое использование

Пример

import pandas as pd

# Создание Series
s = pd.Series([1, 2, 3, 4, 5])

print("Исходные данные:")
print(s)
print()

# Использование функции
print("Каждый элемент * 2:")
print(s.map(lambda x: x * 2))
print()

# Использование сопоставления по словарю
mapping = {1: "A", 2: "B", 3: "C", 4: "D", 5: "E"}
print("Использование сопоставления по словарю:")
print(s.map(mapping))
print()

# Использование сопоставления Series
mapping_series = pd.Series(["A", "B", "C", "D", "E"], index=[1, 2, 3, 4, 5])
print("Использование сопоставления Series:")
print(s.map(mapping_series))

Обработка пропущенных значений

Пример

import pandas as pd
import numpy as np

s = pd.Series([1, 2, np.nan, 4, 5])

print("Содержит NaN:")
print(s)
print()

# map пропускает NaN по умолчанию
print("Обработка map (пропускает NaN):")
print(s.map(lambda x: x * 2 if pd.notna(x) else -1))

DataFrame.applymap

applymapЭто метод DataFrame, который применяет функцию к каждому элементу по одному (Примечание: Pandas 2.0+ рекомендует использоватьDataFrame.mapвместо этого).

Пример

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, 3],
    "B": [4, 5, 6],
    "C": [7, 8, 9]
})

print("Исходные данные:")
print(df)
print()

# Умножить каждый элемент на 2
print("Каждый элемент * 2:")
print(df.applymap(lambda x: x * 2))
print()

# Сохранить 2 десятичных знака
print("Сохранить 2 десятичных знака:")
print(df.applymap(lambda x: round(x, 2)))

applymap выполняет поэлементные операции и может быть медленным для больших данных. Если вам нужно работать только с числовыми столбцами, рассмотрите использование векторизованных операций или apply с параметром axis.


DataFrame.apply

applyЭто самый гибкий метод, позволяющий применять функции вдоль оси.

Применение по столбцу

Пример

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, 3, 4, 5],
    "B": [10, 20, 30, 40, 50],
    "C": [100, 200, 300, 400, 500]
})

print("Исходные данные:")
print(df)
print()

# По умолчанию axis=0, применять по столбцу
print("Сумма по столбцу:")
print(df.apply(sum))
print()

print("Максимум по столбцу:")
print(df.apply(max))

Применение по строкам

Пример

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, 3],
    "B": [10, 20, 30],
    "C": [100, 200, 300]
})

print("Исходные данные:")
print(df)
print()

# axis=1, применить по строкам
print("Сумма по строке:")
print(df.apply(sum, axis=1))
print()

# Максимум - минимум по строке
print("Размах по строке:")
print(df.apply(lambda x: x.max() - x.min(), axis=1))

Использование aggfunc для агрегации

Пример

import pandas as pd
import numpy as np

df = pd.DataFrame({
    "A": [1, 2, 3],
    "B": [10, 20, 30]
})

# Применить несколько функций сразу
print("Сумма и среднее одновременно:")
print(df.apply([sum, np.mean]))
print()

# Возврат нескольких значений
result = df.apply(lambda x: pd.Series({
    "sum": x.sum(),
    "mean": x.mean(),
    "max": x.max()
}, index=["sum", "mean", "max"]))

print("Возврат нескольких значений:")
print(result)

Series.apply

Series также может использовать apply, который похож на map, но более гибкий.

Пример

import pandas as pd
import numpy as np

s = pd.Series([1, 4, 9, 16, 25])

print("Исходные данные:")
print(s)
print()

# Квадратный корень
print("Квадратный корень:")
print(s.apply(np.sqrt))
print()

# Условный возврат
print("Проверка условия:")
print(s.apply(lambda x: "большой" if x > 10 else "маленький"))

Сравнение производительности

Пример

import pandas as pd
import numpy as np
import time

# Создание большого набора данных
n = 100000
s = pd.Series(np.random.randn(n))

# Тест map vs apply
func = lambda x: x * 2 + 1

start = time.time()
result1 = s.map(func)
map_time = time.time() - start

start = time.time()
result2 = s.apply(func)
apply_time = time.time() - start

# Векторизованный (самый быстрый)
start = time.time()
result3 = s * 2 + 1
vec_time = time.time() - start

print(f"время map: {map_time:.4f}s")
print(f"время apply: {apply_time:.4f}s")
print(f"время векторизации: {vec_time:.4f}s")

print("\nВывод: отдавайте предпочтение векторизованным операциям для максимальной производительности")

Практика: преобразование данных

Пример

import pandas as pd
import numpy as np

# Создать пример DataFrame
df = pd.DataFrame({
    "Имя": ["Чжан Сань", "Ли Сы", "Ван У", "Чжао Лю"],
    "Возраст": [25, 30, 28, 35],
    "Зарплата": [12000, 15000, 11000, 18000],
    "Отдел": ["Технологии", "Продажи", "Технологии", "Операции"]
})

print("Исходные данные:")
print(df)
print()

# Использовать apply для построчных вычислений
def calculate(row):
    """Вычислить годовой доход и зарплату после вычета налогов"""
    annual = row["Зарплата"] * 12
    tax = annual * 0.1 if annual > 120000 else annual * 0.05
    after_tax = annual - tax
    return pd.Series({
        "Годовая зарплата": annual,
        "Tax": tax,
        "After tax": after_tax
    })

result = df.apply(calculate, axis=1)
df_result = pd.concat([df, result], axis=1)

print("Результаты вычислений:")
print(df_result)

Выбор из трёх

Метод Объект применения Сценарий Производительность
map Серия Поэлементное преобразование, сопоставление по словарю Высокая
applymap DataFrame Поэлементное преобразование (нечисловые столбцы) Медленная
apply Series/DataFrame Агрегация по строкам/столбцам, пользовательские функции Средняя

Когда доступны векторизованные операции (с непосредственным использованием операторов), не используйте apply/map; когда доступен map, не используйте apply.

Другие расширения