871просмотров
92.8%от подписчиков
27 января 2026 г.
statsScore: 958
Обзор собеседования (Ч.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 (Первый день месяца первой покупки, 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️⃣ Клиенты с суммарным весом покупок > 2 кг (Python) Посчитать клиентов, у которых за последний месяц суммарный вес покупок больше 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() 3️⃣ Реализация дисперсии (Python) Написать функцию для расчёта несмещенной выборочной дисперсии. Решение: 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 это корректирует смещение оценки дисперсии генеральной совокупности 4️⃣ Анализ распределения (статистика) Дана выборка клиентов с тратами и нужно было проанализировать распределение
60 клиентов — 0 ₽
38 клиентов — 1000–1500 ₽
2 клиента — 10 000 ₽ Коротко:
️⃣распределение с heavy tail
️⃣среднее будет сильно смещено выбросами
*️⃣медиана и перцентили устойчивее В некст части больше упора будет на статистику и потом будет 3а