Промты для оптимизации DataFrame: как LLM переводит тяжёлый Pandas в Polars и объясняет утечки памяти

Каждый аналитик данных рано или поздно сталкивается с ситуацией, когда привычный Pandas начинает «есть» гигабайты памяти, а время выполнения groupby или merge измеряется минутами. Переход на Polars обещает ускорение, но требует переписывания кода и понимания новых API. LLM могут стать мостом между этими мирами — если знать, как правильно формулировать запросы.

В этой подборке — 12 промтов для практической работы с табличными данными. Мы разберём, как заставить модель писать корректные цепочки операций, переводить тяжёлый Pandas-код на Polars, объяснять утечки памяти и предлагать векторизацию вместо apply. Каждый промт сопровождается примером результата и комментарием о том, где LLM ошибается и что нужно перепроверять.

Базовые промты: очистка и подготовка данных

1. Генерация цепочки очистки с обработкой пропусков

Задача: быстро получить код для типовой очистки датасета с пропусками, выбросами и дубликатами.

Промт:

Ты — эксперт по Pandas. Напиши функцию clean_dataframe(df), которая:
1. Удаляет полные дубликаты.
2. Для числовых колонок заполняет пропуски медианой, для категориальных — модой.
3. Обрезает выбросы по правилу IQR (1.5 * IQR) для всех числовых колонок.
4. Возвращает очищенный DataFrame и словарь с количеством удалённых/заполненных значений.
Добавь комментарии, объясняющие каждый шаг.

Пример результата (сокращённо):

import pandas as pd
import numpy as np

def clean_dataframe(df):
    report = {}
    initial_len = len(df)
    df = df.drop_duplicates()
    report['duplicates_removed'] = initial_len - len(df)

    for col in df.select_dtypes(include=np.number).columns:
        median = df[col].median()
        df[col] = df[col].fillna(median)
        q1 = df[col].quantile(0.25)
        q3 = df[col].quantile(0.75)
        iqr = q3 - q1
        lower = q1 - 1.5 * iqr
        upper = q3 + 1.5 * iqr
        df[col] = df[col].clip(lower, upper)

    for col in df.select_dtypes(include='object').columns:
        mode = df[col].mode()[0]
        df[col] = df[col].fillna(mode)

    return df, report

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

Что проверить первым Убедитесь, что LLM не использует устаревший метод fillna(method='ffill') — в новых версиях Pandas он вызывает предупреждение. Правильно: df.ffill().

2. Промт для merge с проверкой типов ключей

Задача: избежать ошибки слияния из-за разных типов ключевых колонок.

Промт:

Напиши код для merge двух DataFrame по колонке 'user_id'. Перед слиянием проверь, что типы колонок совпадают. Если нет — приведи оба к строковому типу и выведи предупреждение. После слияния выведи количество строк и проверь, что не появилось дубликатов ключей (если в правом датафрейме ключи уникальны).

Пример результата:

def safe_merge(left, right, on='user_id'):
    if left[on].dtype != right[on].dtype:
        print(f"Типы не совпадают: {left[on].dtype} vs {right[on].dtype}. Приводим к строке.")
        left[on] = left[on].astype(str)
        right[on] = right[on].astype(str)
    merged = left.merge(right, on=on, how='left', validate='many_to_one')
    print(f"Строк после merge: {len(merged)}")
    return merged

Параметр validate помогает отловить неожиданное размножение строк. LLM часто забывает про него, поэтому указывайте явно.

Продвинутые промты: группировки, временные ряды и векторизация

3. Сложный groupby с несколькими агрегациями

Задача: построить отчёт с разными агрегатами для разных колонок.

Промт:

Дан DataFrame с колонками: region, product, sales, quantity, date. Напиши код, который группирует по region и product и считает:
- сумму sales,
- среднее quantity,
- количество уникальных дат.
Используй именованную агрегацию Pandas. Отсортируй результат по сумме sales по убыванию.

Пример результата:

result = (df.groupby(['region', 'product'])
          .agg(total_sales=('sales', 'sum'),
               avg_quantity=('quantity', 'mean'),
               unique_dates=('date', 'nunique'))
          .sort_values('total_sales', ascending=False)
          .reset_index())

Именованная агрегация появилась в Pandas 0.25 и считается стандартом. LLM может предложить устаревший синтаксис с словарём — проверяйте.

4. Resample для временных рядов с пропущенными датами

Задача: корректно агрегировать данные по неделям, учитывая пропуски.

Промт:

Есть DataFrame с колонкой date (тип datetime) и value. Напиши код, который:
1. Устанавливает date как индекс.
2. Ресемплирует по неделям ('W') и считает сумму value.
3. Заполняет пропущенные недели нулями.
4. Возвращает результат с индексом в исходном формате дат.

Пример результата:

df = df.set_index('date')
weekly = df.resample('W')['value'].sum().fillna(0)
weekly.index = weekly.index.strftime('%Y-%m-%d')

