Я твой продукт анализировал – Telegram
Я твой продукт анализировал
1.69K subscribers
103 photos
9 videos
2 files
51 links
Про продуктовую аналитику в IT, мысли, методы анализа и алгоритмы. Всё, что ты хотел знать, но стеснялся спросить.

ЛС тут: @de_kn
Download Telegram
📌 Аналитическая система с единорогами и пони

Мне довелось поработать со многими командами, и у каждой была какая-то своя система хранения и работы с данными. Тут я не про принципы, а про инфраструктуру. И вот чёт недавно я задумался об идеальной, на мой взгляд, системе.

Почти всё я выбрал исключительно потому что нравится 🙂 Я не дата-инженер, поэтому что-то может быть не оптимально, но это мой комфортный стек работы со стороны ПА.

Получился вот такой наборчик:

🔵Данные с бэка, про платежи, регистрации, данные юзеров и вот это вот всё я бы хранил в Postgre. Потому что надёжная и неубиваемая система. Как та самая нокия. А для бэка это главный критерий, на мой взгляд, т.к. тут самые чувствительные данные.

🔵Фронтовый трекер для событий — вот тут хз, раньше был крутой опенсорсный Segment. Весил мало, загрузку не импрувил, user-based. Не умел ничего кроме трека ивентов, но с этой задачей справлялся прекрасно. Вот какой-то такой аналог бы. Может в сторону своей разработки бы смотрел. Ключевой параметр — легкость.

🔵ETL-процессинг исключительно самописный, потому что это не дорого (в масштабах остального) и всегда можно тонко настроить. А для внезапных витринок сюда же прикручиваем DBT.

🔵Кликстрим по фронту складывал бы в колоночную бд, т.к. в запросе обычно нужно мало полей на много строк, а не наоборот. Тут бы зашёл Clickhouse или Vertica. Работал с кликстримом в строковых бд, запрос на >5 млн строк вообще не реально выгрузить. Но вроде как CH на масштабах проигрывает Вертике (но это не точно, слышал такое где-то).

🔵По BI тут два инструмента. В качестве основы для постоянных бордов Shiny (жестко, но стабильно, быстро и функционал ограничен только твоей фантазией). А для временных бордов и черновиков Redash (простой, быстрый, гибкости для времянок достаточно).

🔵Как working-area / хранилище артефактов, рисерчей, результатов экспериментов и т.д. для аналитиков поднял бы DataLore.

Интересно, насколько это вообще жизнеспособная схема со стороны инженерии, но работать аналитику в такой — одно удовольствие 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥1
Интересно, зайдут тут SQL-сниппеты, или не нужны никому, потестим 🙂

Вот довольно популярный сниппет, когда нужно найти что-то наиболее частое, например с каких девайсов обычно сидит юзер, или какой язык использует чаще и т.д.

Я это делаю через подсчёт строк и отбора топ-1 по каждому юзеру. Для примера, нужно найти самый популярный девайс юзера:

select user_id,
device as most_used_device
from (select user_id,
device,
row_number() as over(partition by user_id order by user_id, count(*) desc) as rn
from database
group by 1, 2) as t1
where rn = 1


Логика простая, сначала выстраиваем поюзерный список девайсов с сортировкой по бОльшему количеству чего-нибудь, нумеруем строки, а потом отрезаем все строки, что не 1.

Тут весь прикол в count(*), сюда засовывать нужно то, что логически подойдёт, если это ивенты, то лучше их на дни попилить, чтобы мы не девайсы по количеству ивентов тащили 🙂

#сниппеты
24🔥8👍4
Перебирал тут диск, нашёл старые консоли. Вот, например, прикольный. Это запрос в кликхаус из алертов Redash, который обновлялся каждый час и отправлялся в Slack, тегая ответственного, если срабатывало условие, когда байер тратил больше дневного капа.

Какие только костыли не выдумывали 😀

