Pandas
Pandas — главная библиотека для работы с табличными данными: чтение CSV, очистка, фильтры, группировки и агрегирование в пару строк кода.
1. Что такое Pandas
Pandas превращает Python в «электронную таблицу с кодом». Основные структуры:
- Series — одномерный массив с индексами.
- DataFrame — таблица: строки, столбцы, именованные колонки.
На всех этапах работы с данными — от чтения до отправки в модель — Pandas незаменим.
2. Установка и импорт
pip install pandasimport pandas as pd
print(pd.__version__)3. Создание DataFrame
import pandas as pd
df = pd.DataFrame({
'name': ['Аня', 'Борис', 'Вера'],
'age': [25, 31, 28],
'city': ['Москва', 'Питер', 'Москва']
})
print(df)
print(df.shape) # (3, 3)
print(df.columns) # Index(['name','age','city'])
print(df.describe()) # сводка по числам4. Чтение и запись данных
df = pd.read_csv('data.csv') # CSV
df = pd.read_excel('file.xlsx') # Excel
df = pd.read_json('data.json') # JSON
df = pd.read_sql('SELECT * FROM t', conn) # SQL
df.to_csv('out.csv', index=False)
df.to_excel('out.xlsx', index=False)5. Просмотр и описание
df.head(10) # первые строки
df.tail(5) # последние
df.info() # типы и NULL
df.dtypes # типы колонок
df['age'].value_counts() # частоты6. Выбор строк и столбцов
df['name'] # столбец (Series)
df[['name', 'age']] # несколько столбцов
df.loc[0] # строка по индексу
df.iloc[1, 0] # по позиции
df[df['age'] > 26] # фильтр
df[(df['age'] > 26) & (df['city'] == 'Москва')]
df.query('age > 26 and city == "Москва"')7. Работа с пропусками
df.isna().sum() # сколько NaN в каждой колонке
df.dropna() # удалить строки с NaN
df.dropna(subset=['age'])# только по колонке
df.fillna(0) # залить нулями
df['age'] = df['age'].fillna(df['age'].mean()) # среднимdf.isna().sum(), сколько данных теряется — иногда выгоднее заполнить.8. Новые колонки и функции
df['bmi'] = df['weight'] / (df['height'] ** 2)
def bucket(a):
if a > 30:
return 'high'
return 'low'
df['level'] = df['bmi'].apply(bucket)Векторные условия — np.where из NumPy:
import numpy as np
df['tag'] = np.where(df['age'] > 30, 'взрослый', 'молодой')9. Группировка (groupby)
df.groupby('city')['age'].mean() # средний возраст по городам
df.groupby('city').agg({'age': ['mean', 'median', 'max']})
df.groupby(['city', 'level']).size() # частоты по двум полямАналог GROUP BY из SQL — только с результатом в DataFrame.
10. Сводные таблицы
pd.pivot_table(df,
values='age',
index='city',
columns='level',
aggfunc='mean',
fill_value=0)Как Excel-овская сводная: строки, столбцы, агрегат.
11. Объединение таблиц (Merge)
orders = pd.DataFrame({'user_id': [1, 2, 3], 'amount': [100, 250, 50]})
users = pd.DataFrame({'user_id': [1, 2, 3], 'name': ['A', 'B', 'C']})
merged = orders.merge(users, on='user_id', how='left')
print(merged)how выбирает тип соединения: left/right/inner/outer — как JOIN в SQL. Для конкатенации строк — pd.concat.
12. Обработка дат и строк
df['date'] = pd.to_datetime(df['date'])
df['year'] = df['date'].dt.year
df = df.sort_values('date').set_index('date')
df.resample('M').sum() # помесячная агрегация
df['name'] = df['name'].str.strip().str.title()13. Дубликаты и выбросы
Грязные данные ломают агрегаты: дубликаты завышают суммы, выбросы искажают средние. Первый шаг EDA — поиск полных и частичных дубликатов.
import pandas as pd
df = pd.read_csv('sales.csv')
# Полные дубликаты
print(df.duplicated().sum())
df_clean = df.drop_duplicates()
# Дубликат по ключу (например email)
df = df.drop_duplicates(subset=['email'], keep='first')
# Выбросы по IQR
q1, q3 = df['amount'].quantile([0.25, 0.75])
iqr = q3 - q1
outliers = df[
(df['amount'] < q1 - 1.5 * iqr) |
(df['amount'] > q3 + 1.5 * iqr)
]
print(outliers)14. Категориальные данные
Тип category экономит память и ускоряет группировки: значения хранятся как числа-коды с таблицей категорий, а операции groupby/value_counts работают в разы быстрее.
df['status'] = df['status'].astype('category')
print(df['status'].cat.categories) # список категорий
print(df['status'].value_counts()) # быстрее, чем по строкам
# Порядок важен для сортировки
df['priority'] = pd.Categorical(
df['priority'],
categories=['low', 'medium', 'high'],
ordered=True
)| Метод | Назначение |
|---|---|
| cat.codes | числовые коды для ML |
| cat.rename_categories | переименование значений |
| cat.remove_unused_categories | чистка пустых категорий |
15. apply и vectorized-операции
Циклы по строкам DataFrame — самая медленная операция. Вместо них используйте векторные выражения, np.select и apply только там, где логику не выразить поколоночно.
import numpy as np
# Условия по всему столбцу
df['is_big'] = df['amount'] > 1000
# Много условий — numpy.select
cond = [df['amount'] > 5000, df['amount'] > 1000]
choice = ['VIP', 'обычный']
df['segment'] = np.select(cond, choice, default='мелкий')
# apply — только для сложной логики на скаляре
df['slug'] = df['name'].str.lower().str.replace(' ', '-')16. Работа с Excel, CSV и SQL
pandas читает и пишет Excel, CSV, JSON и базы данных. Для объёмных файлов указывайте нужные колонки и типы при чтении — это экономит память и парсинг.
df = pd.read_csv('sales.csv',
usecols=['date', 'amount'],
dtype={'amount': 'float32'})
df.to_csv('sales_clean.csv', index=False)
# Excel: один лист или весь файл
df = pd.read_excel('report.xlsx', sheet_name='Январь')
# SQL: чтение и запись
from sqlalchemy import create_engine
engine = create_engine('postgresql://user:pass@localhost/db')
df = pd.read_sql('SELECT * FROM sales', engine)
df.to_sql('sales_copy', engine, if_exists='replace')17. Изменение формы: melt, stack и unstack
Данные приходят в разной форме: широкой (одна строка — один объект, много колонок) и длинной (одна строка — одно измерение). Melt переводит «широкую» таблицу в «длинную» для визуализаций и агрегаций: каждая пара колонок превращается в пары variable/value.
import pandas as pd
sales = pd.DataFrame({
'month': ['Янв', 'Фев', 'Мар'],
'north': [100, 120, 130],
'south': [90, 85, 110]
})
long = sales.melt(
id_vars='month',
var_name='region',
value_name='revenue'
)
print(long)Обратная операция — pivot_table или pivot, а stack/unstack умеют перекладывать уровни индекс/колонки то вниз, то вверх. При pivot следите за возможными дублями ключей: pivot_table корректно агрегирует, а pivot бросит ошибку.
| Функция | Действие |
|---|---|
| melt | широкую → длинную |
| pivot / pivot_table | длинную → широкую |
| stack | колонки → строки (индекс) |
| unstack | уровень индекса → колонки |
18. Скользящие окна: rolling, expanding и shift
Скользящие агрегаты строят метрики по истории: среднее за 7 дней, максимум за месяц, сумма со скользящим окном. Метод rolling принимает размер окна, expanding считает по всем предыдущим значениям («кумулятивно»), а shift сдвигает ряд на N позиций — стандартная заготовка для расчёта приростов.
import pandas as pd
df = pd.DataFrame(
{'days': pd.date_range('2026-01-01', periods=10, freq='D'),
'price': [10, 12, 11, 14, 13, 15, 18, 16, 17, 20]})
df['ma3'] = df['price'].rolling(3).mean()
df['cumsum'] = df['price'].expanding().sum()
df['prev'] = df['price'].shift(1)
df['change'] = df['price'].pct_change()
print(df.head())При работе с временными рядами сортируйте индекс по дате заранее: rolling не сортирует, а значит окно окажется «перемешанным», если данные не упорядочены. Для интервалов времени вместо фиксированного числа строк применяйте resample («за любой день месяца»).
- rolling(7).mean() — среднее за неделю; для расписания используйте окно по датам.
- Методы с min_periods защищают «хвосты» от NaN.
- apply внутри rolling работает в разы медленнее встроенных агрегатов.
19. Оптимизация памяти и чтение больших файлов
Память — дефицит в аналитике: каждая колонка хранится целиком. Начните с типов данных: числовые колонки в float64 легко превращаются во float32, целые — в int32/int16, а строки — в категории, если значений мало.
import pandas as pd
df = pd.read_csv('big.csv', dtype={
'id': 'int32',
'qty': 'int16'
})
df['city'] = df['city'].astype('category')
# чтение по частям, если файл не влазит в память
reader = pd.read_csv('huge.csv', chunksize=100_000)
for chunk in reader:
process(chunk)
# тонкий запрос вместо полной загрузки
df_small = pd.read_csv('huge.csv', usecols=['id', 'qty'])Для таблиц из БД передавайте в SQL точный WHERE и только нужные колонки: не тяните всю базу ради пары фильтров. Параллельное чтение через engine='pyarrow' (dtype_backend) в новых pandas ускоряет большие файлы.
df = pd.read_csv('big.csv', engine='pyarrow',
dtype_backend='pyarrow')20. Конвейеры данных и визуализация
Тяжёлая обработка в pandas не всегда «из коробки». Метод pipe позволяет строить читаемые конвейеры: каждая функция принимает и возвращает DataFrame, а цепочка вызывается по очереди. Плюс этого подхода — легко тестировать отдельные шаги.
import pandas as pd
def clean(df):
return df.dropna().rename(columns=str.lower)
def add_rate(df):
return df.assign(rate=df.revenue / df.days)
df = (pd.DataFrame({'Revenue': [100, 200, None],
'Days': [2, 4, 5]})
.pipe(clean)
.pipe(add_rate))
print(df)Особенно удобны конвейеры с кодом визуализации: на выходе каждой стадии — та же таблица, а графики строятся в отдельном шаге. Связка с Matplotlib и Seaborn выводит отчёт одним вызовом, а для интерактивности — Plotly или pandas-bokeh.
- Держите логику извлечения (SQL, файлы) отдельно от трансформаций — проще менять источники.
- График — не «бонус», а проверка: распределение данных сразу видно на гистограмме.
- Кэшируйте тяжёлые шаги (pickle/parquet), чтобы пересчёт не повторялся на каждый реран.
Что дальше
С таблицами разобрались — теперь графики Matplotlib и Seaborn. Для ML переход к Scikit-Learn. Всё удобно вести в Jupyter Notebook.