Новое Распределяем каналы MAX по категориям и территориям. Читать новость
Открытый канал ID 72343601022986

Аналитика, машинное обучение и наука о данных для начинающих / Analytics, machine learning, and data science for beginners. Просто о сложных технологиях

🐍 Python для аналитики | 👨‍💻 SQL | 📊 Визуализация | ➕ Математика | 🦾 Машинное обучение (machine learning, ML) | Наука о данных (Data Science)

Канал носит исключительно информационный и ознакомительный характер. Автор делится личным опытом и субъективным мнением о программировании. Материалы не являются официальной образовательной программой

Каналов в рубрике
101 367
Место этого канала
№ 26 721
Открыть рубрику →
Каналов в рубрике
2 093
Место этого канала
№ 251
Открыть рубрику →
Каналов в рубрике
465
Место этого канала
№ 465
Открыть рубрику →
Каналов в рубрике
937
Место этого канала
№ 937
Открыть рубрику →
Открыть в MAX

Публикации за период

По реакциям

Поиск и вся лента — после бесплатной регистрации. Свои даты — по подписке; владелец канала видит их бесплатно. Сортировка по реакциям — по подписке. Зарегистрироваться

Загрузка…

🤗 Сводная таблица pivot_table — альтернатива groupby для матричных отчётов

🧭 Что такое pivot_table

Это группировка в матрицу: строки × столбцы = значение.
Результат — всегда DataFrame (в отличие от df.groupby(), который может вернуть Series).

📄 Аналоги

- Excel: сводная таблица (Pivot Table)
- SQL: оператор PIVOT (кросстабуляция)

📐 Когда что использовать?

- по одному признаку → groupby
- перекрёстно (2+ признака) → pivot_table
- несколько метрик в одной сводной → pivot_table(values=[...])

🔧 Синтаксис

pd.pivot_table(df,
index='строки',
columns='столбцы', # опционально
values='данные',
aggfunc='mean', # по умолчанию mean
fill_value=0, # замена всех NaN
margins=True, # итоги
sort=True)


📊 Исходные данные

df = pd.DataFrame({
'ch': ['ya','ya','vk','ok'],
'city': ['МСК','СПб','МСК','СПб'],
'cost': [15000,15000,5000,5000],
'revenue': [30000,40000,10000,None]
})


✅ Простая сводная — только index (аналог groupby)

pd.pivot_table(df, index='ch',
values=['cost','revenue'],
aggfunc='sum', fill_value=0)

cost revenue
ch
ok 5000 0
vk 5000 10000
ya 30000 70000


*Списки в values, но строка в aggfunc → две колонки, без лишнего уровня.*

🦾 Матрица (index + columns) — сила pivot_table

pd.pivot_table(df, index='ch',
columns='city',
# 🦾
values='cost',
aggfunc='sum')

city МСК СПб
ch
ok NaN 5000
vk 5000 NaN
ya 15000 15000


📌 fill_value=0 заменяет любые пропуски (NaN):

- если отсутствует комбинация строк и столбцов (пример выше);
- если агрегатная функция вернула NaN для пустой группы.

pd.pivot_table(df, index='ch',
columns='city',
values='cost',
aggfunc='sum',
fill_value=0)

city МСК СПб
ch
ok 0 5000 # нет пары → был бы NaN
vk 5000 0 # также
ya 15000 15000


Без fill_value=0 в таких ячейках будет NaN. С ним — чистая матрица без пропусков, удобна для анализа.

💡 aggfunc и values: строки vs списки (MultiIndex)

aggfunc и values задают, сколько уровней (level) будет в колонках результата (в шапке).

Правило:
- Строка (aggfunc='sum', values='cost') → плоские колонки.
- Список (даже из одного: aggfunc=['sum'], values=['cost']) → дополнительный уровень (MultiIndex).

pd.pivot_table(df, index='ch', values=['cost'], aggfunc=['sum'])

sum
cost
ch
ok 5000
vk 5000
ya 30000


Дополнение: `columns` всегда создаёт уровень — это сами столбцы матрицы, у него есть имя:

result = pd.pivot_table(df, index='ch',
columns='city',
# ← вот уровень
values='cost',
aggfunc='sum',
fill_value=0)

result.columns
# Index(['МСК', 'СПб'], dtype='object', name='city')

name='city' — это и есть уровень, который создал columns.


📊 Тип результата

type(df.groupby('ch')['revenue'].sum()) # Series
type(df.groupby('ch')[['revenue']].sum()) # DF
type(pd.pivot_table(df, index='ch', values='revenue', aggfunc='sum')) # DF

☝️ Про None → NaN (кратко)

- Числовой столбец None → NaN (единый формат для вычислений).
- Строковый столбец None остаётся None (NaN не существует для строк).
- Смешанный → None (без чисел) / NaN (с числами).
- Тип столбца определяется автоматически.
- fill_value=0 заменяет любые NaN в итоговой таблице (включая mean, median).
- Для гарантии замены в pandas < 1.3.0 (особенно при нескольких агрегациях) можно явно дописать .fillna(0):

result = pd.pivot_table(...).fillna(0)

🆚 pivot_table vs groupby

groupby:
- не строит матрицу ❌
- длинная таблица
- только вниз
- возвращает Series или DF

pivot_table:
- строит матрицу ✅
- широкая таблица
- вниз и вправо
- возвращает всегда DF

✅ Чек-лист

- groupby('col') — по одному столбцу
- groupby(['col1','col2']) — по двум
- .groupby(...)['col'].sum() → Series
- .groupby(...)[['col']].sum() → DF
- pivot_table() — перекрёстная группировка
- groupby(..., dropna=False) — не исключать пропуски

💬 Далее:
Объединение таблиц — merge, concat, join.
Просмотры: 52
Перейти в пост Открыть в MAX Сообщить о неточности
🐼 Pandas. Группировки и агрегации

🧐 Логика

Pandas, как и SQL, реализует парадигму Разделение‑Применение‑Объединение / Split‑Apply‑Combine:
- разбиваем данные на группы
- применяем к каждой группе функцию (медиану и т.д.)
- собираем результаты в новый DataFrame

Это логика мышления, а не жёсткий порядок операций.

🆚️ Агрегации в SQL и Pandas

SQL:
- Быстрая агрегация внутри базы без перелива данных
- GROUP BY + COUNT, SUM, AVG, MIN, MAX, STRING_AGG, ARRAY_AGG
- Оконные функции (ROW_NUMBER, LAG, SUM OVER) — агрегация с сохранением строк

Pandas:
- Гибкая агрегация с произвольными функциями: .agg(['mean', 'std', custom_func])
- Трансформация с сохранением размера: .transform()
- Фильтрация групп: .filter(lambda x: len(x) > 5)
- Мультииндексные утилиты: unstack(), pivot_table()

👥 Агрегации по ролям

Аналитик
SQL — метрики по группам
Pandas — аномалии

Дата-сайентист (Data Scientist)
SQL — примеры (sample)
Pandas — генерация признаков (feature engineering)

Инженер данных (Data Engineer)
SQL — витрины
Pandas — прототипы

BI‑аналитик
SQL — вся агрегация в DWH
Pandas — ❌ не нужно

Продуктовый аналитик
SQL — 80% когорт
Pandas — 20% кастом

ML-инженер (Machine Learning Engineer)
SQL — выгрузка признаков (features, фичей)
Pandas — пайплайны

📊 Пример

import pandas as pd

df = pd.DataFrame({
'ch': ['ya', 'vk', 'ok', None, 'tg'],
'cost': [5000, 5000, 500, 500, None],
'revenue': [30000, 10000, None, 40000, 30000]
})


🌟 Синтаксис groupby

df.groupby('ch')['cost'].sum()

df — объект DataFrame
.groupby() — метод группировки
['cost'] — выбор данных
.sum() — метод агрегации

🐍 Типы скобок в Python

( ) — вызов функции/метода
[ ] — доступ к элементу

👥 Группировка