select if(length(slack_string) > 0, slack_string, 'OK') as slack_string
from (select arrayStringConcat(
arrayMap(x - > toString(x),
groupArray(if(to_alert = 'y', '<@user>\n', '') ||
'Campaign: ' || campaignName || '\n' ||
'Current cost: $' || toString(daily_cost) || '\n' ||
'Daily cap: $' || toString(daily_cap)
)),
'\n\n') as slack_string
from (select campaignName,
round(sum(daily_cost), 2) as daily_cost,
round(daily_cap, 2) as daily_cap,
case
when daily_cost >= toFloat64(daily_cap)
then 'y'
else 'n' end as to_alert
from (select campaign,
spot,
spot_id,
name as spot_name,
daily_cost as daily_cost,
daily_cap as daily_cap
from (select *
from (select campaign,
spot,
sum(cost) as daily_cost
from client.actions
where date = today()
and owner = '5fbb4d4b61d6e257153928a1'
group by 1, 2)

left join (select id as campaign,
daily_cap
from client.campaings
where owner_id = '5fbb4d4b61d6e257153928a1') using campaign)

left join (select spot_id,
spot_aid as spot,
name
from client.dictionary_spot
where name like '%opunder%') using spot
where name like '%_%')

left join (select campaignId as campaign,
campaignName
from client.dictionary_campaigns) using campaign
group by 1, 3)
where to_alert = 'y')
🤯8👍41
Зацените в какую красоту на выходных гоняли. Арбалетчиков расставить и готовый оборон пункт 🙂
🔥24👍2
📌 Обнаружение аномалий

Наверняка у всех, кто хоть как-то мониторит дневные метрики, есть дашборды с линейными графиками. Эти графики постоянно штормит, поэтому не всегда сразу понятно упала у нас конверсия и нужно всё бросать и искать причину, или это обычная волатильность метрики.

Есть много способов, как сделать графики более красноречивыми, один из них, пожалуй самый простой и распространённый — это обнаружение аномалий через плавающие доверительные интервалы. Разбираем на примере конверсий.

Кстати, про поиск аномалий иногда спрашивают на собесах, такой способ обычно ценят 🙂

Суть в следующем:

1️⃣ Мы выбираем окно, по которому будем “скользить” и на основе этого окна строим интервалы. Как базу можно взять неделю.

2️⃣ Исходя из предположения о нормальности, считаем скользящее среднее и отклонения, а на их основе задаём границы ДИ.

3️⃣ Накладываем интервалы на исходный график. Точки графика, выходящие за пределы ДИ уже сигнализируют о необычном поведении метрики. Да, не всегда там точно есть причина, но уже сильно понятнее когда пора напрячься, а когда всё ок 🙂

Предположение о нормальности тут справедливо, т.к. мы рассматриваем каждый отдельный день как выборку, а если допускать что в день происходит достаточно много конверсий, то в соответствии с ЦПТ средняя величина будет стремиться к нормальному распределению.


Реализация не влезает в пост, поэтому вынес в Gist. Код на R, но общий смысл там понятен, переписать на Python труда не составит 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥17👍42😐1
В твиттере на очередной круг вышла дискуссия о том, чем бы занимались айтишники, если бы за любую работу платили одинаково и выбирать можно то, к чему душа лежит. Я не могу выбрать между выращиванием оливок / крафтом масла или всё таки производством виски 🙂 и там и там тишина, покой, природа)

Кто куда после айтишечки двинет?
👍11🤔2
📌 Несмещённая дисперсия, степени свободы и почему же n-1 (1/2)

Уже второй день в чатиках мелькает вопрос “почему при оценке несмещённой дисперсии мы делим на n-1”.

Тема не самая простая и наглядная, но давай попробуем разобраться.

Для начала о дисперсии.

Дисперсия
— это мера оценки степени разброса или вариативности данных относительно среднего значения. Чтобы посчитать дисперсию в ГС, нужно:

🔵Вычислить среднее значение;

🔵 Вычислить разницу между каждым наблюдением и средним значением;

🔵Отклонение может быть в большую или меньшую сторону, поэтому каждое значение возводим в квадрат, чтобы избавиться от знаков;

🔵Сложить все получившиеся квадраты отклонений;

🔵Поделить их сумму на n (количество наблюдений).

Но если мы имеем дело с выборкой, а не с ГС, то делить нужно на n-1. А почему так?

Чтобы понять физический смысл этой операции, для начала нужно вспомнить концепцию степеней свободы.

Допустим, мы с друзьями решили скинуться на подарок. Нам нужна сумма в 100р., нас четверо. Первый принёс 30, второй 20, третий 25. Зная это и целевую сумму, последний должен принести ровно 25. Это не он так решил, а у него просто уже не осталось свободы выбора, т.к. он ограничен итоговой суммой.

В этом примере в начале у каждого из трёх первых друзей есть “свобода” принести любую сумму. Они могут решить, сколько именно денег внести, не зная, сколько внесут другие. Т.е. для первых трёх друзей есть три степени свободы, потому что каждый из них может внести разную сумму независимо от остальных.

