1. What is Pandas (and when NOT to use it)?1. Что такое Pandas (и когда его НЕ брать)?
Pandas is the standard Python library for in-memory tabular data: load, clean, reshape, aggregate. It runs on one machine and holds everything in RAM, built on NumPy arrays.
Pandas — стандартная Python-библиотека для табличных данных в памяти: загрузка, очистка, преобразование, агрегация. Работает на одной машине и держит всё в RAM, поверх массивов NumPy.
2. Series & DataFrame2. Series и DataFrame
A Series is a 1-D labeled array (one column). A DataFrame is a 2-D table — a dict of Series sharing one index (the row labels). The index is what makes pandas special: alignment happens by label, not position.
Series — одномерный помеченный массив (одна колонка). DataFrame — двумерная таблица — словарь Series с общим индексом (метки строк). Индекс — то, что делает pandas особенным: выравнивание идёт по метке, а не по позиции.
import pandas as pd df = pd.DataFrame({ "user_id": [1, 2, 3], "country": ["DE", "UK", "DE"], "amount": [10.0, 25.5, 7.0], }) df.head() # first rows df.info() # dtypes + memory + non-null counts df.describe() # summary stats of numeric cols df.shape # (rows, cols) df.dtypes # type per column
3. Selecting & filtering: loc vs iloc3. Выбор и фильтрация: loc vs iloc
| Goal | Code |
|---|---|
| One column → Series | df["amount"] |
| Several columns → DataFrame | df[["user_id","amount"]] |
| By label (rows, cols) | df.loc[row_label, "amount"] |
| By position (integer) | df.iloc[0, 2] |
| Boolean filter | df[df["amount"] > 10] |
| Цель | Код |
|---|---|
| Одна колонка → Series | df["amount"] |
| Несколько колонок → DataFrame | df[["user_id","amount"]] |
| По метке (строки, колонки) | df.loc[row_label, "amount"] |
| По позиции (целое число) | df.iloc[0, 2] |
| Булев фильтр | df[df["amount"] > 10] |
# combine conditions: & | ~ and wrap each in parentheses! df[(df["country"] == "DE") & (df["amount"] > 5)] # membership & query syntax df[df["country"].isin(["DE", "UK"])] df.query("country == 'DE' and amount > 5")
&/| (not and/or) for element-wise filters, and parenthesize each condition. 2) loc = labels, iloc = integer positions — mixing them is a frequent bug.
1) Используй &/| (не and/or) для поэлементных фильтров и заключай каждое условие в скобки. 2) loc = метки, iloc = целочисленные позиции — их путаница частый баг.
4. Transforming columns4. Преобразование колонок
# vectorized math — fast, preferred df["amount_eur"] = df["amount"] * 1.08 # conditional column without a loop import numpy as np df["tier"] = np.where(df["amount"] > 20, "hi", "lo") # map a Series through a dict df["region"] = df["country"].map({"DE": "EU", "UK": "non-EU"}) # string & datetime accessors df["country"].str.lower() pd.to_datetime(df["ts"]).dt.year # assign() for chaining (returns a new df) df = df.assign(net=lambda d: d.amount - d.fee)
df.apply(func, axis=1) loops row-by-row in Python — slow. Use it only when there's no vectorized form. iterrows() is even slower; avoid it. (More in Performance.)
df.apply(func, axis=1) идёт построчно в Python — медленно. Используй, только если нет векторизованной формы. iterrows() ещё медленнее; избегай. (Подробнее в Performance.)
5. groupby & merge5. groupby и merge
groupby follows split → apply → combine: split rows by key, apply an aggregation, combine into a result.
groupby работает по схеме split → apply → combine: разбей строки по ключу, примени агрегацию, собери результат.
(df.groupby("country") .agg(n=("user_id", "count"), total=("amount", "sum"), avg=("amount", "mean")) .reset_index()) # turn the group key back into a column # transform keeps original shape (like a SQL window) df["grp_avg"] = df.groupby("country")["amount"].transform("mean")
merge = SQL join. Know how and watch the row count after.
merge = SQL join. Знай how и следи за числом строк после.
pd.merge(orders, users, on="user_id", how="left") # how: inner | left | right | outer ; validate guards dup keys: pd.merge(orders, users, on="user_id", how="left", validate="many_to_one") # concat = stack rows (UNION) or columns pd.concat([jan, feb], axis=0, ignore_index=True)
merge joins on columns (most common). df.join joins on the index. concat stacks frames. validate= catches accidental fan-out from duplicate keys — a real interview-grade habit.
merge джойнит по колонкам (чаще всего). df.join — по индексу. concat складывает фреймы. validate= ловит случайное размножение строк из-за дублей ключей — привычка уровня интервью.
6. Missing data & dtypes6. Пропуски и типы (dtypes)
df.isna().sum() # nulls per column df.dropna(subset=["user_id"]) # drop rows missing a key df["amount"].fillna(0) # fill df.fillna({"amount": 0, "country": "NA"}) # types: shrink memory & fix parsing df["user_id"] = df["user_id"].astype("int32") df["country"] = df["country"].astype("category") # big win for repeats
NaN is a float, so an int column with a null becomes float64. NaN != NaN, so never compare with == — use .isna(). Modern pandas has nullable Int64/boolean dtypes that keep ints int.
Классический NaN — это float, поэтому int-колонка с пропуском становится float64. NaN != NaN, поэтому никогда не сравнивай через == — используй .isna(). В современном pandas есть nullable-типы Int64/boolean, сохраняющие int.
7. Reading & writing7. Чтение и запись
df = pd.read_csv("data.csv", dtype={"user_id": "int32"}, parse_dates=["ts"], usecols=["user_id", "ts", "amount"]) df = pd.read_parquet("data.parquet") # typed, compressed, fast df.to_parquet("out.parquet", index=False) df.to_csv("out.csv", index=False)
read_csv, pass usecols (only needed columns), dtype (skip inference + save memory), and parse_dates. For big files, chunksize= streams it in pieces. Prefer Parquet when you control the format.
В read_csv передавай usecols (только нужные колонки), dtype (без вывода типов + экономия памяти) и parse_dates. Для больших файлов chunksize= читает по частям. Предпочитай Parquet, когда контролируешь формат.
8. Mini-glossary8. Мини-словарь
| Term | Plain meaning |
|---|---|
| Series | 1-D labeled array (one column). |
| DataFrame | 2-D table; dict of Series sharing an index. |
| Index | The row labels; drives alignment. |
| loc / iloc | Select by label / by integer position. |
| Vectorization | Whole-column ops in C, no Python loop. |
| groupby | split → apply → combine aggregation. |
| transform | group op that keeps the original row count. |
| category dtype | Compact type for repeated string values. |
| Термин | Простой смысл |
|---|---|
| Series | Одномерный помеченный массив (одна колонка). |
| DataFrame | Двумерная таблица; словарь Series с общим индексом. |
| Index | Метки строк; управляет выравниванием. |
| loc / iloc | Выбор по метке / по целочисленной позиции. |
| Векторизация | Операции над всей колонкой в C, без Python-цикла. |
| groupby | Агрегация split → apply → combine. |
| transform | Групповая операция, сохраняющая число строк. |
| category dtype | Компактный тип для повторяющихся строк. |
9. Quick self-check9. Быстрая самопроверка
Answer in your head, then tap to flip.Ответь про себя, потом нажми, чтобы перевернуть.
loc selects by label (index/column names); iloc by integer position. loc slices are inclusive of the end label; iloc is not.loc выбирает по метке (имена индекса/колонок); iloc по целой позиции. У loc срез включает конечную метку; у iloc — нет.&/| (not and/or), and & binds tighter than ==, so each condition needs parentheses: (a==1)&(b>2).Поэлементные фильтры используют &/| (не and/or), и & связывает сильнее ==, поэтому каждое условие в скобках: (a==1)&(b>2).agg collapses each group to one row. transform returns a value per original row (broadcast back) — like a SQL window. Use transform to add a group stat as a new column.agg схлопывает каждую группу в одну строку. transform возвращает значение на каждую исходную строку — как SQL-окно. Используй transform, чтобы добавить групповую статистику новой колонкой.NaN is a float, so pandas upcasts the column to float64. Use nullable Int64 dtype to keep integers.Появился пропуск. Классический NaN — это float, поэтому pandas повышает тип колонки до float64. Используй nullable-тип Int64, чтобы сохранить целые..isna() / .notna(), never == NaN (NaN ≠ NaN). df.isna().sum() counts nulls per column.Используй .isna() / .notna(), никогда == NaN (NaN ≠ NaN). df.isna().sum() считает пропуски по колонкам.