DataFrame: структура и способы создания
DataFrame — это не «таблица как в Excel», а упорядоченный набор столбцов-Series, разделяющих общий индекс строк.
DataFrame — двумерная структура: словарь, где ключи — имена столбцов, значения — Series, и у всех столбцов один общий индекс строк.
Как DataFrame устроен внутри
Проще всего думать о DataFrame как о словаре столбцов: имя столбца → Series. У всех этих Series общий индекс строк, поэтому строки выровнены между столбцами. Важное следствие: каждый столбец имеет свой dtype. В одной таблице спокойно живут целочисленный столбец, столбец строк и столбец дат — в отличие от numpy-массива, где тип один на всё.
Есть две оси: axis=0 — строки (вниз), axis=1 — столбцы (вправо). Многие методы принимают axis, и путаница здесь — частый источник ошибок. Запомните: операция «по строкам» (axis=0) идёт вертикально и схлопывает строки, давая результат на столбец; «по столбцам» (axis=1) идёт горизонтально.
Лучший способ запомнить: axis указывает, какая ось исчезает в результате. df.sum(axis=0) схлопывает строки — остаётся по одному числу на столбец (сумма каждого столбца). df.sum(axis=1) схлопывает столбцы — остаётся по числу на строку (сумма по строке). Та же логика у drop: df.drop("город", axis=1) убирает столбец, df.drop(0, axis=0) — строку. Эта пара осей пронизывает весь pandas, поэтому интуиция «axis = ось, вдоль которой сворачиваем» окупается многократно.
Создание из словаря: самый частый способ
Чаще всего DataFrame собирают из словаря «столбец → список значений»:
import pandas as pd
df = pd.DataFrame({
"город": ["Москва", "Казань", "Сочи"],
"население": [13_000_000, 1_300_000, 470_000],
"море": [False, False, True],
})
print(df)
# город население море
# 0 Москва 13000000 False
# 1 Казань 1300000 False
# 2 Сочи 470000 True
print(df.dtypes)
# город object
# население int64
# море bool
# dtype: object
Ключи словаря стали именами столбцов, индекс строк pandas создал автоматически (0, 1, 2). Каждый столбец получил свой тип. Можно задать индекс явно через index= — например, кодом города.
Создание из списка словарей (записей)
Когда данные приходят «по строкам» (например, из JSON-API), удобен список словарей — каждый словарь это одна строка:
rows = [
{"товар": "мышь", "цена": 990, "шт": 3},
{"товар": "клавиатура", "цена": 2500, "шт": 1},
{"товар": "монитор", "цена": 18000}, # "шт" пропущено
]
# Соберём "DataFrame" вручную: объединим все ключи в набор столбцов
columns = []
for r in rows:
for k in r:
if k not in columns:
columns.append(k)
print("столбцы:", columns)
for i, r in enumerate(rows):
line = [str(r.get(c, "NaN")) for c in columns]
print(i, line)
Вывод:
столбцы: ['товар', 'цена', 'шт'] 0 ['мышь', '990', '3'] 1 ['клавиатура', '2500', '1'] 2 ['монитор', '18000', 'NaN']
Именно так pd.DataFrame(rows) и поступает: собирает объединение всех ключей в столбцы, а недостающие значения заполняет NaN. В реальном pandas строка с пропущенной «шт» получила бы NaN, и столбец «шт» стал бы float64.
Из numpy-массива и из файлов
Из двумерного numpy-массива создаётся DataFrame с числовыми позициями вместо имён — поэтому почти всегда стоит передать columns=:
import numpy as np
arr = np.arange(6).reshape(3, 2)
df = pd.DataFrame(arr, columns=["a", "b"])
# Из файлов — самый частый источник в реальной работе:
df = pd.read_csv("sales.csv") # CSV
df = pd.read_excel("report.xlsx") # Excel
df = pd.read_parquet("data.parquet") # колоночный формат
df = pd.read_json("records.json") # JSON
Чтение файлов мы детально разберём в последнем разделе — там много важных параметров (типы, даты, кодировки). Пока запомните, что read_* возвращают готовый DataFrame.
Доступ к столбцам и строкам
Один столбец достают квадратными скобками или через атрибут, и результат — это Series (то самое выравнивание по индексу строк, которое мы обсуждали):
df["население"] # столбец как Series
df[["город", "море"]] # несколько столбцов как DataFrame (двойные скобки!)
df.население # атрибутный доступ — удобно, но хрупко
Важная тонкость: df["x"] возвращает Series (один столбец), а df[["x"]] — DataFrame из одного столбца. Это разные типы, и путаница приводит к ошибкам в дальнейшем коде. Атрибутный доступ df.население работает, только если имя столбца — корректный идентификатор Python и не конфликтует с методом DataFrame (есть df.count — это метод, а не ваш столбец «count»), поэтому в надёжном коде предпочитают скобки. Создание нового столбца — просто присваивание: df["плотность"] = df["население"] / df["площадь"].
Просмотр и первичный осмотр данных
Первое, что делают с новым DataFrame, — смотрят на него. Эти методы стоит выучить как рефлекс:
| Метод | Что показывает |
df.head(n) / df.tail(n) | первые / последние n строк (по умолчанию 5) |
df.shape | кортеж (строк, столбцов) |
df.dtypes | тип каждого столбца |
df.info() | столбцы, типы, число непустых значений, память |
df.describe() | статистика по числовым столбцам (count, mean, std, квартили) |
df.columns / df.index | имена столбцов / метки строк |
df.memory_usage(deep=True) | память по столбцам (deep — точно для строк) |
info() — главный диагностический метод: за один взгляд видно, где пропуски (по числу non-null) и не «уплыли» ли типы (числа как object — признак грязных данных). describe() быстро выявляет аномалии: отрицательный возраст, цену в триллион, нулевой минимум там, где его быть не должно.
Подводные камни
- Порядок столбцов из словаря. В современном Python и pandas порядок ключей словаря сохраняется, но не полагайтесь на это для критичной логики — обращайтесь к столбцам по имени, а не по позиции.
- object вместо числа. Если
dtypesпоказываетobjectтам, где ждёте число, в данных есть нечисловые значения (пробелы, «—», запятая вместо точки). Это надо чистить (раздел 3). - describe() игнорирует нечисловые столбцы по умолчанию. Для строковых используйте
df.describe(include="object")илиinclude="all". - memory_usage без deep=True недооценивает строки: он считает только указатели, а не сами строки в памяти Python.
Лучшие практики
- После загрузки сразу вызывайте
df.info()иdf.describe(include="all")— это экономит часы отладки. - Давайте осмысленный индекс (
set_index("id")), если в данных есть естественный ключ строки — выравнивание и объединения станут проще. - Обращайтесь к столбцам по имени; не завязывайтесь на их порядок.
Итог
- DataFrame — упорядоченный словарь столбцов-Series с общим индексом строк.
- У каждого столбца свой dtype — это сила pandas по сравнению с numpy.
- Создаётся из dict, списка записей, массива или файла; недостающие значения дают NaN.
info(),describe(),shape,dtypes— обязательный первичный осмотр.