Однако, когда дело доходит до последнего человека, у него уже нет такой же степени свободы, он должен соответствовать заранее определённому плану.

Т.е. если подытожить, в нашей выборке только 3 независимых наблюдения, а последнее всегда зависит от остальных и итоговой цели.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍154🔥2
📌 Несмещённая дисперсия, степени свободы и почему же n-1 (2/2)

В контексте расчёта дисперсии у нас похожая история, но вместо итоговой суммы в 100р, все наши переменные взаимосвязаны через среднее значение выборки. Т.е. зная среднее и все значения, кроме последнего, мы можем его легко посчитать.

Когда мы используем n-1, мы никак не увеличиваем или не уменьшаем количество независимых наблюдений, но мы начинаем корректно учитывать тот факт, что последнее всегда зависимо. Таким образом мы расширяем степень вариативности, и закладываем идею о том, что мы точно не знаем какой разброс в ГС, т.е. математически признаём этот факт.

Если мы говорим о необходимости ориентироваться на независимые наблюдения, мы подчеркиваем важность базового принципа независимости в статистическом анализе.

Использование n-1 в расчёте дисперсии является частным проявлением этого принципа.

P.S. Если прям совсем грубо, то у нас есть требование к анализу, что там всё должно быть независимо. А тут блин, последнее число зависит от остальных. Надо его выпилить и всё будет ок 🙂 но фактически мы не знаем что есть последнее, зависит от того, с какой стороны считать, поэтому как будто в формуле задаём это автоматическое выпиливание. Но эт если совсем условно 🙂

#собесы
👍15🔥53
Приветики, теперь о действительно важных вещах! У меня тут произошло незапланированное обновление винды, пока устанавливаю всякий софт, захотелось обновить и оформление R Studio. Выбрал 3 фаворита, никак не определюсь 😅

1-й Дефолтный Tommorow Night 80s (пусть будет 🤷‍♀️)

2-й Дефолтный Material (🤷‍♂️)

3-й Кастомный Dracula, нагло спёртый с тёмной темы PyCharm (🤷)
🤷16🤷‍♀12🤷‍♂8
📌 R или Python (1/2)

Я уже писал про выбор языка, но тогда это было совсем поверхностно. Сейчас я хочу чуть более комплексно сравнить эти два мощных инструмента аналитиков.

Оба языка прекрасно справляются с задачами обработки и анализа данных, визуализацией, и задачами машинного обучения. На базовом уровне одно и то же. А вот в деталях у них уже видны расхождения.

Если ты находишься на этапе выбора языка, я приведу тут наиболее сильные стороны обоих, а ты уж смотри сам что тебе нужнее.

Аргументы в пользу R:

🔵Пакеты для стат. анализа: R изначально разрабатывался статистиками для статистиков, поэтому тут огромный набор пакетов, специально для стат. анализа. Да, в Python они тоже есть, но многие перекочевали из R почти без изменений, тот же statsmodels это сборка базовых функций R, pandas вдохновлён dplyr, а seaborn старается перенести питонистам декларативный подход из ggplot2. Так как R больше популярен в научной среде, новые методы и техники сначала появляются здесь.

🔵Визуализация: ggplot2 считается одним из лучших пакетов для создания сложных графиков. Он вышел в 2005 и активно развивается. Сейчас он способен создать почти любую визуализацию, ограничен только фантазией автора.

🔵Анализ временных рядов: Пакеты forecast и tseries пока, вроде как, являются наиболее полноценными инструментами для этой задачи. Они часто используются в эконометрике и фин. моделировании.

🔵CRAN: (Сеть архивов комплексных пакетов) крайне удобная штука, которая позволяет быстро найти пакет под любую аналитическую задачу или стат. метод. Обеспечивает высокую гибкость и модульность в развитии языка. Во всех статьях это один из главных аргументов в пользу R. Я с этим полностью согласен 🙂

🔵Интеграция с документами: Через R Markdown и Shiny можно интегрировать анализ данных куда угодно, никаких файлов ноутбуков — прямой импорт хоть в док, хоть в интерактивный апп.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍91
📌 R или Python (2/2)

Аргументы в пользу Python:

🔵ML и DL: Из-за TensorFlow, PyTorch и scikit-learn, Python считается стандартом для машинного и глубокого обучения. Мощно, быстро, качественно.