LLM иногда путает 'W' и 'W-MON' — уточняйте, что нужна неделя, заканчивающаяся в воскресенье (по умолчанию).

Ключевое различие Pandas resample по умолчанию использует закрытый интервал справа, а Polars group_by_dynamic — открытый. Это приводит к разным результатам на границах периодов.

5. Векторизация вместо apply

Задача: ускорить медленный apply, заменив его векторными операциями.

Промт:

У меня есть медленный код:
df['category'] = df['description'].apply(lambda x: 'A' if 'apple' in x.lower() else 'B')
Предложи векторизованную замену без apply. Объясни, почему это быстрее.

Пример результата:

df['category'] = np.where(df['description'].str.lower().str.contains('apple'), 'A', 'B')

Векторизация через строковые методы Pandas работает в разы быстрее, но требует, чтобы все значения были строками. Если есть пропуски, str.contains вернёт NaN — предусмотрите fillna(False).

6. Перевод Pandas-кода на Polars

Задача: автоматически конвертировать цепочку операций в Polars.

Промт:

Переведи следующий Pandas-код на Polars, сохранив логику:
result = df[df['value'] > 100].groupby('category')['value'].agg(['mean', 'count']).reset_index()

Пример результата:

import polars as pl
result = (df.filter(pl.col('value') > 100)
          .group_by('category')
          .agg([pl.col('value').mean().alias('mean'),
                pl.col('value').count().alias('count')])
          .sort('category'))

Polars не использует индексы, поэтому reset_index() не нужен. LLM может забыть про alias — проверяйте имена колонок.

Экспертные промты: отладка памяти и сложные сценарии

7. Диагностика утечки памяти

Задача: понять, почему скрипт потребляет много RAM.

Промт:

Мой Pandas-скрипт обрабатывает CSV на 2 ГБ и падает с MemoryError. Вот код:
[вставьте код]
Проанализируй, какие операции создают копии DataFrame, и предложи оптимизации: использование категориальных типов, чтение по частям (chunksize), удаление ненужных колонок.

Пример результата (фрагмент):

# Вместо полной загрузки:
df = pd.read_csv('big.csv', usecols=['col1', 'col2'], dtype={'col1': 'category'})
# Или чанками:
for chunk in pd.read_csv('big.csv', chunksize=100_000):
    process(chunk)

LLM часто предлагает del df и gc.collect(), но это не решает проблему копий. Ищите в ответе конкретные методы: astype('category'), pd.read_csv(..., low_memory=False).

Что проверить первым Убедитесь, что LLM не советует использовать df.memory_usage(deep=True) без пояснения — это ключевой инструмент для поиска тяжёлых колонок.

8. Сложный merge с асинхронными данными

Задача: объединить датафреймы с разной частотой (например, ежедневные продажи и ежемесячные маркетинговые бюджеты).

Промт:

Есть два DataFrame: sales (daily) и marketing (monthly). Нужно для каждой продажи подтянуть маркетинговый бюджет за соответствующий месяц. Напиши код, который создаёт колонку 'month' в обоих датафреймах и выполняет merge по этой колонке. Учти, что в marketing может не быть некоторых месяцев — заполни пропуски нулями.

Пример результата:

sales['month'] = sales['date'].dt.to_period('M')
marketing['month'] = marketing['date'].dt.to_period('M')
merged = sales.merge(marketing[['month', 'budget']], on='month', how='left')
merged['budget'] = merged['budget'].fillna(0)

LLM может предложить resample вместо merge — это работает, но менее эффективно при больших объёмах. Выбирайте решение осознанно.

9. Оптимизация groupby с помощью категориальных типов

Задача: ускорить группировку по строковой колонке с малым числом уникальных значений.

Промт:

Код: df.groupby('city')['sales'].sum() выполняется 10 секунд. Колонка city содержит 50 уникальных значений. Как ускорить? Предложи преобразование типов и альтернативы.

Пример результата:

df['city'] = df['city'].astype('category')
# или использовать Polars:
import polars as pl
df_pl = pl.from_pandas(df)
result = df_pl.group_by('city').agg(pl.col('sales').sum())

Категориальный тип уменьшает память и ускоряет группировку за счёт целочисленных кодов. Но осторожно: при частых операциях добавления новых категорий это может замедлить работу.

10. Генерация синтетических данных для тестов

Задача: создать реалистичный датафрейм для проверки пайплайна.

Промт:

Сгенерируй Pandas DataFrame с 10 000 строк и колонками: user_id (int), age (int от 18 до 70), country (выбор из 5 стран), purchase_amount (float с логнормальным распределением), purchase_date (datetime за последний год). Добавь 5% пропусков в purchase_amount.

Пример результата:

import numpy as np
import pandas as pd

np.random.seed(42)
n = 10000
df = pd.DataFrame({
    'user_id': np.arange(n),
    'age': np.random.randint(18, 71, n),
    'country': np.random.choice(['RU', 'US', 'DE', 'FR', 'CN'], n),
    'purchase_amount': np.random.lognormal(mean=3, sigma=1, size=n),
    'purchase_date': pd.date_range('2025-01-01', periods=n, freq='H')
})
df.loc[df.sample(frac=0.05).index, 'purchase_amount'] = np.nan