groupby() только группирует данные, не считает их.
Результат появляется при добавлении агрегации: sum(), mean() и т.д.

df.groupby('ch')[['cost', 'revenue']].sum()

Результат — DataFrame: потеряли 40k выручки 🤯

cost revenue
ch
ok 500.0 0.0
tg 0.0 30000.0
vk 5000.0 10000.0
ya 5000.0 30000.0


Почему?
`0.0`, а не `0`: если есть None → Pandas автоматически приводит всю колонку к типу float64

нет строки с NaN: по умолчанию строки с None в ключе группировки исключаются из результата groupby(dropna=True)
dropna=False — чтобы вернуть, см. ниже.

0️⃣ NaN или 0?

Зависит от:
1) метода агрегации
2) объекта агрегации

1️⃣ Методы sum и count возвращают число, все остальные — NaN:

• .sum() → пустая сумма = 0
• .mean() → нечего усреднять = NaN
• .count() → ноль штук = 0
• .min() → не из чего выбирать = NaN
• .max() → NaN
• .std() → NaN

2️⃣ NaN в ключе группировки — другие правила

- NaN в значениях (revenue, cost) → правила агрегации (см. таб. выше)
- NaN в ключе группировки (ch) → зависит от dropna:
`dropna=True` (по умолчанию): → строки с None в ключе исключаются
`dropna=False`: → None становится отдельной группой, внутри — те же правила агрегации

df.groupby('ch', dropna=False)[['cost', 'revenue']].sum()

Результат:

cost revenue
ch
NaN 500.0 40000.0
ok 500.0 0.0
tg 0.0 30000.0
vk 5000.0 10000.0
ya 5000.0 30000.0

# появилась группа NaN и 40k 🥳

💡 Альтернатива: fillna(0)

Чтобы цифры сходились, меняем None на 0 (везде):

df.fillna(0).groupby('ch')['revenue'].mean()

🤔 Series или DataFrame?

Pandas определяет автоматически по результату:
df['cost'] → Series (одинарные скобки)
df[['cost']] → DataFrame (двойные скобки)


.groupby() аналогично:
- одна колонка (агрегация) → Series
- две+ колонок (агрегации) → DataFrame

➕ Несколько агрегаций через agg

df.groupby('ch')['revenue'].agg(['sum', 'mean'])

💡 transform — среднее внутри каждой группы

df['mean_ch'] = df.groupby('ch')['revenue'].transform('mean')

Результат:

ch cost revenue mean_ch
0 ya 5000.0 30000.0 30000.0
1 vk 5000.0 10000.0 10000.0
2 ok 500.0 NaN NaN
3 None 500.0 40000.0 NaN
4 tg NaN 30000.0 30000.0


🎯 transform полезен для:
- нормализации
- расчёта долей
- заполнения пропусков

💬 Далее:
Сводные таблицы — pivot_table
Просмотры: 195
Перейти в пост Открыть в MAX Сообщить о неточности
🧹 Чистка и преобразование данных в Pandas

Разберём основные приёмы.

📄 Копия или оригинал?

В Pandas большинство методов по умолчанию не изменяют исходный DataFrame, а возвращают новый изменённый объект.

Если нужно изменить исходный, используется параметр inplace=True.

☝️ inplace=True не используется в цепочках методов (method chaining), потому что он возвращает None, а не DataFrame, и цепочка обрывается. Поэтому в стиле df.method1().method2() всегда работают методы без inplace, а результат присваивается переменной или передаётся дальше.

import pandas as pd

# ✅ Цепочки (без inplace)
df_clean = (df
.fillna(0)
.dropna()
.rename(columns={'A': 'B'}))

# ❌ Так не работает – inplace вернёт None
df.fillna(0, inplace=True).dropna() # Ошибка!


🍩 Что делать с пропусками?

.dropna() и .fillna() — два основных метода для работы с пропущенными значениями (NaN, None, NaT).

Для замены других некорректных значений (например, 0 или пустая строка) используйте .replace() (см.ниже).

