6 трюков в Pandas, которые сэкономят время
Мария Жарова | t.me/data_easyКогда только начинаешь работать с данными, кажется, что всё сводится к .groupby(), for-циклам и магическому df[df["col"] == "val"]. Но потом приходит понимание: эффективность — в деталях.
Вот 6 трюков в Pandas, которые сэкономят вам часы рутины и сделают код чище, быстрее и понятнее. Некоторые почти незаметные, но очень мощные. Поехали!
1. map() и apply() — когда и что?
Для одного столбца всегда выбирайте map() — он быстрее и проще. Особенно если используете словарь или простую функцию:
df["gender_code"] = df["gender"].map({"male": 0, "female": 1}) df["name_len"] = df["name"].map(len)
Почему это работает быстрее, чем apply()?
Потому что map() оптимизирован для Series: он напрямую применяет функцию к каждому элементу, без лишних обёрток и лишнего контроля.
Но! Если вам нужно работать с несколькими колонками одновременно, без apply() не обойтись:
df["full_name"] = df.apply(lambda row: f"{row['first']} {row['last']}", axis=1)
2. query() — фильтрация как в SQL
Любителям SQL этот синтаксис точно понравится:
df.query("age > 25 and city == 'Moscow'")
Выглядит лучше, читается легче, особенно когда много условий.
Под капотом это тот же фильтр, что и df[(df["age"] > 25) & (df["city"] == "Moscow")],
по производительности почти одинаково, но писать и читать query() иногда гораздо приятнее:)
Внутри можно также использовать переменные:
age_limit = 25
df.query("age > @age_limit")
3. isin() — фильтрация по списку значений
К слову, если хотите отобрать строки, где значения для фильтрации содержатся в списке, isin() вам в помощь:
df[df["category"].isin(["books", "electronics"])]
Инверсия (not in) делается просто:
df[~df["user_id"].isin(blacklist)]
Читается лучше, чем громоздкие цепочки | и ==.
4. assign() — новые столбцы в цепочках
Иногда хочется, чтобы код читалcя плавно, без лишних отвлекающих строк и вкраплений вроде df["col"] = ...посреди пайплайна. В этом может помочь assign(), сравните код до:
df["total"] = df["price"] * df["quantity"] df = df[df["total"] > 1000]
и после:
df = (
df
.assign(total=lambda x: x["price"] * x["quantity"])
.query("total > 1000")
)
Красота, да и ничего не потеряется.
5. pipe() — для тех, кто любит пайплайны
Когда сама цепочка трансформаций становится длинной, хочется сохранить плавный поток операций без вложенных функций и промежуточных переменных. Тут на помощь приходит .pipe().
Он передаёт датафрейм как первый аргумент в функцию. Это удобно, если приходится писать кастомные функции для обработки данных, но хочется использовать их прямо в цепочке:
def clean_text(df): df["text"] = df["text"].str.lower() return df def add_features(df, some_param): df["length"] = df["text"].str.len() * some_param return df df = ( df .pipe(clean_text) .pipe(add_features, some_param=10) )
Полезная вещь, если строите многоступенчатые преобразования.
6. nlargest() и nsmallest() — топ по колонке
Вместо этого:
df.sort_values("revenue", ascending=False).head(5)
можно написать так:
df.nlargest(5, "revenue")
а если нужны значения с другого отсортированного "конца", то так тоже можно:
df.nsmallest(3, "error_rate")
Каждый из этих методов поначалу кажется просто «альтернативным синтаксисом». Но вместе они превращают Pandas-код из «скрипта для себя» в читаемый, поддерживаемый и быстрый пайплайн⚡.