🔵NLP: Библиотеки NLTK, spaCy и transformers для обработки естественного языка намного мощнее аналогов R. Топ инструмент для чат-ботов, переводчиков или анализа текстов.

🔵Веб-разработка: Python поддерживает Django и Flask, поэтому задачи, которые требуют на выходе интерфейсов для взаимодействия с пользователями тут создавать тупо удобнее. В R это пытается делать Shiny, но он пока далёк от такого.

🔵Автоматизация: Тут R даже не пытается конкурировать, под задачи автоматизации там ничего сносного не завезли. Нет, он, конечно умеет в скриптинг, даже Airflow его поддерживает. Но шансы увидеть на проде скрипты автоматизации через R примерно такие же, как найти горшочек лепрекона.

🔵Интеграция с другими языками: Python в плане интеграции в разработку намного более гибкий, особенно полезно при разработке приложений, где анализ данных это не самоцель, а лишь часть большого приложения, требующего взаимодействия с базами данных, веб-сервисами и тд.

В целом, оба языка могут справиться с любыми аналитическими задачами, просто где-то удобнее один, а где-то другой.


Для исследований, стат. анализа, визуализации и публикаций материалов я бы смотрел в сторону R. И так уж совпало, что это стандартный набор задач продуктовой аналитики.

Python более интересен в первую очередь для DS, в этой сфере он является заслуженным стандартом. Для DA, скорее всего, выбор Python тоже более оправдан из-за задач автоматизации и контроля качества данных.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13
📌 Один из способов запроса воронки

В работе часто приходится анализировать какие-нибудь воронки или последовательности с условиями. Например юзер сделал то-то, потом вот это, а потом то. Есть миллион разных способов как собрать такой лог, но мне в последнее время нравится вот такой, можно сказать, сниппет, с использованием множественных cte. Он простой, кастомизируемый и достаточно надёжный в плане точности.

Вот как он может выглядеть на примере расчёта проходимости через авторизацию в приложении через смс. Основан на фронтовых ивентах, но это вообще не важно.

🔵В этом примере есть экран, страница или любой другой индикатор что юзер попал на страницу логина,

🔵потом жмякнул по авторизации через смс

🔵и успешно залогинился, попав на главную.

Логика простая, собираем отдельно каждый шаг, а потом склеиваем поюзерно с соблюдением таймингов — второй шаг после первого, третий за вторым и т.д. Я ещё добавил фильтр что это всё в один день. Но тут можно что угодно навешивать. Вообще можно независимо кастомить условия на любом шаге.

В итоге будет таблица, где NULL в датах это потери, т.е. юзер дропнулся. Дальше можно уже как угодно это агрегировать и делать что там было нужно.

Забирайте, пользуйтесь 🙂

# Собираем данные по первому шагу
with login as (
select user_id,
timestamp as login_screen_dt
from db
where date(timestamp) >= current_date - 30
and event = 'screen_view'
and screen_name = 'login'
),

# По второму
sms_screen as (
select user_id,
timestamp as sms_screen_dt
from db
where date(timestamp) >= current_date - 30
and event = 'screen_view'
and screen_name = 'sms'
),

# По третьему
home_page as (
select user_id,
timestamp as home_page_dt
from db
where date(timestamp) >= current_date - 30
and event = 'screen_view'
and screen_name = 'home_page'
)

# Склеиваем это всё
select ls.*,
ss.sms_screen_dt,
hp.home_page_dt
from login ls
left join sms_screen ss on ls.user_id = ss.user_id
and ls.login_screen_dt <= ss.sms_screen_dt
and date(ls.login_screen_dt) = date(ss.sms_screen_dt)
left join home_page hp on ss.user_id = hp.user_id
and ss.sms_screen_dt <= hp.home_page_dt
and date(ss.sms_screen_dt) = date(hp.home_page_dt)


#сниппеты
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥18👍9
📌 Метрика Retention Rate (1/2)

Показатель удержания (RR) — одна из главных метрик приложений SaaS. Показывает насколько приложение “увлекает” пользователей.

Метрика, сама по себе, простая, но тут есть несколько нюансов, о которых нельзя забывать.

Есть два типа расчёта этой метрики:

🔵N-day, или классический способ — расчёт в точности на день. В такой концепции RR 7-го дня (R7) показывает сколько юзеров вернулось именно на 7-й день после первого запуска.

🔵Rolling — более гибкий подход, здесь R7 показывает сколько юзеров вернулось на 7-й день или позже.