Выбор зависит от количества пропусков:
• Удалить (.dropna()) — когда данные с пропусками не нужны для анализа (теряем объём, но избавляемся от проблем)
• Заполнить (.fillna()) — когда пропусков мало и разумная замена (среднее, медиана, 0 и т.п.) не сильно исказит данные

df.dropna() # удалить строки с любым NaN
df.dropna(how='all') # удалить строки, где все значения NaN

df.fillna(0)
# заполнить константой
df.fillna(df['cost'].mean()) # заполнить средним по столбцу
df.fillna(df.median()) # каждый столбец заполняет свои пропуски собственной медианой этого же столбца


🔄 Преобразование типов данных

Изменить тип столбца можно с помощью .astype():

df['price'] = df['price'].astype('float32')
df['date'] = pd.to_datetime(df['date']) # работа с датами


🆕 Перезапись существующих столбцов

➡️ Простое добавление новых столбцов — описано ранее.

Перезапись происходит через прямое переприсваивание:

# Повышаем цены на 10%
df['price'] = df['price'] * 1.1 # без методов .update() или .replace()


📌 Замена значений: .apply(), .map(), .replace()

Метод .apply() — для функции любой сложности (своей, lambda, встроенной) на Series и DataFrame

Лямбда — компактная функция в одну строку (одно выражение). Для простых действий это удобнее, чем создавать отдельную функцию:
lambda x: x * 1.1 # возьми x, верни x * 1.1

# лямбда-функция: пересчёт цены в доллары
df['price_usd'] = df['price_eur'].apply(lambda x: x * 1.1)

# своя функция (когда логика сложнее)
def discount(price):
return price * 0.9 if price > 1000 else price

df['price_disc'] = df['price'].apply(discount)

# применение к строке (axis=1) — для больших данных может быть медленнее векторизованных операций
df['full_info'] = df.apply(lambda row: f"{row['name']} - {row['price']}", axis=1)

Метод .map() — простое преобразование элементов или замена значений по словарю (только Series)

# Замена кодов на названия городов
df['city'] = df['city_code'].map({1: 'Москва', 2: 'СПб', 3: 'Казань'})
# Если кода нет в словаре → NaN


Метод .replace() — глобальная замена конкретных значений (Series и DataFrame)

# Замена 'Msk' на 'Москва', 'Spb' на 'СПб' (во всём DataFrame)
df['city'] = df['city'].replace({'Msk': 'Москва', 'Spb': 'СПб'})


Короткое правило:
• одна колонка → .map()
• весь DataFrame → .replace()

➗ Разделение строк

# Исходные данные
df = pd.DataFrame({'full_name': ['Иванов Иван', 'Петров Петр', 'Сидоров Сидор']})

# Разделяем фамилию и имя
df[['last_name', 'first_name']] = df['full_name'].str.split(' ', expand=True)


✅ Что нужно запомнить

• Копии vs оригинала (inplace и method chaining)
• Работа с пропусками: .dropna(), .fillna()
• Преобразование типов: .astype(), pd.to_datetime()
• Перезапись существующих столбцов:
.apply() с кастомными функциями любой сложности
.map() — замена по словарю
.replace() — глобальная замена значений
• Разделение строк .str.split()

💬 Далее:
Pandas. Группировки и агрегации
Просмотры: 275
Перейти в пост Открыть в MAX Сообщить о неточности
ВКонтакте Телеграм Одноклассники
Избранное в datool.ru

Следите за каналом в личном кабинете

Зарегистрируйтесь в datool.ru, чтобы добавить канал «Аналитика, машинное обучение и наука о данных для начинающих / Analytics, machine learning, and data science for beginners. Просто о сложных технологиях» в избранное и отслеживать его показатели.

Зарегистрироваться
Для владельцев каналов

Подтвердите свой канал

Войдите или зарегистрируйтесь в datool.ru, затем добавьте нашего бота в канал по инструкции в личном кабинете. После проверки владения замок исчезнет и вам станет доступно управление каналом.

Войти или зарегистрироваться

Сообщить о неточности

Опишите, что нужно исправить. Если есть источник, добавьте ссылку.

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти