Руководство по Pandas
Изучите pandas с нуля: Series, DataFrame, фильтрация, groupby, пропущенные значения, объединение и визуализация данных с примерами на Python.
pandas — наиболее широко используемая Python-библиотека для работы со структурированными (табличными) данными. Она предоставляет две основные структуры данных — Series и DataFrame — и богатый набор инструментов для загрузки, очистки, преобразования, агрегирования и визуализации данных.
Эта глава охватывает всё необходимое, чтобы начать продуктивно работать с pandas с нуля: установку, структуры данных, чтение файлов, выбор и фильтрацию данных, обработку пропущенных значений, группировку, объединение и основы построения графиков.
Установка pandas
Установите pandas с помощью pip:
pip install pandasЕсли вы планируете следовать примерам с построением графиков в этой главе, также установите Matplotlib:
pip install matplotlibПосле установки импортируйте pandas, используя стандартный псевдоним pd:
import pandas as pdДве основные структуры данных
Series
Series — это одномерный массив с метками. Каждый элемент имеет значение и соответствующую метку индекса (по умолчанию — целые числа, начиная с 0).
import pandas as pd
scores = pd.Series([88.5, 92.0, 79.5, 95.0])
print(scores)Вывод:
0 88.5
1 92.0
2 79.5
3 95.0
dtype: float64Вы можете задать собственные метки индекса, чтобы данные были более самоописательными:
scores = pd.Series(
[88.5, 92.0, 79.5, 95.0],
index=['Alice', 'Bob', 'Carol', 'Dave']
)
print(scores)
print(scores['Bob']) # 92.0Вывод:
Alice 88.5
Bob 92.0
Carol 79.5
Dave 95.0
dtype: float64
92.0Series с осмысленным индексом похожа на словарь Python, но поддерживает векторизованные операции и интегрирована с остальной частью API pandas.
DataFrame
DataFrame — это двумерная таблица с метками строк и столбцов — можно представить её как электронную таблицу или SQL-таблицу, загруженную в Python. Каждый столбец внутренне является Series, разделяющей один и тот же индекс строк.
Создание DataFrame из словаря списков
Вывод:
name age score
0 Alice 25 88.5
1 Bob 30 92.0
2 Carol 28 79.5
3 Dave 35 95.0Ключи словаря становятся именами столбцов; значения словаря становятся столбцами. Индекс строк по умолчанию — 0, 1, 2, 3.
Полезные атрибуты для изучения DataFrame сразу после создания:
| Атрибут / Метод | Что возвращает |
|---|---|
df.shape | Кортеж (rows, columns) |
df.dtypes | Тип данных каждого столбца |
df.columns | Метки столбцов |
df.index | Метки строк |
df.head(n) | Первые n строк (по умолчанию 5) |
df.tail(n) | Последние n строк (по умолчанию 5) |
df.describe() | Сводная статистика для числовых столбцов |
df.info() | Имена столбцов, типы и количество непустых значений |
Чтение данных из файлов
В реальных проектах DataFrame вручную создаётся редко. pandas умеет читать десятки форматов файлов.
Чтение CSV-файла
import pandas as pd
df = pd.read_csv('sales.csv')
print(df.head())
print(df.shape) # e.g. (1000, 5)
print(df.dtypes)pd.read_csv() автоматически определяет типы столбцов. Распространённые параметры:
sep=';'— изменить разделитель (по умолчанию — запятая)index_col='id'— использовать столбец в качестве индекса строкparse_dates=['date']— распознать столбец как дату и времяnrows=500— читать только первые 500 строк (удобно для больших файлов)
Чтение файла Excel
df = pd.read_excel('report.xlsx', sheet_name='Sheet1')Требуется дополнительная зависимость openpyxl: pip install openpyxl.
Запись данных обратно в файл
df.to_csv('output.csv', index=False) # CSV without the row index column
df.to_excel('output.xlsx', index=False) # ExcelВыбор данных
Выбор столбцов
Выберите один столбец, чтобы получить Series:
ages = df['age']
print(type(ages)) # <class 'pandas.core.series.Series'>Выберите несколько столбцов, чтобы получить DataFrame:
subset = df[['name', 'score']]
print(subset)Вывод:
name score
0 Alice 88.5
1 Bob 92.0
2 Carol 79.5
3 Dave 95.0Выбор строк с помощью loc и iloc
pandas предоставляет два основных способа выбора строк:
loc— выбор по метке (значению индекса)iloc— выбор по целочисленной позиции (с 0)
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
print(df.loc[1]) # row with index label 1
print()
print(df.iloc[0]) # first row by position
print()
print(df.loc[1:2]) # rows with labels 1 and 2 (inclusive)
print()
print(df.iloc[0:2]) # rows at positions 0 and 1 (end is exclusive)Вывод:
name Bob
age 30
score 92.0
Name: 1, dtype: object
name Alice
age 25
score 88.5
Name: 0, dtype: object
name age score
1 Bob 30 92.0
2 Carol 28 79.5
name age score
0 Alice 25 88.5
1 Bob 30 92.0Обратите внимание на разницу: loc[1:2] — выбор по метке, включая оба конца; iloc[0:2] — выбор по позиции, правый конец не включается (как в обычных срезах Python).
Вы также можете выбрать конкретную ячейку:
print(df.loc[1, 'score']) # 92.0 — by label
print(df.iloc[0, 2]) # 88.5 — by positionФильтрация строк
Фильтруйте строки с помощью булева условия в квадратных скобках:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
# Rows where age is greater than 28
print(df[df['age'] > 28])Вывод:
name age score
1 Bob 30 92.0
3 Dave 35 95.0Объединяйте несколько условий с помощью & (и) или | (или). Всегда заключайте каждое условие в скобки:
# Age > 25 AND score >= 90
print(df[(df['age'] > 25) & (df['score'] >= 90)])Вывод:
name age score
1 Bob 30 92.0
3 Dave 35 95.0Используйте isin() для фильтрации по списку значений:
print(df[df['name'].isin(['Alice', 'Carol'])])Добавление и изменение столбцов
Добавьте новый столбец, присвоив ему значение:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
# Add a column with a calculated value
df['grade'] = df['score'].apply(lambda x: 'A' if x >= 90 else 'B')
print(df)Вывод:
name age score grade
0 Alice 25 88.5 B
1 Bob 30 92.0 A
2 Carol 28 79.5 B
3 Dave 35 95.0 Aapply() применяет функцию к каждому элементу столбца. Для простой арифметики лучше использовать векторизованные операции напрямую — они быстрее, чем apply():
df['score_scaled'] = df['score'] / 100 # no apply() neededПереименуйте столбцы с помощью rename():
df = df.rename(columns={'score': 'exam_score', 'age': 'years_old'})Удалите столбец с помощью drop():
df = df.drop(columns=['grade'])Сортировка данных
Отсортируйте DataFrame по одному или нескольким столбцам с помощью sort_values():
import pandas as pd
data = {
'department': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'name': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
'salary': [90000, 95000, 70000, 72000, 88000],
}
df = pd.DataFrame(data)
print(df.sort_values('salary', ascending=False))Вывод:
department name salary
1 Eng Bob 95000
0 Eng Alice 90000
4 Eng Eve 88000
3 HR Dave 72000
2 HR Carol 70000Сортировка по нескольким столбцам — например, по отделу по возрастанию, затем по зарплате по убыванию внутри каждого отдела:
df_sorted = df.sort_values(['department', 'salary'], ascending=[True, False])
print(df_sorted)Обработка пропущенных значений
Реальные наборы данных почти всегда содержат пропущенные значения. pandas представляет их как NaN (Not a Number).
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, None, 28, 35],
'score': [88.5, 92.0, None, 95.0],
}
df = pd.DataFrame(data)
# Count missing values per column
print(df.isnull().sum())Вывод:
name 0
age 1
score 1
dtype: int64Заполнение пропущенных значений
Замените NaN фиксированным значением или статистическим показателем:
df_filled = df.fillna({
'age': df['age'].mean(), # fill with column mean
'score': df['score'].median() # fill with column median
})
print(df_filled)Вывод:
name age score
0 Alice 25.000000 88.5
1 Bob 29.333333 92.0
2 Carol 28.000000 92.0
3 Dave 35.000000 95.0Удаление строк с пропущенными значениями
df_dropped = df.dropna()
print(df_dropped)Вывод:
name age score
0 Alice 25.0 88.5
3 Dave 35.0 95.0Когда заполнять, а когда удалять: удаление строк приводит к потере данных и может вносить смещение, если значения отсутствуют не случайно. Заполнение (импутация) обычно предпочтительнее, когда пропущенных данных мало. Для рабочих процессов машинного обучения смотрите главу Scale о стандартизации числовых признаков после импутации.
Группировка данных
groupby() разделяет DataFrame на группы, применяет функцию к каждой группе и объединяет результаты. Это аналог GROUP BY в SQL для pandas.
import pandas as pd
data = {
'department': ['Eng', 'Eng', 'HR', 'HR', 'Eng'],
'name': ['Alice', 'Bob', 'Carol', 'Dave', 'Eve'],
'salary': [90000, 95000, 70000, 72000, 88000],
}
df = pd.DataFrame(data)
print(df.groupby('department')['salary'].mean())Вывод:
department
Eng 91000.0
HR 71000.0
Name: salary, dtype: float64Примените несколько функций агрегирования одновременно с помощью agg():
print(df.groupby('department')['salary'].agg(['mean', 'min', 'max', 'count']))Вывод:
mean min max count
department
Eng 91000.0 88000 95000 3
HR 71000.0 70000 72000 2Объединение и конкатенация DataFrame
Объединение (как JOIN в SQL)
Используйте pd.merge() для объединения двух DataFrame по общему ключевому столбцу:
import pandas as pd
employees = pd.DataFrame({
'emp_id': [1, 2, 3],
'name': ['Alice', 'Bob', 'Carol'],
'dept_id': [10, 20, 10],
})
departments = pd.DataFrame({
'dept_id': [10, 20],
'dept_name': ['Engineering', 'HR'],
})
merged = pd.merge(employees, departments, on='dept_id')
print(merged)Вывод:
emp_id name dept_id dept_name
0 1 Alice 10 Engineering
1 2 Bob 20 HR
2 3 Carol 10 EngineeringПо умолчанию используется внутреннее объединение (только строки с совпадающим ключом в обоих DataFrame). Управляйте типом объединения с помощью how:
how='left'— все строки из левого DataFrame, совпадающие строки из правогоhow='right'— все строки из правого DataFrame, совпадающие строки из левогоhow='outer'— все строки из обоих DataFrame;NaNтам, где нет совпадения
Конкатенация (стекование DataFrame)
Используйте pd.concat() для вертикального стекования DataFrame с одинаковыми столбцами:
import pandas as pd
q1 = pd.DataFrame({'name': ['Alice', 'Bob'], 'sales': [120, 95]})
q2 = pd.DataFrame({'name': ['Carol', 'Dave'], 'sales': [110, 130]})
combined = pd.concat([q1, q2], ignore_index=True)
print(combined)Вывод:
name sales
0 Alice 120
1 Bob 95
2 Carol 110
3 Dave 130ignore_index=True сбрасывает индекс строк, чтобы он шёл от 0 до 3 вместо повторения 0 и 1 из каждого исходного DataFrame.
Описательная статистика
pandas упрощает вычисление сводной статистики для всего DataFrame или отдельных столбцов:
import pandas as pd
data = {
'name': ['Alice', 'Bob', 'Carol', 'Dave'],
'age': [25, 30, 28, 35],
'score': [88.5, 92.0, 79.5, 95.0],
}
df = pd.DataFrame(data)
print(df[['age', 'score']].describe())Вывод:
age score
count 4.000000 4.000000
mean 29.500000 88.750000
std 4.203173 6.714412
min 25.000000 79.500000
25% 27.250000 86.250000
50% 29.000000 90.250000
75% 31.250000 92.750000
max 35.000000 95.000000Отдельные статистики также доступны как прямые методы: df['score'].mean(), df['score'].std(), df['score'].median(), df['age'].max().
Базовая визуализация данных
pandas интегрирована с Matplotlib, поэтому вы можете строить графики прямо из DataFrame с помощью метода .plot(). Установите Matplotlib заранее, если ещё не сделали этого: pip install matplotlib.
Линейный график
import pandas as pd
import matplotlib.pyplot as plt
data = {
'month': ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
'revenue': [15000, 18000, 16500, 21000, 23000],
}
df = pd.DataFrame(data)
df.plot(kind='line', x='month', y='revenue', marker='o', title='Monthly Revenue')
plt.ylabel('Revenue ($)')
plt.tight_layout()
plt.show()Столбчатая диаграмма
df.plot(kind='bar', x='month', y='revenue', color='steelblue', title='Monthly Revenue')
plt.ylabel('Revenue ($)')
plt.xticks(rotation=0)
plt.tight_layout()
plt.show()Распространённые значения параметра kind:
kind | Тип графика |
|---|---|
'line' | Линейный график |
'bar' | Вертикальная столбчатая диаграмма |
'barh' | Горизонтальная столбчатая диаграмма |
'hist' | Гистограмма |
'box' | Ящик с усами |
'scatter' | Точечная диаграмма (требует x и y) |
'pie' | Круговая диаграмма |
Для более продвинутого построения графиков смотрите главы Matplotlib Introduction и Matplotlib Scatter Plot.
Типичные подводные камни
SettingWithCopyWarning: Когда вы фильтруете DataFrame и затем пытаетесь изменить результат, pandas может предупредить вас, что вы изменяете копию, а не исходный объект. Используйте .copy(), чтобы сделать это явным:
# Safe: work on an explicit copy
young = df[df['age'] < 30].copy()
young['group'] = 'junior'Цепочечная индексация: df['col'][0] = value может изменить или не изменить исходный DataFrame. Всегда используйте df.loc[0, 'col'] = value для присвоения.
Имена столбцов с пробелами: Если столбец называется "first name", необходимо использовать скобочную нотацию — df['first name'] — а не точечную (df.first name является синтаксической ошибкой).
Целые числа vs. float после fillna: Заполнение NaN в столбце с целыми числами числом преобразует столбец в float64, поскольку NaN — это число с плавающей точкой. Используйте pd.Int64Dtype() (nullable integer), если нужно сохранить целочисленную семантику при наличии пропущенных значений.
Связанные главы
- NumPy Tutorial — библиотека массивов, на которой построена pandas
- Matplotlib Introduction — создание качественных графиков из ваших данных
- Matplotlib Scatter Plot — визуализация зависимостей между двумя числовыми переменными
- Data Distribution — понимание того, как значения распределены в наборе данных
- Scale — нормализация и стандартизация числовых признаков перед моделированием
- Categorical Data — кодирование нечисловых столбцов для машинного обучения
- Train/Test Split — разделение DataFrame pandas на обучающую и тестовую выборки
- SciPy Tutorial — статистические и научные функции, дополняющие pandas