Правильнее, в большинстве случаев, использовать классический подход. Это связано с устоявшимися нормами в индустрии. Если ты хочешь сравнить показатели своего продукта с бенчмарками, то там почти всегда будет классический расчёт.


У метода Rolling есть весомый нюанс — он не стабилен. Исходя из определения, если юзер установил приложение, потом забросил его и вернулся через месяц — у тебя поплывут все значения на все дни до, т.к. каждый учитывается по условию “вернулся на день N или позже”.

Rolling иногда полезен для продуктов с долгими циклами, дизайн которых не предполагает ежедневного использования. Например приложение по аренде отелей, куда юзер не возвращается каждый день (и это нормально).
Please open Telegram to view this post
VIEW IN TELEGRAM
👍14🔥1
📌 Метрика Retention Rate (2/2)

Ещё одним нюансом в расчёте RR является окно расчётов.

Оно бывает календарное или 24-х часовое. В календарном подходе день N считается по дате, а в часовом — по окну в 24 часа. Т.е. в подходе с часами для каждого юзера день будет завершаться по своему. Это более точно, но менее удобно. Обычно так редко заморачиваются и используют календарный.

График RR часто строят в пределах 30 дней. Контрольными точками обычно являются 1, 3, 7, 14, 21 и 30-й дни.


В этой схеме выделяют три сегмента:

🔵Краткосрочный RR — это R1-R3, показывает первые впечатления, чтобы увеличить эти показатели нужно работать с первыми сессиями.

🔵Среднесрочный RR — промежуток где-то между R7-R14, самый сложный в управлении, обычно где-то здесь должно происходить раскрытие A-ha момента.

🔵Долгосрочный RR — от R21 и выше, почти не управляемый сам по себе сегмент, во многом он зависит от успешности первых двух.

На что вообще обращать внимание на графике? Во-первых нужно оценивать эти сегменты, они помогут понять где можно поработать над удержанием, всё ли ок с первыми сессиями и происходит ли “щелчок” на средней дистанции.

Во-вторых, ищи плато. Ближе к долгосроку график выравнивается, вот тут происходит формирование кор-аудитории. И чем раньше оно начинается, тем лучше.

P.S. Надо завязывать с двойными постами, конечно 😅
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥5
📌 Сомнительные рабочие практики

В твиттере на днях разгоняли срач дискуссию про информационную гигиену в работе. Там было больше с уклоном в собесы и лайв кодинг, но и ряд общих моментов тоже затронули.

Прокомментирую со своей стороны:

🔵Переработки. Абсолютное зло, тут даже что-то обсуждать странно. С огромной натяжкой это может быть ок, если это заранее оговорённая разовая история с доплатой ради какого-то великого (не для тебя, конечно) дела. Но не вот эти ежедневные, потому что надо было вчера. Горят сроки, сгори и ты 😄

🔵Активность в слаке вне рабочее время. В том же твиттере часто бомбят потому что “начальник написал мне в 9 вечера!”. Ну написал и написал, может он только что вспомнил и отправил чтобы не забыть, подумаешь. А вот если ты считаешь что это не ждёт до утра, или, что ещё хуже — он так считает — это уже звоночек.

🔵Созвоны по любым вопросам. Активность чуть более чем бесполезная и должна умереть вообще. Одно дело, когда вопрос объёмный и важный, есть протокол, и по итогам это выливается в какие-то артефакты, типа задач или документации. Совсем другое когда это созвон ради созвона, особенно если разбирается 1-2 вопроса, которые нужно просто прояснить. А если по итогу ничего нигде не документируется, можно считать вы просто прожгли время нескольких человек.

🔵Дейлики. Спорная тема, причём чем дольше работаешь, тем больше переходишь в лагерь “оно ненужное”. Полно статей по тайм-менеджменту, и ни в одной никто всерьёз не пытается защищать дейли. Они создавались как 15-ти минутные синхро внутри команды с общей задачей, но переросли в какой-то мутный мит, где половина присутствующих никак не задействована в задаче другой половины. Часовые дейли, на котором одновременно присутствует и бэк и дизайн обожаю всей душой. Они оправданы только в случае когда у вас кроме этого инструмента синхронизации больше ничего нет. Если есть хотя бы слак и джира, то я не вижу ни одной причины оставлять их. Совсем другое дело это викли, раз в неделю. Вот тут смысл уже есть, но он немного в другом 🙂
Please open Telegram to view this post
VIEW IN TELEGRAM
👍16