Праздники ещё идут — и нет, я не спился😁
Начало января 2026 для меня — про размеренный отдых и паузу.
Без спешки и перегруза. Просто время, в котором можно: выспаться, выдохнуть, спокойно подумать и, в целом, нормально отдохнуть
Сейчас я в Белграде🇷🇸 — гуляю, знакомлюсь с городом и страной, ловлю ощущение перезагрузки. Очень классное чувство — начинать год без суеты, без дедлайнов, без вечного «надо было ещё вчера».
Особенно это ощущалось сегодня, 7 января — здесь празднуют Рождество.
Город буквально нажал на паузу: около 95% всего закрыто — музеи, заведения, магазины. Работают только точечные кафешки (и то, они начали открываться ближе к 14-15) и, конечно же, храмы. Люди никуда не торопятся, день просто проживается.
Фотки с Сербии прикладываю в посте📸
Пока это 3 день, поэтому, вероятно, дополню после поездки и мб напишу про Сербию отдельный пост (в рамках какой-нибудь конкретной темы). Кстати, если что-то интересно — пишите в комментарии, вполне это может перерасти в пост.
А вообще, иногда лучший способ провести праздники — позволить себе тишину и неспешность, хотя я тот ещё любитель покутить.
А как вы проводите свои праздники?👀
@data_driven_bogdan
Начало января 2026 для меня — про размеренный отдых и паузу.
Без спешки и перегруза. Просто время, в котором можно: выспаться, выдохнуть, спокойно подумать и, в целом, нормально отдохнуть
Сейчас я в Белграде🇷🇸 — гуляю, знакомлюсь с городом и страной, ловлю ощущение перезагрузки. Очень классное чувство — начинать год без суеты, без дедлайнов, без вечного «надо было ещё вчера».
Особенно это ощущалось сегодня, 7 января — здесь празднуют Рождество.
Город буквально нажал на паузу: около 95% всего закрыто — музеи, заведения, магазины. Работают только точечные кафешки (и то, они начали открываться ближе к 14-15) и, конечно же, храмы. Люди никуда не торопятся, день просто проживается.
Фотки с Сербии прикладываю в посте📸
Пока это 3 день, поэтому, вероятно, дополню после поездки и мб напишу про Сербию отдельный пост (в рамках какой-нибудь конкретной темы). Кстати, если что-то интересно — пишите в комментарии, вполне это может перерасти в пост.
А вообще, иногда лучший способ провести праздники — позволить себе тишину и неспешность, хотя я тот ещё любитель покутить.
А как вы проводите свои праздники?
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤30🔥21😍13
✈️ Tax Free в путешествиях: как вернуть бабки с покупок и не проебаться
Думал, про что написать с Сербии — и, под конец поездки тема сама пришла, мы вспомнили о возможности возврата НДС после покупок, которой и воспользовались, поэтому я решил рассказать о tax free что это и как им воспользоваться и вернуть себе бабки после трат за границей.
С этой темой я сталкивался еще раньше, когда ездил в США, и вот в крайний день в Сербии мы тоже про это вспомнили — как раз вовремя.
Коротко, что это вообще такое
Tax Free — это возможность вернуть НДС с покупок, при выезде из страны, в которой они были приобретены (должен быть нерезидентом).
В Сербии, например:
*️⃣ минимальная сумма чека для Tax Free — от 6 000 динар (+- 4.8к рублей)
*️⃣ действует не на все товары
ставка НДС в Сербии 20%/10%/0% также, в зависимости от товара.
PS В каждой стране правила разные — перед поездкой лучше загуглить конкретно под страну.
Какие вообще бывают Tax Free❓
Глобально — 2 варианта:
1️⃣ Instant Tax Free
Ты показываешь паспорт прямо при покупке, и тебе сразу вычитают НДС из суммы.
Очень удобно, такое чаще встречается в Азии — в Японии точно есть.
2️⃣ Классический
Ты сначала платишь полную сумму, а потом уже занимаешься возвратом НДС. Такой вариант распространен в Европе.
Дальше разберем именно этот вариант (чеков можно оформлять несколько)
1️⃣ Купили вещи на >6к динар в одном чеке
2️⃣ Просим Tax Free Form на кассе
Кстати, как оказалось: не обязательно делать это день в день, мы вообще пришли за формой в последний день
При себе нужно иметь паспорт
Далее на кассе заполняют форму, к ней крепят чеки и далее ты выбираешь способ возврата: кэшом или на карту
От этого дальше будет зависеть сценарий.
Кстати, как обычно, у меня все прошло не без проблем - на этом этапе у меня не правильно заполнили форму. В итоге нашли вариант выхода из данной ситуации: сделали возврат покупки, пробили их заново, оформили новый Tax Free Form на новые чеки. Повезло, что вещи были с собой.
Если бы нет — могли быть проблемы.
Что дальше (если не instant, тк при нем просто показываем паспорт при покупке и нам вычитают НДС из стоимости).
3️⃣ При выезде из страны нужно заверить форму Tax Free у таможни
Условия к моменту выезда:
*️⃣ вещи не использованы
*️⃣ с бирками
*️⃣ желательно в коробке
Сам штамп ставят
*️⃣ после регистрации, но до паспортного контроля
*️⃣ либо прямо на регистрации просишь вызвать таможенника,
если планируешь сдать эти вещи в багаж
Там ставят штамп — и все, форма валидна.
4️⃣ Как дальше получить бабки❓
*️⃣ Наличкой в аэропорту
После паспортного контроля, в зоне вылета - в Сербии был отдельный магазик, где выдают кеш
Как обычно, тут не без проблем - я летел обратно ночью, а начинал этот магазин работать только с 6 утра)) В любом случае, возврат кэшем я не выбирал, но если выберите вы, посмотрите есть ли такой магазин/пункт при выезде из страны у вас и время его работы перед выбором возврата денег на этапе оформления формы.
*️⃣ При возврате в страну
В течение 1 года (иногда 3 месяца — зависит от страны).
Приходишь в магазин с формой — возвращают всю сумму НДС.
Есть вариант передать "штампованную" форму человеку, который планирует ехать в эту страну и он уже получит эти деньги и вернет тебе (или кинет, смотря кого попросил). У этого варианты есть свои минусы, тк нужен вариант кого то, кто едет в эту страну, либо самому планировать приезд, но в таком случае, ты сможешь вернешь всю сумму НДС (на примере чека - это 20%)
*️⃣ Посредники (как сделал я)
Я воспользовался Global Blue.
Как это работает:
*️⃣ загружаешь Tax Free Form в приложение
*️⃣ подтверждаешь штамп в таможне
*️⃣ через 1–3 дня приходит возврат на карту
ps статусы обновляются автоматически
Из явных минусов — возвращают не всю сумму НДС
из 20% по факту выходит примерно 10–15% но, за то быстро, в моем случае вернули 12%
Если всё сделать правильно — можно вернуть приятную сумму и закрыть вопрос без стресса, надеюсь кто-то сможет вернуть свою лавеху🍌
👇Пользовались ли tax free услугой?
@data_driven_bogdan
Думал, про что написать с Сербии — и, под конец поездки тема сама пришла, мы вспомнили о возможности возврата НДС после покупок, которой и воспользовались, поэтому я решил рассказать о tax free что это и как им воспользоваться и вернуть себе бабки после трат за границей.
С этой темой я сталкивался еще раньше, когда ездил в США, и вот в крайний день в Сербии мы тоже про это вспомнили — как раз вовремя.
Коротко, что это вообще такое
Tax Free — это возможность вернуть НДС с покупок, при выезде из страны, в которой они были приобретены (должен быть нерезидентом).
В Сербии, например:
ставка НДС в Сербии 20%/10%/0% также, в зависимости от товара.
PS В каждой стране правила разные — перед поездкой лучше загуглить конкретно под страну.
Какие вообще бывают Tax Free
Глобально — 2 варианта:
Ты показываешь паспорт прямо при покупке, и тебе сразу вычитают НДС из суммы.
Очень удобно, такое чаще встречается в Азии — в Японии точно есть.
Ты сначала платишь полную сумму, а потом уже занимаешься возвратом НДС. Такой вариант распространен в Европе.
Дальше разберем именно этот вариант (чеков можно оформлять несколько)
Кстати, как оказалось: не обязательно делать это день в день, мы вообще пришли за формой в последний день
При себе нужно иметь паспорт
Далее на кассе заполняют форму, к ней крепят чеки и далее ты выбираешь способ возврата: кэшом или на карту
От этого дальше будет зависеть сценарий.
Кстати, как обычно, у меня все прошло не без проблем - на этом этапе у меня не правильно заполнили форму. В итоге нашли вариант выхода из данной ситуации: сделали возврат покупки, пробили их заново, оформили новый Tax Free Form на новые чеки. Повезло, что вещи были с собой.
Если бы нет — могли быть проблемы.
Что дальше (если не instant, тк при нем просто показываем паспорт при покупке и нам вычитают НДС из стоимости).
Условия к моменту выезда:
Сам штамп ставят
если планируешь сдать эти вещи в багаж
Там ставят штамп — и все, форма валидна.
После паспортного контроля, в зоне вылета - в Сербии был отдельный магазик, где выдают кеш
Как обычно, тут не без проблем - я летел обратно ночью, а начинал этот магазин работать только с 6 утра)) В любом случае, возврат кэшем я не выбирал, но если выберите вы, посмотрите есть ли такой магазин/пункт при выезде из страны у вас и время его работы перед выбором возврата денег на этапе оформления формы.
В течение 1 года (иногда 3 месяца — зависит от страны).
Приходишь в магазин с формой — возвращают всю сумму НДС.
Есть вариант передать "штампованную" форму человеку, который планирует ехать в эту страну и он уже получит эти деньги и вернет тебе (или кинет, смотря кого попросил). У этого варианты есть свои минусы, тк нужен вариант кого то, кто едет в эту страну, либо самому планировать приезд, но в таком случае, ты сможешь вернешь всю сумму НДС (на примере чека - это 20%)
Я воспользовался Global Blue.
Как это работает:
ps статусы обновляются автоматически
Из явных минусов — возвращают не всю сумму НДС
из 20% по факту выходит примерно 10–15% но, за то быстро, в моем случае вернули 12%
Если всё сделать правильно — можно вернуть приятную сумму и закрыть вопрос без стресса, надеюсь кто-то сможет вернуть свою лавеху
👇Пользовались ли tax free услугой?
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤53👍41🔥35
Обзор собеседования
Продолжаем разбор собеседования в USETECH (Ч. 2). В первой части были SQL + Python задачки, их можно посмотреть тут. Во второй — теория, системное мышление и вопросы “на понимание”.
SQL
1️⃣ Что такое подзапрос
Запрос внутри запроса, может быть в SELECT, WHERE или FROM.
2️⃣ Коррелированный подзапрос
Подзапрос, который ссылается на внешнюю таблицу и фактически сравнивает строку с самой собой по условию.
3️⃣ CTE (WITH)
Подзапрос, вынесенный в отдельную временную таблицу для читаемости и переиспользования.
4️⃣ UNION vs UNION ALL
UNION — убирает дубликаты
UNION ALL — просто склеивает результаты
5️⃣ INTERSECT и EXCEPT
INTERSECT — строки, которые есть в обеих таблицах
EXCEPT — строки из первой, которых нет во второй
6️⃣ Работа с NULL (COALESCE)
COALESCE заполняет NULL первым ненулевым значением из списка аргументов.
7️⃣ Работа с датами
EXTRACT / DATE_PART — получить год, месяц
CAST или :: — приведение типов
8️⃣ Оконные функции
Считают агрегаты без схлопывания строк.
9️⃣ ROW_NUMBER / RANK / DENSE_RANK
ROW_NUMBER — уникальный номер
RANK — с пропусками
DENSE_RANK — без пропусков
1️⃣ 0️⃣ PIVOT / UNPIVOT
Транспонирование таблицы: строки ↔️ колонки.
Python / Pandas
1️⃣ 1️⃣ list vs tuple
list — изменяемый
tuple — неизменяемый
1️⃣ 2️⃣ Почему NumPy быстрее циклов
Векторизованные операции выполняются на уровне C, а не Python.
1️⃣ 3️⃣ Что такое векторизация
Операции сразу над массивом, а не поэлементно.
1️⃣ 4️⃣ Если данные не помещаются в память
Читать и обрабатывать чанками.
1️⃣ 5️⃣ Работа с большими файлами (chunks)
Чтение и запись по частям, без загрузки всего в память.
1️⃣ 6️⃣ Parquet
Колоночный формат хранения, компактный и быстрый для аналитики.
1️⃣ 7️⃣ loc vs iloc
loc — по меткам
iloc — по индексам
1️⃣ 8️⃣ Типовой пайплайн в Pandas
read → describe → чистка → трансформации → EDA → сохранение
1️⃣ 9️⃣ merge vs concat
merge — аналог JOIN
concat — склейка по строкам или колонкам (аналог UNION)
Статистика
2️⃣ 0️⃣ Корреляция
Мера связи между числовыми переменными, от −1 до 1.
2️⃣ 1️⃣ Пирсон vs Спирмен
Пирсон — линейная связь
Спирмен — ранговая
2️⃣ 2️⃣ Почему корреляция ≠ причинность
Показывает связь, но не объясняет влияние.
2️⃣ 3️⃣ ДИ
Диапазон, в котором с заданной вероятностью лежит истинное значение параметра.
2️⃣ 4️⃣ Интерпретация 95% ДИ
В 95% случаев интервал накрывает истинное значение.
2️⃣ 5️⃣ Среднее / медиана / мода
Среднее — сумма / количество
Медиана — центральное значение
Мода — самое частое
2️⃣ 6️⃣ Почему медиана устойчивее
Меньше чувствительна к выбросам.
БД и архитектура
2️⃣ 7️⃣ SMP vs MPP
SMP — один узел
MPP — параллельные вычисления на сегментах
2️⃣ 8️⃣ PostgreSQL vs Greenplum
Postgres — SMP, строковое хранение
Greenplum — MPP, распределённые вычисления
2️⃣ 9️⃣ Почему Greenplum быстрее
Параллельные вычисления на сегментах.
3️⃣ 0️⃣ Дистрибуция данных
Распределение строк по сегментам.
3️⃣ 1️⃣ Data skew
Неравномерное распределение данных → самый медленный сегмент тормозит весь запрос.
3️⃣ 2️⃣ ClickHouse — плюсы и минусы
Плюсы: колоночное хранение, быстрые агрегации
Минусы: слаб для OLTP, частых JOIN и INSERT
3️⃣ 3️⃣ Data Lake
Хранилище файлов/ сырые данные, дешёвое, без строгой схемы.
Инфа / DE
3️⃣ 4️⃣ Docker vs VM
Контейнеры шарят ОС → легче и быстрее
VM — отдельная ОС → тяжелее
3️⃣ 5️⃣ Dockerfile
Инструкция сборки контейнера из слоёв.
3️⃣ 6️⃣ Порядок слоёв в Dockerfile
Влияет на кэширование и скорость сборки.
3️⃣ 7️⃣ Как уменьшить Docker-образ
Slim / Alpine образы, меньше слоёв, правильный порядок RUN.
3️⃣ 8️⃣ Docker Compose
YAML-файл для запуска нескольких контейнеров и их сети.
3️⃣ 9️⃣ Airflow
Инструмент оркестрации пайплайнов.
4️⃣ 0️⃣ DAG
Граф задач с зависимостями.
4️⃣ 1️⃣ Kafka
Брокер сообщений для стриминга данных.
4️⃣ 2️⃣ Producer / Consumer / Topic / Partition
Producer пишет в topic
Consumer читает из партиций
4️⃣ 3️⃣ Consumer Group
Группа консьюмеров, каждый читает свою партицию.
4️⃣ 4️⃣ At-least-once / At-most-once / Exactly-once
At-least-once — возможны дубли
At-most-once — возможны потери
Exactly-once — ровно один раз (самый сложный)
@data_driven_bogdan
Продолжаем разбор собеседования в USETECH (Ч. 2). В первой части были SQL + Python задачки, их можно посмотреть тут. Во второй — теория, системное мышление и вопросы “на понимание”.
SQL
Запрос внутри запроса, может быть в SELECT, WHERE или FROM.
Подзапрос, который ссылается на внешнюю таблицу и фактически сравнивает строку с самой собой по условию.
Подзапрос, вынесенный в отдельную временную таблицу для читаемости и переиспользования.
UNION — убирает дубликаты
UNION ALL — просто склеивает результаты
INTERSECT — строки, которые есть в обеих таблицах
EXCEPT — строки из первой, которых нет во второй
COALESCE заполняет NULL первым ненулевым значением из списка аргументов.
EXTRACT / DATE_PART — получить год, месяц
CAST или :: — приведение типов
Считают агрегаты без схлопывания строк.
ROW_NUMBER — уникальный номер
RANK — с пропусками
DENSE_RANK — без пропусков
Транспонирование таблицы: строки ↔️ колонки.
Python / Pandas
list — изменяемый
tuple — неизменяемый
Векторизованные операции выполняются на уровне C, а не Python.
Операции сразу над массивом, а не поэлементно.
Читать и обрабатывать чанками.
Чтение и запись по частям, без загрузки всего в память.
Колоночный формат хранения, компактный и быстрый для аналитики.
loc — по меткам
iloc — по индексам
read → describe → чистка → трансформации → EDA → сохранение
merge — аналог JOIN
concat — склейка по строкам или колонкам (аналог UNION)
Статистика
Мера связи между числовыми переменными, от −1 до 1.
Пирсон — линейная связь
Спирмен — ранговая
Показывает связь, но не объясняет влияние.
Диапазон, в котором с заданной вероятностью лежит истинное значение параметра.
В 95% случаев интервал накрывает истинное значение.
Среднее — сумма / количество
Медиана — центральное значение
Мода — самое частое
Меньше чувствительна к выбросам.
БД и архитектура
SMP — один узел
MPP — параллельные вычисления на сегментах
Postgres — SMP, строковое хранение
Greenplum — MPP, распределённые вычисления
Параллельные вычисления на сегментах.
Распределение строк по сегментам.
Неравномерное распределение данных → самый медленный сегмент тормозит весь запрос.
Плюсы: колоночное хранение, быстрые агрегации
Минусы: слаб для OLTP, частых JOIN и INSERT
Хранилище файлов/ сырые данные, дешёвое, без строгой схемы.
Инфа / DE
Контейнеры шарят ОС → легче и быстрее
VM — отдельная ОС → тяжелее
Инструкция сборки контейнера из слоёв.
Влияет на кэширование и скорость сборки.
Slim / Alpine образы, меньше слоёв, правильный порядок RUN.
YAML-файл для запуска нескольких контейнеров и их сети.
Инструмент оркестрации пайплайнов.
Граф задач с зависимостями.
Брокер сообщений для стриминга данных.
Producer пишет в topic
Consumer читает из партиций
Группа консьюмеров, каждый читает свою партицию.
At-least-once — возможны дубли
At-most-once — возможны потери
Exactly-once — ровно один раз (самый сложный)
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
❤38🔥31 20 6👍1👏1
This media is not supported in your browser
VIEW IN TELEGRAM
Хорошего окончания рабочей недели!
И немного юморка вам в придачу — чтобы никто такое безобразие вам в mr не предлагал!
@data_driven_bogdan
И немного юморка вам в придачу — чтобы никто такое безобразие вам в mr не предлагал!
@data_driven_bogdan
❤29🤣20🔥13🥰7👍4👏4
Обзор собеседования (Ч.1)
Компания: Dodo brands
Вилка: +-350 net
Должность: Дата аналитик
Формат: Удаленный
Этапы собеседования:
HR – Тех. собес (внутренний) – Хуево кукуево созвонов с кем только можно – Offer
Грейд: Middle + / Senior
Дата собеседования: декабрь 2025
Небольшое предисловие перед обзором тех собеса. На самом деле, вторая половина декабря выдалась очень насыщенной на собеседования - их было у меня просто не нормально много, как и сообщений от хрок. Кто бы что не говорил о том, что это уже не сезон и все кто мог ушли на фриз, есть такое ощущение, что те, кто не ушли на фриз еще больше заинтересованы в этот момент в найме. Предполагаю это связано в том числе с тем, что команды с потребностями заинтересованы растратить свой бюджет к концу когда, чтобы им его не подрезали с учетом того, что они его не затратили в "достаточном" виде в текущем. Что такое "достаточный" вид каждый ответственный за бюджет трактует как ему кайф - цель одна, в некст году хотя бы не меньше. (могу быть не прав)
SQL, Python и немного статистического мышления
Технический блок: SQL + Python
1️⃣ 60-day retention по когортам (SQL)
Необходимо посчитать 60-day retention по факту покупок пользователей
orders (order_id, user_id, order_date)
В ответе должна быть выведена след. таблица:
- cohort_month (Первый день месяца первой покупки,
- cohort_size (Общее количество новых покупателей в этом месяце)
- retention_60d (Процент повторно купивших в течение 60 дней)
Решение:
2️⃣ Клиенты с суммарным весом покупок > 2 кг (Python)
Посчитать клиентов, у которых за последний месяц суммарный вес покупок больше 2 кг.
SALES: client_id, date, sku, cnt
DICT: sku (товар), weight (вес в кг)
Решение:
3️⃣ Реализация дисперсии (Python)
Написать функцию для расчёта несмещенной выборочной дисперсии.
Решение:
Важно не перепутать population и sample variance (ну и помнить конечно, что такое дисперсия в целом — мера разброса значений относительно среднего, если на человеческом)
Несмещенная выборочная дисперсия отличается от обычной тем, что в знаменателе не n, а на n − 1 это корректирует смещение оценки дисперсии генеральной совокупности
4️⃣ Анализ распределения (статистика)
Дана выборка клиентов с тратами и нужно было проанализировать распределение
60 клиентов — 0 ₽
38 клиентов — 1000–1500 ₽
2 клиента — 10 000 ₽
Коротко:
*️⃣ распределение с heavy tail
*️⃣ среднее будет сильно смещено выбросами
*️⃣ медиана и перцентили устойчивее
В некст части больше упора будет на статистику и потом будет 3ая очень интересная часть про переговоры
🍌 Подпишись и поддержи канал бустом
@data_driven_bogdan
Компания: Dodo brands
Вилка: +-350 net
Должность: Дата аналитик
Формат: Удаленный
Этапы собеседования:
HR – Тех. собес (внутренний) – Хуево кукуево созвонов с кем только можно – Offer
Грейд: Middle + / Senior
Дата собеседования: декабрь 2025
Небольшое предисловие перед обзором тех собеса. На самом деле, вторая половина декабря выдалась очень насыщенной на собеседования - их было у меня просто не нормально много, как и сообщений от хрок. Кто бы что не говорил о том, что это уже не сезон и все кто мог ушли на фриз, есть такое ощущение, что те, кто не ушли на фриз еще больше заинтересованы в этот момент в найме. Предполагаю это связано в том числе с тем, что команды с потребностями заинтересованы растратить свой бюджет к концу когда, чтобы им его не подрезали с учетом того, что они его не затратили в "достаточном" виде в текущем. Что такое "достаточный" вид каждый ответственный за бюджет трактует как ему кайф - цель одна, в некст году хотя бы не меньше. (могу быть не прав)
SQL, Python и немного статистического мышления
Технический блок: SQL + Python
Необходимо посчитать 60-day retention по факту покупок пользователей
orders (order_id, user_id, order_date)
В ответе должна быть выведена след. таблица:
- cohort_month (Первый день месяца первой покупки,
YYYY-MM-01)- cohort_size (Общее количество новых покупателей в этом месяце)
- retention_60d (Процент повторно купивших в течение 60 дней)
Решение:
-- определяем дату первой покупки каждого юзера
WITH first_order AS (
SELECT
user_id,
MIN(order_date) AS first_order_date
FROM orders
GROUP BY 1
),
-- находим юзеров, которые сделали хотя бы 1 покупку после первой в теч. 60 дней
returns AS (
SELECT DISTINCT
f.user_id
FROM first_order f
JOIN orders o
ON f.user_id = o.user_id
AND o.order_date > f.first_order_date
AND o.order_date <= f.first_order_date + INTERVAL '60 day'
)
-- считаем стату, left'ом оставляем юзеров без повторной покупки
SELECT
DATE_TRUNC('month', f.first_order_date)::date AS cohort_month,
COUNT(f.user_id) AS cohort_size,
ROUND(
COUNT(r.user_id) * 1.0 / COUNT(f.user_id),
2
) AS retention_60d
FROM first_order f
LEFT JOIN returns r USING (user_id)
GROUP BY 1;
Посчитать клиентов, у которых за последний месяц суммарный вес покупок больше 2 кг.
SALES: client_id, date, sku, cnt
DICT: sku (товар), weight (вес в кг)
Решение:
-- ласт месяц берем
last_month = sales[
sales["date"] >= sales["date"].max() - pd.DateOffset(months=1)
]
-- дикс мерджим с фактом
df = last_month.merge(dict_, on="sku", how="inner")
-- считаем тотал вес (штуки на справочный вес)
df["total_weight"] = df["cnt"] * df["weight"]
-- агрегация сум. веса по каждому клиенту и отбор по общему весу >2 кг
result = (
df.groupby("client_id", as_index=False)["total_weight"]
.sum()
.query("total_weight > 2")
)
-- список client_id
clients = result["client_id"].tolist()
Написать функцию для расчёта несмещенной выборочной дисперсии.
Решение:
def var(a: list):
mean = sum(a) / len(a)
return sum((x - mean) ** 2 for x in a) / (len(a) - 1)
Важно не перепутать population и sample variance (ну и помнить конечно, что такое дисперсия в целом — мера разброса значений относительно среднего, если на человеческом)
Несмещенная выборочная дисперсия отличается от обычной тем, что в знаменателе не n, а на n − 1 это корректирует смещение оценки дисперсии генеральной совокупности
Дана выборка клиентов с тратами и нужно было проанализировать распределение
60 клиентов — 0 ₽
38 клиентов — 1000–1500 ₽
2 клиента — 10 000 ₽
Коротко:
В некст части больше упора будет на статистику и потом будет 3ая очень интересная часть про переговоры
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥45🦄25 13❤8👏5 5👍4
Я наконец-то пересобрал всю информацию с телетайпа и вынес ее на сайт — теперь все про менторство и другие виды моих услуг по data компактно собрано в одностраничнике.
На сайте описал форматы работы со мной:
— разовые консультации
— мок-собеседования
— работа с резюме/легендой
— менторство с доведением до оффера
В сфере data уже больше 3х лет. Работал в финтехе, FMCG и ритейле — Альфа-Банк, ВТБ, Philip Morris, Магнит, а также стартапах. Постоянно выхожу на рынок, много собеседуюсь и коммуницирую с кандидатами, поэтому хорошо понимаю актуальные требования рынка и ожидания работодателей.
Работа со мной — это про системную работу, психологию и понимание рынка, без громких обещаний и иллюзий быстрых результатов при отсутствии должных усилий.
Если ты давно думал разобраться, куда и как дальше расти в аналитике — возможно, тебе зайдет.
Если нет — просто оставляю ссылку, вдруг когда-нибудь надумаешь или поделишься с другом, который думает о вкате.
Вопросы, как обычно, можно задать в личке.
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥33👍21❤16👏8 4🦄3🥰2🤯2
Data Driven / Bogdan Ivanov pinned «🍌 Апдейт Я наконец-то пересобрал всю информацию с телетайпа и вынес ее на сайт — теперь все про менторство и другие виды моих услуг по data компактно собрано в одностраничнике. 👉 https://datadrivenbogdan.com На сайте описал форматы работы со мной: — разовые…»
С развитием аналитической архитектуры крупные компании перестают укладываться в модель «одна большая СУБД на всё» (Greenplum, Oracle, Teradata). По мере зрелости появляются доменные команды, новые источники данных, стриминг, ML-пайплайны, разные типы нагрузок — и архитектура естественным образом начинает распределяться. Часть данных хранится в S3, часть — в CH, часть — в постгре, что-то приходит через Kafka, где-то до сих пор живёт Hive или старый DWH. Всё это — нормальная эволюция сложной системы.
Проблема в другом: бизнесу по-прежнему нужен единый SQL-доступ ко всем данным, дешёвое масштабируемое хранение, контроль над инфраструктурой и отсутствие жёсткой привязки к одному вендору или облаку. И вот в этот момент модель «центральная СУБД» перестаёт быть устойчивой.
Возникает архитектурный разрыв: данные уже распределены, а инструменты доступа к ним — нет. Нужен слой, который объединит всё это без миграции в одну гигантскую систему, и при этом даст управляемость уровня DWH поверх Data Lake.
И именно здесь появляется связка Trino + Apache Iceberg.
Что это за связка и почему именно она
Trino — это распределённый SQL движок. Он не хранит данные и не является хранилищем в классическом смысле. Это слой выполнения запросов, который может ходить в разные источники (СУБД) через коннекторы и исполнять один SQL поверх разных систем одновременно.
Ключевая идея Trino — federation. Один SQL может одновременно читать таблицу в S3, сделать join с CH, подтянуть данные из GP и агрегировать всё в одном запросе. Без физической миграции данных в единое DWH. Trino становится универсальным SQL-слоем компании.
Apache Iceberg — это не движок, а формат таблиц для Data Lake. Он добавляет к object storage (S3 / GCS / ADLS) управляемость уровня DWH. Iceberg хранит данные в columnar-форматах (Parquet / ORC / Avro), а поверх них — слой метаданных и snapshot-модель.
В чём его разница от обычного S3
Коротко — в управлении. Iceberg даёт:
PS архитектуру Iceberg'а разберем в следующем посте подробнее.
Фактически Iceberg превращает папку с файлами в полноценную аналитическую таблицу.
Почему именно они в связке
Iceberg отвечает за хранение, консистентность и метаданные.
Trino отвечает за вычисления и доступ.
Iceberg гарантирует, что таблица атомарна и согласована. Trino умеет эффективно читать manifest-файлы, отсекать лишние файлы на этапе планирования, делать file pruning и выполнять запросы распределённо. Это архитектурно совместимые компоненты.
Если упростить архитектуру: Object Storage → Iceberg (табличный слой) → Trino (SQL-слой) → BI / аналитика / ML
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥19👍9❤7 6🦄2
1🔥25👍12 7❤🔥4 2❤1
Causal Inference: как оценивать эффект, когда A/B — не вариант (Ч. 2)
В первой части разобрали DiD, сегодня разберем еще один популярный инструмент — Propensity Score Matching (далее PSM).
Идея PSM'a - мы не сравниваем всех подряд из теста и контроля, а сначала стараемся сделать группы максимально сопоставимыми по характеристикам,
и только потом считаем эффект.
Если DiD — это про сравнение трендов, то PSM — это про подбор группы.
В чем проблема, которую решает PSM❓
Представим ситуацию:
➖ акция показана только лояльным клиентам
➖ новая функция доступна только premium подписчикам
➖ пользователи сами приняли решение участвовать
В этом случае назначение treatment не случайно, то есть попадание в тест зависит от характеристик X (доход, активность, средний чек и тд).
P(T=1 | X) ≠ P(T=1)
Значит, если просто сравнить разницу средних, то мы получим смещенную оценку, где разница может быть вызвана не воздействием, а тем, что группы изначально разные.
E[Y | T=1] − E[Y | T=0]
Формальная логика
Для каждого объекта i существуют два потенциальных исхода:
Yᵢ(1) — если получил воздействие
Yᵢ(0) — если не получил воздействие
Мы наблюдаем только один из них. Второй — контрфакт.
Нас интересует: ATT = E[Y(1) − Y(0) | T=1]
Средний эффект на тех, кто получил treatment.
Проблема в том, что E[Y(0) | T=1] мы не наблюдаем.
Мы не знаем, что было бы с тестовой группой без воздействия.
PSM как раз пытается оценить этот контрфакт, только вместо того чтобы сравнивать всех из теста со всеми из контроля,
мы для каждого участника теста ищем максимально похожего участника из контроля.
Как это работает❓
Вместо того чтобы матчить по десяткам признаков X напрямую, мы считаем:
p(X) = P(T=1 | X) - это вероятность попадания в treatment при данных характеристиках.
Теорема Розенбаума и Рубина говорит, что если выполняется предпосылка unconfoundedness, то достаточно сбалансировать группы по ps, а не по всему вектору признаков X.
По сути, мы схлопываем многомерную проблему в одно число.
Как строится PSM на практике
1️⃣ Выбираем две группы
Собираем датасет из тестовой группы (получила воздействие) и контроль (не получила воздействие)
ps ниже в комментах напишу пример
Контроль желательно существенно больше теста (часто в 3–5 раз), чтобы алгоритму было из чего подбирать пары.
2️⃣ Формируем признаки X. (aov, arppu, freq, трафик, регион, также, например, метрики на товар X и так далее)
Критично: все признаки считаются только по данным ДО момента воздействия.
3️⃣ Строим модель для оценки propensity score (PS).
Это обычная бинарная классификация: таргет — T (0/1), признаки — X,
только нам нужно не само значение таргета, а скор по клиенту для попадания в таргет
Для этого используются ML модели для проблемы классификации: лог. регрессия, град бустинг, рандом форест и тд.
Важно: нам нужна хорошая калибровка вероятностей, если модель идеально различает тест и контроль — это тревожный сигнал => группы могут быть слишком разными, те нужно подбирать другую КГ.
4️⃣ Выполняем matching (M).
Для каждого объекта из treatment ищем объект из control с максимально близким ps. (иногда допускается matching с повторениями)
Популярные методы:
— Nearest Neighbor
— k-ближайших соседей
— Caliper (ограничение на |Δp| ≤ ε) и др
5️⃣ Считаем эффект
Далее мы получили подмножество test и control'а, которым подобралась пара друг другаи теперь мы можем сравнить эффект:
ATT ≈ E[Y | T=1] − E[Y | T=0, matched]
Тем самым, мы заменили ненаблюдаемый контрфакт на максимально похожий на контрфакт объекты.
Вот так вот работает PSM, надеюсь объяснил понятно, пару дополнений оставлю в комментах.
❤️🔥 Подписывайтесь и поддержите канал бустом
↗️ Менторю и помогаю выйти на оффер
❓ Сталкивались с PSM? Если да, расскажите про ваши кейсы
@data_driven_bogdan
В первой части разобрали DiD, сегодня разберем еще один популярный инструмент — Propensity Score Matching (далее PSM).
Идея PSM'a - мы не сравниваем всех подряд из теста и контроля, а сначала стараемся сделать группы максимально сопоставимыми по характеристикам,
и только потом считаем эффект.
Если DiD — это про сравнение трендов, то PSM — это про подбор группы.
В чем проблема, которую решает PSM
Представим ситуацию:
В этом случае назначение treatment не случайно, то есть попадание в тест зависит от характеристик X (доход, активность, средний чек и тд).
P(T=1 | X) ≠ P(T=1)
Значит, если просто сравнить разницу средних, то мы получим смещенную оценку, где разница может быть вызвана не воздействием, а тем, что группы изначально разные.
E[Y | T=1] − E[Y | T=0]
Формальная логика
Для каждого объекта i существуют два потенциальных исхода:
Yᵢ(1) — если получил воздействие
Yᵢ(0) — если не получил воздействие
Мы наблюдаем только один из них. Второй — контрфакт.
Нас интересует: ATT = E[Y(1) − Y(0) | T=1]
Средний эффект на тех, кто получил treatment.
Проблема в том, что E[Y(0) | T=1] мы не наблюдаем.
Мы не знаем, что было бы с тестовой группой без воздействия.
PSM как раз пытается оценить этот контрфакт, только вместо того чтобы сравнивать всех из теста со всеми из контроля,
мы для каждого участника теста ищем максимально похожего участника из контроля.
Как это работает
Вместо того чтобы матчить по десяткам признаков X напрямую, мы считаем:
p(X) = P(T=1 | X) - это вероятность попадания в treatment при данных характеристиках.
Теорема Розенбаума и Рубина говорит, что если выполняется предпосылка unconfoundedness, то достаточно сбалансировать группы по ps, а не по всему вектору признаков X.
По сути, мы схлопываем многомерную проблему в одно число.
Как строится PSM на практике
Собираем датасет из тестовой группы (получила воздействие) и контроль (не получила воздействие)
ps ниже в комментах напишу пример
Контроль желательно существенно больше теста (часто в 3–5 раз), чтобы алгоритму было из чего подбирать пары.
Критично: все признаки считаются только по данным ДО момента воздействия.
Это обычная бинарная классификация: таргет — T (0/1), признаки — X,
только нам нужно не само значение таргета, а скор по клиенту для попадания в таргет
Для этого используются ML модели для проблемы классификации: лог. регрессия, град бустинг, рандом форест и тд.
Важно: нам нужна хорошая калибровка вероятностей, если модель идеально различает тест и контроль — это тревожный сигнал => группы могут быть слишком разными, те нужно подбирать другую КГ.
Для каждого объекта из treatment ищем объект из control с максимально близким ps. (иногда допускается matching с повторениями)
Популярные методы:
— Nearest Neighbor
— k-ближайших соседей
— Caliper (ограничение на |Δp| ≤ ε) и др
Далее мы получили подмножество test и control'а, которым подобралась пара друг другаи теперь мы можем сравнить эффект:
ATT ≈ E[Y | T=1] − E[Y | T=0, matched]
Тем самым, мы заменили ненаблюдаемый контрфакт на максимально похожий на контрфакт объекты.
Вот так вот работает PSM, надеюсь объяснил понятно, пару дополнений оставлю в комментах.
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
2👍24 17❤11🦄4
This media is not supported in your browser
VIEW IN TELEGRAM
Вчера в приседе 150 сел
Потихоньку растем!😎
На выходных напишу про causal impact
Всем хороших выходных и с окончанием рабочей недели!👨💻
@data_driven_bogdan
Потихоньку растем!
На выходных напишу про causal impact
Всем хороших выходных и с окончанием рабочей недели!
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤5👍5🔥5😍1
Causal Inference: как оценивать эффект, когда A/B — не вариант (Ч. 3)
Сегодня разберем еще один популярный инструмент — Causal Impact (далее CI), он же синтетический контроль на основе прогноза
Идея метода
Мы строим прогноз того, как вела бы себя метрика, если бы изменения не произошло, и сравниваем этот прогноз с фактом (в факте изменения есть).
То есть CI — это способ построить контрфакт через модель временного ряда. => Эффект = Факт − Прогноз
В чем задача, которую решает CI❓
Представим ситуацию:
➖ фичу раскатили сразу на всю аудиторию
➖ маркетинговую кампанию запустили без теста
➖ минимальную сумму заказа внедрили на весь маркетплейс
➖ регулятор изменил ставку, тариф, правило
Контрольной группы нет, но нам нужно ответить на вопрос:
👉 «А что было бы с метрикой, если бы изменений не произошло?»
Как работает CI❓
1️⃣ Берём длинную историю данных до вмешательства
2️⃣ Обучаем модель, которая учится на: тренде, сезонности, внешних факторах (если есть ковариаты)
3️⃣ Строим прогноз на период изменения — пытаемся прогнозировать ситуацию в "мире", где вмешательства как будто бы не было
4️⃣ Сравниваем прогноз с фактическими значениями
Если факт стабильно выходит за ДИ прогноза — скорее всего, изменение действительно повлияло.
Что происходит “под капотом”❓
Классическая реализация CI основана на BSTS (Bayesian Structural Time Series) — это класс байесовских моделей временных рядов.
Модель строит распределение прогнозов и оценивает неопределенность, из которого затем считается эффект и доверительные интервалы.
Реализация в R — пакет CausalImpact (Google), в Python есть — pycausalimpact.
Но можно применять любые модели временных рядов, например:
➖ ARIMA / SARIMA (statsmodels)
➖ Prophet (prophet)
➖ модели из darts, gluonts, pmdarima
➖ ML с лагами (XGBoost, LightGBM)
Также можно реализовать логику вручную через statsmodels, sklearn или любые TS-фреймворки.
Принцип один: обучаем модель на pre-period → прогнозируем period → сравниваем прогноз и факт.
Если в модели используются ковариаты (внешние факторы), они должны:
➖ хорошо коррелировать с целевой метрикой
➖ не быть напрямую затронуты вмешательством
Иначе модель может “встроить” эффект внутрь прогноза
и занизить итоговую оценку.
Когда метод применим❓
➖ Есть длинная история наблюдений ДО вмешательства
➖ Модель хорошо прогнозирует pre-period (нет систематического смещения, разумный ДИ)
ps По хорошему ошибка прогноза на pre-period должна быть существенно меньше предполагаемого эффекта.
➖ Можно подобрать адекватные ковариаты
➖ Вмешательство произошло в конкретный момент времени
Ограничения метода
➖ Нет контроля за внешними событиями, если они совпали по времени
➖ Сложно отделить эффект нескольких вмешательств
Пример
ЦБ резко поднял ключевую ставку — мы хотим понять, как это повлияло на объем кредитов. Контрольной страны нет, группы сравнивать не с кем.
Мы строим модель по данным до повышения ставки, прогнозируем объем кредитов без повышения
и сравниваем с фактом.
Разница — и есть оценка эффекта.
❤️🔥 Подписывайтесь и поддержите канал бустом
↗️ Менторю и помогаю выйти на оффер
❓ Все ли понятно? А если работали с Causal Impact — расскажите про ваши кейсы👇
@data_driven_bogdan
Сегодня разберем еще один популярный инструмент — Causal Impact (далее CI), он же синтетический контроль на основе прогноза
Идея метода
Мы строим прогноз того, как вела бы себя метрика, если бы изменения не произошло, и сравниваем этот прогноз с фактом (в факте изменения есть).
То есть CI — это способ построить контрфакт через модель временного ряда. => Эффект = Факт − Прогноз
В чем задача, которую решает CI
Представим ситуацию:
Контрольной группы нет, но нам нужно ответить на вопрос:
👉 «А что было бы с метрикой, если бы изменений не произошло?»
Как работает CI
Если факт стабильно выходит за ДИ прогноза — скорее всего, изменение действительно повлияло.
Что происходит “под капотом”
Классическая реализация CI основана на BSTS (Bayesian Structural Time Series) — это класс байесовских моделей временных рядов.
Модель строит распределение прогнозов и оценивает неопределенность, из которого затем считается эффект и доверительные интервалы.
Реализация в R — пакет CausalImpact (Google), в Python есть — pycausalimpact.
Но можно применять любые модели временных рядов, например:
Также можно реализовать логику вручную через statsmodels, sklearn или любые TS-фреймворки.
Принцип один: обучаем модель на pre-period → прогнозируем period → сравниваем прогноз и факт.
Если в модели используются ковариаты (внешние факторы), они должны:
Иначе модель может “встроить” эффект внутрь прогноза
и занизить итоговую оценку.
Когда метод применим
ps По хорошему ошибка прогноза на pre-period должна быть существенно меньше предполагаемого эффекта.
Ограничения метода
Пример
ЦБ резко поднял ключевую ставку — мы хотим понять, как это повлияло на объем кредитов. Контрольной страны нет, группы сравнивать не с кем.
Мы строим модель по данным до повышения ставки, прогнозируем объем кредитов без повышения
и сравниваем с фактом.
Разница — и есть оценка эффекта.
@data_driven_bogdan
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥7❤5 3
