Мир аналитика данных
СтатистикаПишу о рабочих буднях аналитика. Тут много рабочего кода, прохождение собеседований и еще много всего полезного. https://www.linkedin.com/in/valeriashuvaeva Автор канала: @Valeria_Shuvaeva
- Последний пост
- 13 авг.
- Последнее чтение
- 12:42
- Постов за неделю
- 2
- Всего постов
- 21
- Тип
- открытый
- Язык
- русский
- В каталоге с
- 12 авг.
- 1/24сутки в ленте
- 406
- 1/48двое суток
- 465
- 1/72трое суток
- 501
Оценка по просмотрам недавних постов: пост набирает почти всё за первые сутки.
Посты
Похоже, единственный человек, который может годами ничего не менять и все равно вывозить, это Дэдпул. Остальным полезно время от времени проводить карьерный чекап: понять, насколько востребованы ваши навыки, соответствует ли зарплата рынку и какие инструменты сегодня ждут от аналитиков. В этом поможет hh.ru.
📊 A/B-тест: что делаем после окончания эксперимента? Считаем итоги! 🚀 Как вы можете заметить у меня в канале реально много полезного кода. Что ж продолжим эту тенденцию! 😄 В прошлом посте я показала, как до запуска теста рассчитать минимальный детектируемый эффект (MDE) для бинарной метрики (конверсии). Мы выяснили, что при базовой конверсии ~4.94% и выборке 50 000 пользователей мы сможем «увидеть» только изменения больше 10.99% относительного прироста. А теперь давайте смоделируем реальный тест – сгенерируем данные, где в тестовой группе конверсия реально выше, и посмотрим, что получится. Спойлер: наш фактический эффект окажется достаточно большим, чтобы его обнаружить при таком размере выборки. А статистическую значимость мы проверим отдельно. 😉 🎯 Настройки эксперимента Общий размер выборки: 51 500 пользователей (разбивка 50/50) Базовая конверсия в контроле: 4,9% (control_conversion = 0.049) Ожидаемая конверсия в тесте: 5,5% (test_conversion = 0.055) Относительный прирост: (0,055 – 0,049) / 0,049 ≈ 12,2% Это тот эффект, который мы хотим обнаружить. Но сможет ли тест его увидеть? Давайте проверим! 🧬 Генерируем синтетические данные Фиксируем seed=42 для воспроизводимости. import numpy as np import pandas as pd from scipy.stats import chisquare, norm from statsmodels.stats.proportion import proportions_ztest import math n = 51500 control_conversion = 0.049 test_conversion = 0.055 np.random.seed(42) # Генерируем ID и метку группы (50/50) active_user_id = np.arange(1, n + 1) test_id = np.random.binomial(1, 0.5, size=n) df = pd.DataFrame({'active_user_id': active_user_id, 'test_id': test_id}) # Генерируем конверсии отдельно для каждой группы df['is_converted'] = 0 df.loc[df['test_id'] == 0, 'is_converted'] = np.random.binomial(1, control_conversion, size=(df['test_id'] == 0).sum()) df.loc[df['test_id'] == 1, 'is_converted'] = np.random.binomial(1, test_conversion, size=(df['test_id'] == 1).sum()) df.head() 🔍 Шаг 1. Проверяем разбивку на группы (SRM) Перед тем как смотреть на конверсию, сначала проверяем, правильно ли пользователи распределились между группами. Почему это важно? Если вместо ожидаемых 50/50 мы получили, например, 60/40, результат эксперимента уже вызывает вопросы. Ожидаем, что в каждой группе будет примерно по 25 750 пользователей. from scipy.stats import chisquare control = df[df['test_id']==0]['active_user_id'].nunique() test = df[df['test_id']==1]['active_user_id'].nunique() # Ожидаемое распределение (50/50) total = control + test print('В тесте присвоены номера групп для:',total,'устройств') expected = total / 2 # Критерий хи-квадрат chi2_stat, p_value = chisquare([control, test], f_exp=[expected, expected]) print(f"Хи-квадрат статистика: {chi2_stat:.4f}") print(f"P-value: {p_value:.6f}") # Вывод решения alpha = 0.05 if p_value < alpha: print("SRM обнаружен — тест ненадёжен.") else: print("SRM не обнаружено. Разбивка на группы правильная.") Результат: Контроль: 25767, Тест: 25733 Хи-квадрат: 0.0224, p-value: 0.8809 ✅ Разбивка корректна – можно продолжать. 📈 Шаг 2. Фактические конверсии – и вот сюрприз! Считаем реальные доли (в жизни то, что получилось после двух-трех недель томительного ожидания, у нас - то что нагенерировалось после np.random.binomial: control_users = len(df[df['test_id'] == 0]) test_users = len(df[df['test_id'] == 1]) control_conv = df[df['test_id'] == 0]['is_converted'].sum() test_conv = df[df['test_id'] == 1]['is_converted'].sum() cr_control = control_conv / control_users cr_test = test_conv / test_users uplift = (cr_test / cr_control - 1) * 100 effect_pp = (cr_test - cr_control) * 100 print(f'Control users: {control_users}') print(f'Control conversions: {control_conv}') print(f'CR control: {cr_control:.2%}') print('==============================') print(f'Test users: {test_users}') print(f'Test conversions: {test_conv}') print(f'Test control: {cr_test:.2%}') print('==============================') print(f'Effect: +{effect_pp:.2f} п.п.') print(f'uplift: {uplift:.2f}%') Вывод (примерный, при seed=42): Control users: 25767 Control conversions: 1176 CR control: 4.56% =================================== Test users: 25733 Test conversions: 1407 Test control: 5.47% =================================== Effect: +0.90 п.п. 📈 uplift: 19.8% Почему контроль не 4,9%, а 4,56%? Это нормально. Когда мы задаём: control_conversion = 0.049 мы не говорим: «В контроле будет ровно 4,9% конверсий». Мы говорим: «Каждый пользователь имеет вероятность 4,9% сконвертироваться». А np.random.binomial() генерирует случайную выборку из этого распределения. Поэтому фактическая конверсия в конечной выборке может немного отличаться от заданной. Это ровно то, что происходит и в реальном эксперименте: ожидаемый baseline и фактический baseline — не обязательно одно и то же! И здесь у нас: ожидали: 4,9% получили: 4,56% А в тесте: ожидали: 5,5% получили: 5,47% Именно с фактическими значениями мы дальше и работаем. 🧮 Шаг 3. Считаем фактический эффект. Проводим z‑тест для двух пропорций Теперь главный вопрос: Можем ли мы считать разницу между 4,56% и 5,47% статистически значимой? Для двух независимых конверсий используем z-тест для двух пропорций. stat, p_value = proportions_ztest(count=[test_conv, control_conv], nobs=[test_users, control_users], alternative='two-sided') print(f'z-stat: {stat:.4f}') print(f'p-value: {p_value:.10f}') z-stat: 4.6981 p-value: 0.0000026 p_value < 0.05 поэтому отвергаем нулевую гипотезу.🎉 Тест прокрасился! Эффект статистически значим. 🔁 Шаг 4. Сравниваем с MDE, пересчитанным после теста на фактическом baseline и размере выборки И вот здесь возвращаемся к тому, с чего начали. MDE показывает, какой минимальный эффект способен обнаружить наш тест при заданных параметрах. После завершения эксперимента мы можем дополнительно пересчитать его, используя: - фактический baseline - 4,56%; - фактический общий размер выборки - 51 500. Это не «новый правильный MDE», а дополнительная оценка чувствительности теста на фактических данных. n_total = control_users + test_users mde_abs, mde_rel, lower, upper = mde_for_conversion(cr_control, n_total) # Фактический эффект в процентных пунктах effect_pp = (cr_test - cr_control) * 100 print(f"Конверсия в контроле: {cr_control:.2%}") print(f"Конверсия в тесте: {cr_test:.2%}") print(f"Фактический эффект: +{effect_pp:.2f} п.п.") print("MDE: ±", round(mde_abs*100, 2), "п.п. - абсолютный (", round(mde_rel, 2), "% - относительный)") print(f'uplift: {uplift:.2f}%') if uplift > mde_rel: print("✅ Наш эффект превышает MDE") else: print("❌ Эффект меньше MDE") Получим: Конверсия в контроле: 4.56% Конверсия в тесте: 5.47% Фактический эффект: +0.90 п.п. MDE: ± 0.52 п.п. - абсолютный ( 11.29 % - относительный) uplift: 19.80% ✅ Наш фактический эффект (19.80%) превышает MDE(11,29%) Это означает, что эффект такого масштаба находится в пределах чувствительности теста. 🏁 Итого Мы прошли полный путь от сырых данных до вывода: 1️⃣ Проверили SRM → разбивка 50/50 корректна 2️⃣ Посчитали фактический CR → 4,56% vs 5,47% 3️⃣ Посчитали эффект → +0,9 п.п. / +19,80% 4️⃣ Проверили статистическую значимость → p-value < 0,05 5️⃣ Сравнили эффект с MDE → 19,80% > 11,29% И чтобы не путаться, еще раз: MDE и статистическая значимость отвечают на разные вопросы. MDE: Насколько большим должен быть эффект, чтобы наш тест имел достаточную чувствительность его обнаружить? p-value: Достаточно ли данных, чтобы считать наблюдаемую разницу статистически значимой? 📎 Вот ноутбук, чтобы Вы смогли поэкспериментировать.
📊 А/Б-тесты. Считаем MDE до того, как запустим тест. Хочу показать вам рабочий код для расчета минимального детектируемого эффекта (MDE) - это самый маленький истинный эффект, который тест сможет признать значимым. 🎯 На каком примере будем считать? Покажу на примере конверсии (бинарная метрика). Её часто ставят как приемочную метрику. Она просто считается и легко интерпретируется. Например, вы хотите поменять что-то в приложении – дизайн какой-то карточки, ее рекомендательную систему или просто сделали что-то еще из улучшений. И вы можете рассчитать конверсию в добавление в корзину или открытие какого-то блока или прям в саму покупку. ⭐Пусть наша приемочная метрика - конверсия пользователей в заказ. Нам нужны два простых поля на каждого активного пользователя: ● active_user_id - кто заходил в приложение за последние 2 недели; ● order_flg - совершил ли он целевое действие (1 - да, 0 - нет). ✅ Генерируем синтетический датасет на 50 000 пользователей с базовой конверсией 5%: n = 50000 baseline_conversion = 0.05 np.random.seed(42) active_user_id = np.arange(1, n + 1) order_flg = np.random.binomial(1, baseline_conversion, size=n) df = pd.DataFrame({'active_user_id': active_user_id,'order_flg': order_flg}) df.head() Смотрим на фактические цифры: active_users = df['active_user_id'].nunique() users_with_order = df[df['order_flg']==1]['active_user_id'].nunique() share_users_with_order = users_with_order / active_users print('Активные клиенты:', active_users) print('Клиенты с заказом:', users_with_order) print('Конверсия в заказ:', round(share_users_with_order * 100, 2), '%') ✅Формула расчёта MDE Я использую стандартный подход на основе z-критерия для двух пропорций Это означает, что мы предполагаем: при больших выборках распределение разности конверсий между тестом и контролем стремится к нормальному (ЦПТ). В функции n_total — это суммарное количество пользователей в обеих группах. То есть при n_total = 50 000 в каждой группе будет по 25 000 человек. def mde_for_conversion(baseline, n_total, alpha=0.05, power=0.80, two_sided=True): """ baseline - конверсия в контроле n_per_group - размер каждой группы """ n_per_group = n_total / 2 p = baseline # Квантили нормального распределения if two_sided: z_alpha = norm.ppf(1 - alpha/2) else: z_alpha = norm.ppf(1 - alpha) z_beta = norm.ppf(power) se = math.sqrt(p * (1 - p) / n_per_group + p * (1 - p) / n_per_group) mde_abs = (z_alpha + z_beta) * se mde_rel = mde_abs / baseline * 100 lower = baseline - mde_abs upper = baseline + mde_abs return mde_abs, mde_rel, lower, upper Считаем mde n_total = int(active_users) #всего пользователей для обеих групп baseline_conversion =share_users_with_order mde_abs, mde_rel, lower, upper = mde_for_conversion(baseline_conversion, n_total) print("\n" + "=" * 60) print("MDE ДЛЯ КОНВЕРСИИ (n_total=" + format(n_total, ",") + "):") print("=" * 60) print("Baseline:", round(baseline_conversion*100, 2), "%") print("MDE: ±", round(mde_abs*100, 2), "п.п. (", round(mde_rel, 2), "% )") print("Диапазон:", round(lower*100, 2), "% –", round(upper*100, 2), "%") 📈 Смотрим на вывод и делаем выводы 😀 MDE ДЛЯ КОНВЕРСИИ (n_total=50,000): Baseline: 4.94 % MDE: ± 0.54 п.п. ( 10.99 % ) Диапазон: 4.4 % – 5.48 % Как это читать? 1️⃣ Сейчас базовая конверсия - 4.94%. 2️⃣ Мы сможем статистически значимо зафиксировать изменение, только если конверсия в тесте выйдет за пределы коридора 4.4% – 5.48%. 3️⃣Это означает, что тест «увидит» только прирост от 10.99% относительно базового значения. Если ваше дизайн-решение даёт +5% к конверсии (а это очень даже неплохо!), то при 50 000 пользователях тест не сможет это доказать. 😭 Вы получите p-value > 0.05 и решите, что эффекта нет, хотя он есть. Но чтобы «поймать» +5%, нужно кратно увеличивать выборку, например держать тест не две недели, а три. 📎 Вот ноутбук, чтобы Вы смогли поэкспериментировать. Если нравятся такие посты с реальным кодом и разбором A/B, то ставьте огонечки 🔥😀
Ребята, привет! 👋 Хочу рассказать вам про штуку, которая Вам понравится. У Паши Бухтика (No Data No Growth) через 2 дня стартует новый поток по A/B. И формат в этот раз необычный 👀 Раньше аналитики и продакты учились отдельно. А тут он собрал их на одном потоке с общими обсуждениями и совместными домашками. И мне эта идея прям откликнулась. Если бы уже не проходила у него курс, то пошла бы сейчас точно 🔥 Потому что в реальной работе A/B – это всегда общая ответственность продакта и аналитика. И чем хуже они понимают друг друга, тем чаще тест превращается в формальность, а не в инструмент решений. Знакомо, да? 😄 🎯 Что заберут продакты: За 7 недель практики научатся говорить с аналитиком на одном языке, грамотно ставить задачи, видеть слабые места в дизайне теста до запуска, не подкручивать методологию под свои гипотезы и защищать решения перед руководством. 📊 Что заберут аналитики: Программа шире – кроме общей части есть отдельные занятия: ✔️ сплитование; ✔️ симуляции Монте-Карло; ✔️ ratio-метрики и стат. критерии; ✔️ множественное тестирование; ✔️ A/B без A/B, ускорение, сетевой эффект. И то, чему почти нигде не учат – объяснять выводы A/B нетехническим людям и видеть, как продакт реально использует их в решениях. Часто именно это и отделяет мидла от сеньора 👍 🔥 А самое интересное – практики: Они проходят вместе в мини-группах: ➡️ Продакты начинают понимать, как думают аналитики; ➡️ Аналитики – как устроена продуктовая логика. Редкий случай, когда обе стороны учатся друг у друга прямо в процессе, а не после ✨ 🎓 А если вы уже были на прошлых потоках. Можно прийти снова: досдать домашки, освежить материал, попробовать новый формат. Паша обещал спецусловия. Старт уже 5 июня. Заявку можно оставить тут: 👉 Для аналитиков: https://nodatanogrowth.com/product-analyst-ab-testing 👉 Для продактов: https://nodatanogrowth.com/product-manager-ab-testing На аналитическом треке осталось всего 4 места. Так что лучше написать сегодня, чем в июле жалеть, что не успел 😉
📚 Посмотрела хэндбук по A/B-тестированию от команды Trisigma (платформа экспериментов от Авито). Он оказался прям очень неплохим. Там внутри собрана хорошая база, которую полезно освежить даже тем, кто уже давно работает с экспериментами и метриками 👀 И конечно можно повторить основы статистики: что такое дисперсия, стандартное отклонение, стандартная ошибка, типы распределения данных. Там прям хорошо разобрано. А то нет, нет, да и забывается какая-то формула или информация если это что-то прям не часто используется. Что конкретно есть внутри: 🟢основы A/B-тестов и типы экспериментов 🟢как формулировать гипотезы 🟢классификация метрик: goal / proxy / guardrail / debug 🟢OEC и закон Кэмпбелла 🟢ошибки в экспериментах и как не словить ложные выводы 🟢атомарный дизайн метрик 🟢ну и введение в матстат: дисперсия, стандартное отклонение, распределения, ЦПТ и т.д. (расчеты на примерах) Понравилось, что всё объясняется на нормальных продуктовых примерах, даже расчеты внутри есть 🧮 Забрать можно в боте @trisigma_avito_bot за подписку на их канал. Реклама. ООО "Авито Тех".
видео или голосовое, без подписи
видео или голосовое, без подписи
видео или голосовое, без подписи
🔥 Вчера побывала в офисе Яндекса на Digital day! Главная тема вечера - Яндекс Метрика. Поделюсь сухими фактами сначала: ✅ Что нового: - ИИ-помощник (уже в бета-версии - можно тестить 👀) - Можно смотреть средние показатели продаж по рынку, нужно только поставить галочку в настройках "Получить доступ к ответу по рынку" ✅ Ключевые инсайты (и где деньги 💰): - Как меняется аналитика под разные индустрии - Глубина разметки - куда копать, чтобы не тонуть в данных - Какие отчёты смотрят лидеры рынка в Метрике - Как измеряют вовлечённость - Где искать потери в данных и как их чинить ✅ Огонь-фишка, которую полезно изучить: В Метрику можно передавать данные e-commerce по client_id 📌 Это значит - отслеживать офлайн-выручку и связывать её с действиями на сайте. Кейс из METRO - рабочий и успешный 🔥 В общем, было объемно и интересно🔥 А еще получилось пообщаться с разными людьми - нетворкинг в силе 🤝 И да, несколько человек зашли в канал после встречи - спасибо, что вы здесь! 👏 А чтобы быть на связи плотнее, я добавила LinkedIn в описание. Жду в контактах! 🍕🍽 Ну и, конечно, вкусно покормили - тоже важная метрика мероприятия! 📎Спикеры обещали прислать презу со всеми ссылками и темами. Как пришлют - прикреплю здесь!
Свежее исследование рынка аналитиков 2025 от NEWHR. 7 главных трендов рынка: 📈1️⃣ Зарплаты у многих выросли, но рынок уже не летит вверх Две трети аналитиков получили рост дохода, но чаще это было не из-за смены работы, а из-за индексации или повышения грейда. В целом рост по рынку - меньше 10%, тогда как раньше это скорее были 15–20% в год. То есть история «перешёл в новую компанию и сразу +30%» уже не выглядит нормой. 💸 2️⃣Деньги стали главным фактором Интересные задачи и развитие всё ещё важны, но зарплата впервые вышла на первое место и для удержания, и при выборе нового оффера. Очень показательный сдвиг: рынок стал более прагматичным. 🌍 3️⃣Российский и международный рынки всё сильнее расходятся Привлекательность зарубежных компаний для аналитиков из РФ за два года упала на 31%. Плюс снижается интерес к переезду: люди чаще ориентируются на тот рынок, где уже работают. ⏳4️⃣ Искать работу стало дольше 77% аналитиков находят работу за 3 месяца, но год назад таких было 81%. А доля тех, кто ищет до 6 месяцев, выросла с 53% до 61%. То есть рынок не рухнул, но стал плотнее: конкуренция выше, а найм медленнее. 🏆5️⃣Авито - лидер по привлекательности в качестве возможного работодателя. Хуже всех репутация у VK и Сбера. 🤖 6️⃣AI и ML уже не “бонус”, а новый must-have За год доля аналитиков, которые работают с ML-сервисами, выросла с 14% до 22%. А развивать этот навык хотят 41,5% респондентов. Похоже, для аналитиков это уже не «что-то дополнительное», а всё больше часть профессии. 🏢 7️⃣Грейд влияет не только на зарплату От него зависят ещё и скорость поиска работы, свобода выбора локации и компании. Сеньоры, принципалы и тимлиды в целом чувствуют себя на рынке увереннее. Ну и еще разное: ✔️ Какие задачи решают аналитики сегодня ✔️ Локации и планы аналитиков на переезд ✔️ На какие компании и в каком формате работают ✔️ Как менялись зарплаты аналитиков в течение 2025 года ✔️ Сколько они получают сегодня в зависимости от специализации и грейда ✔️ Откуда пришли в профессию и как планируют развиваться дальше ✔️ ТОП и Анти-ТОП российских компаний по мнению аналитиков ✔️ Что ценят в аналитической культуре ✔️ На какие конференции ходят и за кем из экспертов следят ▶️ Вот Сайт с полными результатами
Я про вас не забыла и вот принесла кое-что интересное. Телегу замедляют, но я остаюсь тут и не хочу предлагать вам куда-то переходить. Поддержите огонечками, что вы тут и вам это по прежнему нужно! Сегодня хочу показать удобный SQL-прием для A/B тестов: как смотреть метрику сразу по нескольким двухнедельным периодам и не размечать каждый интервал руками. Так легче заметить, метрика стабильна или скачет от периода к периоду. В этом примере считаем такую метрику: доля пользователей, которые открыли карточку товара из целевого блока, среди всех пользователей, открывших карточку товара за период. Логика очень простая: ➡️ берем всех уникальных пользователей, открывших карточку товара ➡️ отдельно считаем тех, кто пришел в карточку из блока Подборка для вас ➡️ делим второе на первое и получаем долю Сгенерировала df_product_events(event_ts, user_id, event_name, event_payload). import duckdb import pandas as pd query = """ with events as ( select date_add( date '2026-02-02', INTERVAL (cast(14 * floor(date_diff('day', date '2026-02-02', cast(event_ts as date)) / 14.0) as integer)) DAY) as period_start, user_id, json_extract_string(event_payload, '$.source_block') as source_block from df_product_events where event_ts >= timestamp '2026-02-02 00:00:00' and event_ts < timestamp '2026-03-16 00:00:00' and event_name = 'product_card_open' and nullif(trim(user_id), '') is not null ) select period_start, period_start + INTERVAL 13 DAY as period_end, count(distinct user_id) as users_total, count(distinct case when source_block = 'Подборка для вас' then user_id end) as users_from_target_block, round( 100.0 * count(distinct case when source_block = 'Подборка для вас' then user_id end) / count(distinct user_id), 2 ) as share_from_target_block from events group by 1, 2 order by 1 """ result = duckdb.query(query).to_df() Самая важная часть здесь - это расчет period_start (каждому событию назначается начало его двухнедельного периода) Что здесь происходит: 1️⃣Берем опорную дату, с которой хотим начать нарезку периодов 2️⃣Через date_diff считаем, сколько дней прошло от нее до события 3️⃣ Делим это число на 14.0, чтобы понять, в какой двухнедельный интервал попало событие. 4️⃣Через floor округляем вниз, чтобы получить номер двухнедельного интервала 5️⃣ потом умножаем на 14 и прибавляем к опорной дате через date_add В итоге каждое событие автоматически попадает в нужное окно. Например, если опорная дата - 2026-02-02, то: событие от 2026-02-03 попадет в период с началом 2026-02-02 событие от 2026-02-14 тоже попадет туда же а событие от 2026-02-16 уже уйдет в следующий период Дальше все обычно: по каждому периоду считаем всех уникальных пользователей карточки товара, отдельно - пользователей из целевого блока, и получаем долю. Мне нравится этот способ тем, что он очень легко масштабируется. Не нужно руками прописывать периоды через case when, не нужно собирать отдельные запросы под каждое окно. Один раз задали опорную дату и длину периода - и дальше запрос сам аккуратно раскладывает события как надо.👍 Если нужно смотреть метрику не по 14 дням, а, например, по трем неделям, меняется одно число и все. Удобно же! В ноутбуке я еще отдельно оформила формулировку метрики в виде плашки зеленого цвета - так что можно заглянуть не только за SQL, но и за кодом такой вставки. Отделять метрику от метрики в огромных скриптах очень удобно!
Поздравляю всех девушек с 8 марта! 🌷 Пусть будет больше радости, сил, интересных задач и чтобы жизнь почаще радовала хорошими результатами… желательно со статистической значимостью 😄✨ Я тут немного выпала из канала. Но у меня есть сразу несколько поводов для радости: ✅ Закончился испытательный срок на работе 🎉 Три месяца пролетели очень быстро! Задачи интересные, команда отличная! Работаем над улучшением приложения Азбуки Вкуса! 📱Кто ещё не скачал (Москвичи и Питерцы) - обязательно скачивайте. Там реально много прикольного и вкусного! А если найдете там какие-то проблемы... - ну вы теперь знаете кому писать 😜 ✅ 🎤 Ещё сходила на стендап (уже второй раз) Очень необычный опыт: сидишь прямо возле сцены, атмосфера супер живая. Поняла, почему люди туда ходят не один раз 😄 ✅ Ну и сам праздник! Три дня отдыха - это вам не шутки. Тут отдыхать надо со всей ответственностью 😄 А вы как проводите длинные выходные? 😊 Фото приветствуются. Да, знаю, телега уже не та… но фоточки всё ещё поднимают метрики настроения 📈 И вот вам A/B-тест на выходные(ну две недели такой тест не дали пока держать 😂: 🅰️ Группа A (контроль) - отдых 😄 👍 - жмём, если вы за этот вариант 🅱️ Группа B - ещё больше отдыха 😎 🔥 - если считаете, что отдыхаете ещё сильнее чем обычно. Посмотрим, кто победит 📊
Ребята, привет! 👋 У Паши Бухтика (No Data No Growth) 2 марта стартует пятый поток по A/B-тестированию! 📣 Вот его пост с подробностями: https://t.me/nodatanogrowth/1038 Я проходила этот курс в том году - было круто и очень полезно! 👍 Следующий поток будет только осенью. Короче, очень рекомендую🚀🚀🚀 Учеба - это вложение в себя, которое окупается! Ссылка на его сайт
Удобная функция UNNEST в PostgreSQL для работы Всем привет! Решила поделиться тут с вами одной полезной функцией, которую как раз недавно использовала на работе. У нас есть массив устройств у пользователей. Но если мы хотим: ✔️посчитать устройства ✔️сделать join ✔️агрегировать ✔️считать DISTINCT то массив нужно разложить в строки. Представим, что у нас есть данные, где у пользователя несколько устройств лежат в массиве. Было: 1 строка = массив устройств Должно быть: несколько строк с пользователем = одно устройство в строке Сначала создадим это прямо в Python import duckdb import pandas as pd df = pd.DataFrame({ "user_id": [1, 2, 3], "device_ids": [ ["dev_a", "dev_b"], ["dev_c"], ["dev_d", "dev_e", "dev_f"] ] }) И вот тут-то мы разворачиваем массив через UNNEST query = """ SELECT user_id, d AS device_id FROM df CROSS JOIN UNNEST(device_ids) AS t(d) ORDER BY 1, 2 """ result = duckdb.query(query).to_df() Разберем необычную конструкцию CROSS JOIN UNNEST(device_ids) AS t(d) Что вообще означает AS t(d)? 🟢UNNEST(device_ids) - разворачивает массив 🟢t - имя временной таблицы 🟢d - имя колонки внутри неё После этого d — обычная колонка, с которой можно работать как с любой другой. Главное потом случайно не задвоить метрику когда будем соединять таблицу с таблицей заказов, например. orders = pd.DataFrame({ "user_id": [1, 2], "revenue": [100, 200] }) Теперь делаем join после UNNEST: query = """ SELECT df.user_id, d AS device_id, o.revenue FROM df CROSS JOIN UNNEST(device_ids) AS t(d) LEFT JOIN orders o ON df.user_id = o.user_id ORDER BY 1, 2 """ result2 = duckdb.query(query).to_df() User 1 имел revenue = 100 Но теперь эта сотка появилась два раза! 😱 Поэтому нужно быть внимательным и понимать для чего мы это делаем. ❌ Нельзя после этого просто делать SUM(revenue) по этой таблице - выручка продублируется на каждое устройство и итог “раздуется”. ✅ Но зато расшив девайсы и приджойнив user-level выручку мы можем посмотреть её рядом на строках устройств. 💡 Зачем это может быть нужно? Например: сколько устройств у платящих пользователей есть ли различия между single-device и multi-device users сколько выручки приходится на пользователей с 3+ устройствами Мы не делим revenue по устройствам. Мы просто используем её как атрибут пользователя. P.S Кстати, я перешла на VS Code - мне нравится. Красивый же черный фон, да? Ну и удобно видеть в структуре файлы проекта.
🔬Тут прислали исследование. Смотрим, изучаем. Я тоже где-то там есть 😄🔬 📁 300+ экспертов и каналов, за которыми следят аналитики В 2025 году мы в NEWHR завершили сбор данных для нашего ежегодного исследования рынка аналитиков. Такие исследования позволяют в динамике наблюдать за тем, как меняется профессия, задачи, зарплаты аналитиков, их амбиции, желанные и нежеланные компании для работы и многое другое. Сейчас мы обрабатываем результаты, и уже готовы поделиться с вами первыми инсайтами. А именно — рейтингом экспертов отрасли и каналами, которые читают и смотрят наши респонденты-аналитики. Выборка респондентов в этом году — 1493 человека! 🔗 Полный список экспертов-аналитиков Что вы найдёте на лендинге: ➖ Рейтинги ТОП-15 экспертов и ТОП-30 Telegram-каналов, интересных аналитикам Они разделены специализациям: отдельно для продуктовых, маркетинговых, дата-, веб- и BI-аналитиков и отдельно для системных и бизнес-аналитиков — потому что предпочтения отличаются. ➖ Полные списки экспертов (100+), Telegram-каналов (130+), подкастов и YouTube-каналов которые аналитики находят интересными Telegram-каналы для удобства разделены по темам: аналитика, обучение и карьера, BI/UX/Data Viz, Data Engineering и разработка, ML/DS, Product Managment, продуктовая и HR аналитика. Отдельно мы выделили блок экспертов, которых читаем сами — именно к ним мы обратились за информационной поддержкой. Благодарим всех, кто помог собрать такую выборку 💙 Полные результаты исследования мы опубликуем весной, следите за обновлениями!
Тренд на «универсалов»: кто будет востребован в аналитике в 2026? Эра «просто аналитиков», которые умеют только собирать таблицы, проходит. Сейчас заметен четкий сигнал рынка: компаниям нужны специалисты полного цикла — те, кто понимает путь данных от сбора до принятия бизнес-решения. Знания таблиц и базового SQL больше недостаточно, если вы хотите получать приглашения на собеседования и выигрывать конкуренцию у других кандидатов. Чтобы не тонуть в бесконечном списке требований работодателей, важно сфокусироваться на самом нужном. Илья Ковалёв (Senior-аналитик Dodo Brands) и Наталья Рожкова (HR-эксперт) проведут прямой эфир о том, как выжить и вырасти в этой среде 👍 🟠На примерах из Dodo посмотрим, как вести задачу от сырых данных до рабочего дашборда. 🟠Почему универсальные навыки стали преимуществом и как джуну соответствовать этому фильтру. 🟠Советы от HR, как доработать резюме и отклики, чтобы «пробивать» автоматические фильтры и внимание рекрутеров. 💬 Всем зарегистрировавшимся Simulative пришлют полезный материал — карту компетенций аналитика данных со всеми нужными инструментами для освоения. 🔗 Регистрируйтесь на бесплатный вебинар
видео или голосовое, без подписи
видео или голосовое, без подписи
видео или голосовое, без подписи
видео или голосовое, без подписи