Pandas apply / map / applymap
apply, map и applymap — три основные функции в Pandas для преобразования данных. Они позволяют выполнять гибкие поэлементные или пакетные операции над DataFrame или Series.
Series.map
mapЭто метод Series, используемый для преобразования каждого элемента в Series.
Базовое использование
Пример
# Создание 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 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 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 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 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 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 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 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 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.