LLM хорошо справляется с такими задачами, но может перепутать параметры распределения. Проверяйте, что данные не содержат отрицательных сумм и даты в разумном диапазоне.

11. Перевод сложной агрегации на Polars

Задача: переписать многошаговую агрегацию с оконными функциями.

Промт:

Переведи на Polars:
df['rank'] = df.groupby('category')['value'].rank(pct=True)
df['rolling_mean'] = df.groupby('category')['value'].transform(lambda s: s.rolling(7).mean())

Пример результата:

df_pl = df_pl.with_columns([
    pl.col('value').rank().over('category').alias('rank'),
    pl.col('value').rolling_mean(7).over('category').alias('rolling_mean')
])

В Polars оконные функции требуют явного указания .over(). LLM может забыть про порядок сортировки для rolling — проверяйте, что данные отсортированы по времени.

Ключевое различие Pandas rolling по умолчанию требует монотонного индекса, Polars — нет. Но для корректного результата в Polars нужно явно сортировать перед оконной функцией.

12. Отладка ошибок типов при merge

Задача: разобраться, почему merge возвращает пустой результат.

Промт:

Код: df1.merge(df2, on='id') возвращает 0 строк, хотя в обоих датафреймах есть значения '123'. В df1 колонка id имеет тип object, в df2 — int64. Как исправить и почему это происходит?

Пример результата:

df1['id'] = df1['id'].astype(int)  # или df2['id'].astype(str)
merged = df1.merge(df2, on='id')

Причина: Pandas сравнивает значения с учётом типа, и строка '123' не равна числу 123. LLM часто предлагает просто astype(str) для обоих, но это может привести к потере ведущих нулей. Лучше приводить к тому типу, который соответствует смыслу данных.

Когда LLM ускоряет работу, а когда требует проверки

LLM отлично справляются с генерацией шаблонного кода, переводом между библиотеками и объяснением ошибок. Они экономят время на рутине: написание clean_dataframe, конвертация Pandas → Polars, поиск узких мест по описанию.

Но есть области, где модель ошибается предсказуемо:

  • Типы данных и пропуски. LLM может предложить операцию, которая упадёт на NaN или на неожиданном типе. Всегда проверяйте код на тестовом наборе с пропусками.
  • Порядок операций. В Polars порядок filter и with_columns может влиять на результат. Модель может переставить шаги местами.
  • Устаревший синтаксис. Pandas быстро развивается, и LLM иногда выдаёт код, который работает, но с предупреждениями (например, append вместо concat).

Практическое правило: используйте LLM для черновика, но финальную проверку делайте на реальных данных с граничными случаями. Особенно это касается merge и groupby — здесь ошибки типов приводят к неверным результатам, а не к исключениям.

Если вы хотите глубже разобраться в работе с данными и LLM, обратите внимание на смежные материалы: Юнит-тесты на Python с LLM: 12 промтов от pytest-фикстур до Hypothesis и Golang с нуля: горутины, каналы и реальная цена конкурентности в Go.

Промты — это инструмент, который усиливает ваши навыки, но не заменяет понимание данных. Чем лучше вы знаете Pandas и Polars, тем точнее формулируете запросы и тем быстрее замечаете, где модель ошиблась. Начните с малого: возьмите один промт из этой подборки и примените к своему текущему проекту. Уже через несколько итераций вы выработаете собственный стиль общения с LLM, который будет экономить часы работы.

← Все статьи

Спросить AI по этой статье

Задайте вопрос по этой статье — ASI Biont ответит, опираясь на её текст.

Читайте также

ИИ для повседневной жизни: как построить реальный семейный бюджет с ChatGPT и Claude (без кода, 2026)

27 октября 2026

Нейрохакинг и когнитивная оптимизация: как за неделю собрать протокол, который реально работает

27 октября 2026

Цифровая гигиена за вечер: как найти утечки персональных данных и удалить информацию о себе из интернета

27 октября 2026

Сколько часов учить испанский до DELE 2026: разбор нормативов, статистики и гибридной подготовки с AI-репетитором

27 октября 2026

Юнит-тесты на Python с LLM: 12 промтов от pytest-фикстур до Hypothesis, которые закрывают непокрытые ветки

27 октября 2026

QA Automation Engineer: 5 мифов, которые стоят новичкам месяцев (и как их избежать)

11 ноября 2026

Вайб кодинг: как создавать код с помощью AI без навыков программирования — обзор курса и практические грабли

27 октября 2026

Full-Stack AI Engineer: как RAG-пайплайны, векторные базы данных и развертывание LLM на самом деле работают в продакшене

28 октября 2026

CIPM / CIPP/E — Управление конфиденциальностью и GDPR (IAPP): как статистика правоприменения GDPR превращает риск несоответствия требованиям в статью бюджета

28 октября 2026