Полная база вопросов с собеседований для Data-аналитиков и Data Scientist’ов.
188 из 188 вопросов
WB
SQLЛегкийвопрос
Опиши правильный порядок, по которому движок БД обрабатывает SQL-запрос.
Опиши правильный порядок, по которому движок БД обрабатывает SQL-запрос.
Порядок выполнения SQL-запроса движком базы данных:
FROM — определяются таблицы-источники, выполняются JOIN
WHERE — фильтрация строк по условию
GROUP BY — группировка строк
HAVING — фильтрация групп
SELECT — выбор столбцов, вычисление выражений
DISTINCT — удаление дубликатов
ORDER BY — сортировка результата
LIMIT / OFFSET — ограничение выборки
Важно: оконные функции (OVER()) вычисляются после WHERE, GROUP BY, HAVING, но до DISTINCT и ORDER BY.
WB
SQLСреднийзадача
Посчитать скользящее среднее по доле сервиса 'rec' в общей выручке всех серви…
Посчитать скользящее среднее по доле сервиса 'rec' в общей выручке всех сервисов в феврале 2023 года, в динамике по дням.
WITH daily AS (
SELECTdate,
SUM(CASEWHEN service ='rec'THEN revenue ELSE0END) AS rec_revenue,
SUM(revenue) AS total_revenue
FROM orders
WHEREdateBETWEEN'2023-02-01'AND'2023-02-28'GROUPBYdate
)
SELECTdate,
rec_revenue *1.0/NULLIF(total_revenue, 0) AS rec_share,
AVG(rec_revenue *1.0/NULLIF(total_revenue, 0))
OVER (ORDERBYdateROWSBETWEEN2 PRECEDING ANDCURRENTROW) AS moving_avg_share
FROM daily
ORDERBYdate;
Скользящее среднее рассчитывается по окну в 3 дня (текущий + 2 предыдущих). Сначала считаем дневную долю сервиса rec, затем применяем оконную функцию AVG с ROWS BETWEEN.
WB
PythonСреднийзадача
Необходимо произвести фильтрацию вложенного массива и извлечь элементы 1-го и…
Необходимо произвести фильтрацию вложенного массива и извлечь элементы 1-го индекса.
data = [[1, 'a', True], [2, 'b', False], [3, 'c', True]]
# Способ 1: list comprehension
result = [item[1] for item in data]
# ['a', 'b', 'c']# Способ 2: map + operator.itemgetterfrom operator import itemgetter
result = list(map(itemgetter(1), data))
Оба подхода извлекают элемент с индексом 1 из каждого вложенного списка. List comprehension — более читаемый и Pythonic способ.
WB
PythonСреднийзадача
Напиши метод, который в качестве параметра принимает строку и возвращает слов…
Напиши метод, который в качестве параметра принимает строку и возвращает словарь с количеством символов. Пример: вход 'abcabb' → выход: {'a': 2, 'b': 3, 'c': 1}.
# Способ 1: collections.Counterfrom collections import Counter
defcount_chars(s: str) -> dict:
returndict(Counter(s))
# Способ 2: вручнуюdefcount_chars(s: str) -> dict:
result = {}
for char in s:
result[char] = result.get(char, 0) + 1return result
print(count_chars('abcabb')) # {'a': 2, 'b': 3, 'c': 1}
Counter — самый лаконичный способ. Ручной вариант показывает понимание работы с dict.get() и итерацией по строке.
WB
PythonСреднийзадача
Напиши функцию, которая принимает на вход словарь вида d = {"Wildberries": 20…
Напиши функцию, которая принимает на вход словарь вида d = {"Wildberries": 20, "Ozon": 13, ...} (key — название маркетплейса, value — вес) и возвращает случайно сгенерированное название маркетплейса. Вероятность «выпадения» прямо пропорциональна весу. С какой сложностью работает алгоритм? Можно ли ускорить, если функцию нужно вызвать 10^6 раз?
import random
# Базовый вариант O(n) на каждый вызовdefweighted_random(d: dict) -> str:
names = list(d.keys())
weights = list(d.values())
return random.choices(names, weights=weights, k=1)[0]
# Оптимизированный вариант для 10^6 вызовов:# Предварительно строим кумулятивные веса O(n),# затем каждый вызов — бинарный поиск O(log n)import bisect
defmake_sampler(d: dict):
names = list(d.keys())
cum_weights = []
total = 0for w in d.values():
total += w
cum_weights.append(total)
defsample():
r = random.uniform(0, total)
idx = bisect.bisect_left(cum_weights, r)
return names[idx]
return sample
sampler = make_sampler(d)
for _ inrange(10**6):
sampler() # O(log n) каждый вызов
Базовый random.choices работает за O(n). С предвычислением кумулятивных весов + bisect получаем O(log n) на вызов и O(n) на подготовку.
WB
КейсыСложныйкейс
По итогам первого квартала продакт пришёл с ad-hoc задачей: «Нужно обосновани…
По итогам первого квартала продакт пришёл с ad-hoc задачей: «Нужно обоснование на данных, почему средний чек в сервисе rec ниже, чем у других сервисов?» Есть выгрузки orders (заказы) и events (просмотры и добавления в корзину). Как подойти к анализу?
Фреймворк анализа:
Декомпозиция среднего чека:Средний чек = GMV / Кол-во заказов. Что именно ниже — GMV на заказ или количество товаров в заказе?
Анализ ассортимента: Какие товары рекомендуются в rec? Средняя цена товара в рекомендациях vs. в других сервисах.
Поведение пользователей (events):
Конверсия: просмотр → добавление в корзину → покупка
Среднее количество просмотренных товаров перед покупкой
Доля пользователей, которые добавляют в корзину, но не покупают
Сегментация: Разбить по категориям товаров, по сегментам пользователей (новые/старые, частота покупок)
Гипотезы:
Рекомендации показывают дешёвые товары
Пользователи rec — другой сегмент (новички, casual buyers)
Рекомендации неточные → пользователь покупает меньше товаров из выдачи
WB
SQLСреднийзадача
Дана таблица сотрудников (employee_id, name, skill, salary). Бюджет на зарпла…
Дана таблица сотрудников (employee_id, name, skill, salary). Бюджет на зарплаты 500 тыс. руб. Напишите запрос, который выводит имена операторов для группы, если в приоритете операторы с наибольшим скилом.
WITH data AS (
SELECT
name,
SUM(salary) OVER (
ORDERBY skill DESC, salary, employee_id
) AS cum_sum
FROM employees
)
SELECT name
FROM data
WHERE cum_sum <=500;
Используем оконную функцию SUM() OVER() для нарастающего итога зарплат, отсортированных по убыванию скила. Берём всех сотрудников, пока кумулятивная сумма не превысит бюджет. Сортировка по salary, employee_id при одинаковом скиле обеспечивает детерминированный результат.
WB
SQLСреднийзадача
Посчитайте медианную зарплату выбранных сотрудников (из задачи с бюджетом 500…
Посчитайте медианную зарплату выбранных сотрудников (из задачи с бюджетом 500 тыс.), не используя встроенную функцию медианы.
WITH data AS (
SELECT
name, employee_id, salary,
SUM(salary) OVER (ORDERBY skill DESC, salary, employee_id) AS cum_sum
FROM employees
),
budget AS (
SELECT name, employee_id, salary
FROM data
WHERE cum_sum <=500
),
emp_rank AS (
SELECT
salary,
ROW_NUMBER() OVER (ORDERBY salary) AS rn,
COUNT(*) OVER () AS cnt
FROM budget
)
SELECTAVG(salary) AS median_salary
FROM emp_rank
WHERE-- нечётное: берём средний элемент
(cnt %2=1AND rn = (cnt +1) /2)
OR-- чётное: среднее двух центральных
(cnt %2=0AND rn IN (cnt /2, cnt /2+1));
Идея: нумеруем строки по зарплате, считаем общее количество. Для нечётного количества берём элемент посередине, для чётного — среднее двух центральных.
WB
PythonСреднийзадача
Дана строка (возможно пустая) из букв A-Z, например AAAABBBCCXYZDDDDEEEFFFAAA…
Дана строка (возможно пустая) из букв A-Z, например AAAABBBCCXYZDDDDEEEFFFAAAAAABBBB…C. Нужно написать функцию RLE (Run-Length Encoding), которая вернёт строку вида A4B3C2XYZD4E3F3A6B28. Если символ один раз — без числа, если больше — с числом повторений. Выдать ошибку при недопустимой строке.
defrle(s: str) -> str:
ifnot s:
return''ifnot s.isalpha() ornot s.isupper():
raise ValueError('Строка должна содержать только A-Z')
result = []
count = 1for i inrange(1, len(s)):
if s[i] == s[i - 1]:
count += 1else:
result.append(s[i - 1])
if count > 1:
result.append(str(count))
count = 1# Последняя группа
result.append(s[-1])
if count > 1:
result.append(str(count))
return''.join(result)
print(rle('AAAABBBCCXYZ')) # A4B3C2XYZ
Алгоритм за O(n): проходим по строке, считаем подряд идущие одинаковые символы. При смене символа записываем символ и счётчик (если > 1).
WB
КейсыСложныйкейс
Открыли новую поддержку в Грузии. ПВЗ работают 2 месяца, заказы растут. Подде…
Открыли новую поддержку в Грузии. ПВЗ работают 2 месяца, заказы растут. Поддержка запущена месяц назад. Напиши список метрик, которые отражали бы эффективность работы поддержки.
Метрики эффективности поддержки:
Объём:
Общее количество обращений
Доля обращений от всех заказов
Доля обращений от активных пользователей в Грузии
Качество:
NPS / среднее количество звёзд в отзывах
SLA — доля обращений, закрытых в рамках целевого времени
Доля положительных отзывов
Влияние на бизнес:
Доля и количество купивших пользователей после общения с поддержкой
Retention пользователей, обратившихся в поддержку vs. не обращавшихся
Операционные:
Среднее количество сообщений внутри одного обращения
Среднее время ответа (first response time)
Доля вернувшихся с повторным обращением в течение дня
Фильтры для анализа: тема обращения, канал (чат/звонок), тип проблемы.
Магнит
A/B тестыСреднийзадача
Ты аналитик в сервисе доставки продуктов. Команда тестирует блок с историей з…
Ты аналитик в сервисе доставки продуктов. Команда тестирует блок с историей заказов на главной странице приложения (группа B видит блок, группа A — нет). Даны таблицы df_ab_groups (user_id, ab_group) и df_financial (date, user_id, revenue). Задача 1: найти количество пользователей, попавших более чем в одну группу эксперимента.
import pandas as pd
# Находим пользователей в нескольких группах
user_groups = df_ab_groups.groupby('user_id')['ab_group'].nunique().reset_index()
user_groups.columns = ['user_id', 'group_count']
multi_group = user_groups[user_groups['group_count'] > 1]
print(f'Пользователей в нескольких группах: {len(multi_group)}')
Если таких пользователей много — это признак SRM (Sample Ratio Mismatch). Их нужно исключить из анализа или разобраться в причинах перетекания между группами.
Магнит
A/B тестыСреднийзадача
Посчитай суммарную выручку на клиента за период эксперимента и определи его г…
Посчитай суммарную выручку на клиента за период эксперимента и определи его группу. Данные: df_ab_groups (user_id, ab_group), df_financial (date, user_id, revenue).
# Суммарная выручка на клиента
user_revenue = df_financial.groupby('user_id')['revenue'].sum().reset_index()
user_revenue.columns = ['user_id', 'total_revenue']
# Присоединяем группу эксперимента
result = pd.merge(user_revenue, df_ab_groups, on='user_id', how='inner')
# Средняя выручка по группамprint(result.groupby('ab_group')['total_revenue'].mean())
Важно: используем inner join, чтобы исключить пользователей без определённой группы. Если пользователь был в нескольких группах — предварительно исключаем таких (см. задачу 1).
Магнит
A/B тестыСреднийзадача
Напиши функцию, которая возвращает бокс-плот по выручке в разрезе A/B групп и…
Напиши функцию, которая возвращает бокс-плот по выручке в разрезе A/B групп и выводит итоги эксперимента: Uplift = X, p_value = Y, аудитория = N. Добавь параметр управления выбросами (перцентиль для порогового значения).
import matplotlib.pyplot as plt
from scipy import stats
import numpy as np
defab_results(df, remove_outliers=False, percentile=99):
if remove_outliers:
threshold = np.percentile(df['total_revenue'], percentile)
df = df[df['total_revenue'] <= threshold]
a = df[df['ab_group'] == 'a']['total_revenue']
b = df[df['ab_group'] == 'b']['total_revenue']
# Бокс-плот
fig, ax = plt.subplots()
df.boxplot(column='total_revenue', by='ab_group', ax=ax)
ax.set_title('Выручка по группам')
plt.suptitle('')
plt.show()
# Статистика
uplift = (b.mean() - a.mean()) / a.mean() * 100
_, p_value = stats.ttest_ind(a, b)
n = len(df)
print(f'Uplift = {uplift:.2f}%')
print(f'p_value = {p_value:.4f}')
print(f'Аудитория эксперимента = {n}')
Функция принимает параметры remove_outliers и percentile для управления выбросами. T-test проверяет разницу средних между группами.
Магнит
SQLСреднийзадача
Таблица watch_content (user_id, video_id, date). Вывести список пользователей…
Таблица watch_content (user_id, video_id, date). Вывести список пользователей, смотревших video_id 1 и 3 (оба видео), но не смотревших video_id 2.
SELECT user_id
FROM watch_content
WHERE video_id IN (1, 3)
GROUPBY user_id
HAVINGCOUNT(DISTINCT video_id) =2ANDSUM(CASEWHEN video_id =2THEN1ELSE0END) =0;
Альтернативный подход через подзапрос:
SELECTDISTINCT user_id
FROM watch_content
WHERE video_id =1AND user_id IN (SELECT user_id FROM watch_content WHERE video_id =3)
AND user_id NOTIN (SELECT user_id FROM watch_content WHERE video_id =2);
Первый вариант эффективнее — один проход по таблице с условной агрегацией.
Магнит
SQLСреднийзадача
Таблица raw.orders (user_id, transaction_datetime, item_id, order_id) и dicts…
Таблица raw.orders (user_id, transaction_datetime, item_id, order_id) и dicts.items (item_id, brand, name, price). Для каждого пользователя вывести наименование и цену самого дорогого товара в его первой транзакции.
WITH first_order AS (
SELECT
user_id,
MIN(transaction_datetime) AS first_dt
FROM raw.orders
GROUPBY user_id
),
first_items AS (
SELECT
o.user_id,
i.name,
i.price,
ROW_NUMBER() OVER (
PARTITIONBY o.user_id ORDERBY i.price DESC
) AS rn
FROM raw.orders o
JOIN first_order fo
ON o.user_id = fo.user_id
AND o.transaction_datetime = fo.first_dt
JOIN dicts.items i ON o.item_id = i.item_id
)
SELECT user_id, name, price
FROM first_items
WHERE rn =1;
Сначала находим дату первой транзакции пользователя, затем из товаров этой транзакции выбираем самый дорогой через ROW_NUMBER().
Магнит
SQLСреднийзадача
На основе таблицы raw.orders (user_id, transaction_datetime, item_id, order_i…
На основе таблицы raw.orders (user_id, transaction_datetime, item_id, order_id) вывести: 1) размер когорт по месяцам, 2) ретеншен 2-го месяца. Когорта — множество пользователей, объединённых месяцем первой покупки.
WITH cohorts AS (
SELECT
user_id,
DATE_TRUNC('month', MIN(transaction_datetime)) AS cohort_month
FROM raw.orders
GROUPBY user_id
),
activity AS (
SELECTDISTINCT
o.user_id,
c.cohort_month,
DATE_TRUNC('month', o.transaction_datetime) AS activity_month
FROM raw.orders o
JOIN cohorts c ON o.user_id = c.user_id
),
cohort_size AS (
SELECT cohort_month, COUNT(*) AS size
FROM cohorts
GROUPBY cohort_month
)
SELECT
a.cohort_month,
cs.size AS cohort_size,
COUNT(DISTINCTCASEWHEN DATEDIFF('month', a.cohort_month, a.activity_month) =2THEN a.user_id END
) AS retained_m2,
ROUND(
COUNT(DISTINCTCASEWHEN DATEDIFF('month', a.cohort_month, a.activity_month) =2THEN a.user_id END
) *100.0/ cs.size, 2
) AS retention_m2_pct
FROM activity a
JOIN cohort_size cs ON a.cohort_month = cs.cohort_month
GROUPBY a.cohort_month, cs.size
ORDERBY a.cohort_month;
Строим когорты по первой покупке, затем считаем уникальных пользователей, вернувшихся через 2 месяца.
Магнит
A/B тестыСложныйкейс
Магнит запускает категорию кэшбэка совместно с банком-партнёром. Группа A (10…
Магнит запускает категорию кэшбэка совместно с банком-партнёром. Группа A (1000 чел.) — не видят кэшбэк, группа B (1100 чел.) — видят кэшбэк, из них 300 воспользовались впервые. Тест прокрасился в зелёный — доля покупателей в B выше. Как оценить экономический эффект?
Ключевая метрика: доля пользователей, совершивших покупку.
Тест показал, что доля в B выше — но нужно оценить прибыльность.
CAC (Cost of Acquisition):
Все затраты на кэшбэк + интеграция с банком (% от продаж)
Из 300 воспользовавшихся кэшбэком не все пришли благодаря ему
Доля тех, кто пришёл благодаря кэшбэку: (1100 − 1000) / 300 ≈ 33%
LTV:
Выручка от привлечённых кэшбэком пользователей за N месяцев
LTV > CAC → программа выгодна
Вывод: Нужно считать unit-экономику: если LTV привлечённых через кэшбэк пользователей покрывает стоимость программы — раскатываем.
Вкусвилл
SQLСреднийзадача
Дана таблица visits (Department, FIO, Date, Status). Status может быть: на ра…
Дана таблица visits (Department, FIO, Date, Status). Status может быть: на работе / на больничном / в отпуске (оплачиваемом) / в отпуске (за свой счет). Нужно вывести интервалы непрерывного нахождения сотрудника в определённом статусе (DateFrom, DateTo, Status).
Это задача Gaps & Islands. Решение:
WITH ranked AS (
SELECT
Department, FIO, Date, Status,
ROW_NUMBER() OVER (PARTITIONBY FIO ORDERBYDate) AS rn_all,
ROW_NUMBER() OVER (PARTITIONBY FIO, Status ORDERBYDate) AS rn_status
FROM visits
),
islands AS (
SELECT
Department, FIO, Status,
MIN(Date) AS DateFrom,
MAX(Date) AS DateTo,
rn_all - rn_status AS grp
FROM ranked
GROUPBY Department, FIO, Status, rn_all - rn_status
)
SELECT Department, FIO, DateFrom, DateTo, Status
FROM islands
ORDERBY FIO, DateFrom;
Идея: Разница между двумя нумерациями (rn_all - rn_status) остаётся постоянной для последовательных строк с одинаковым статусом, но меняется при смене статуса. Это позволяет группировать «острова» непрерывного статуса.
Альтернативный простой вариант — через LEAD:
SELECT
FIO,
DateAS DateFrom,
LEAD(Date) OVER (PARTITIONBY FIO ORDERBYDate) AS DateTo,
Status
FROM visits;
Вкусвилл
PythonСреднийзадача
Написать функцию, которая будет выводить товары, не прошедшие минимальный пор…
Написать функцию, которая будет выводить товары, не прошедшие минимальный порог по продажам за месяц. На вход: минимальный порог выручки и массив продаж вида [[{"product_id": 1, "quantity": 2, "price": 100}], ...].
defthreshold_filter(bench: int, sales: list) -> list:
failed_products = []
for sale_group in sales:
for item in sale_group:
gmv = item['quantity'] * item['price']
if gmv < bench:
failed_products.append(item['product_id'])
return failed_products
# Пример
sales = [
[{"product_id": 1, "quantity": 2, "price": 100}],
[{"product_id": 2, "quantity": 3, "price": 100}],
[{"product_id": 3, "quantity": 1, "price": 50}]
]
print(threshold_filter(150, sales)) # [3]
Важно: вложенный массив — список списков, поэтому нужен двойной цикл. Распространённая ошибка — обращаться как i[0] вместо итерации по элементам.
Вкусвилл
СтатистикаСреднийзадача
Мы промоутируем товары наших брендов в поисковой выдаче. Опция 1 — показывать…
Мы промоутируем товары наших брендов в поисковой выдаче. Опция 1 — показывать один товар на каждые 25 выданных. Опция 2 — заменить товар с шансом 4%. Сколько показов мы сделаем на 100 товаров? Каков шанс показать только 1 товар на 100 выданных при второй стратегии?
Опция 1 (детерминированная):
100 / 25 = 4 показа на каждые 100 товаров
Опция 2 (вероятностная):
Математическое ожидание: 100 × 0.04 = 4 показа (в среднем)
Также можно записать: вероятность = (99/100) × 0.96⁹⁹ + (1/100) — но формально это не совсем корректно, правильнее через биномиальное распределение.
Вкусвилл
КейсыСложныйкейс
На корзине есть блок с товарами Зелёного Ценника (40% скидки на товары с подх…
На корзине есть блок с товарами Зелёного Ценника (40% скидки на товары с подходящим сроком годности). Планируем сделать фичу, подсвечивающую эти ценники. Какие риски оценивать и как с ними бороться?
Риски и контрмеры:
Снижение CR в переход на карточку товара — дизайн подсветки может отвлекать от основных товаров. Контрмера: A/B тест, следить за CR в карточку всех товаров.
Снижение среднего чека / гросс-прибыли — пользователи переключаются на скидочные товары. Контрмера: мониторить средний чек и маржинальность.
Минимальный чек заказа — если пользователи набирают корзину из дешёвых скидочных товаров, чек может не дотянуть до минимума.
Каннибализация основного ассортимента — пользователи перестают покупать товары без скидки.
Предложения по усилению эффекта:
Комбинировать скидочные товары с рекомендациями похожих товаров без скидки
Пуш-уведомления о попадании любимого товара в акцию
Геймификация и система лояльности
Вкусвилл
КейсыСложныйкейс
Мы внедрили баннер «рецепты» в поиске приложения. Пользователи кликают, но ср…
Мы внедрили баннер «рецепты» в поиске приложения. Пользователи кликают, но средний чек и выручка не растут. Какие рекомендации?
Диагностика:
Проверить конверсию воронки: клик на баннер → просмотр рецепта → добавление ингредиентов в корзину → покупка
Где обрыв? Пользователи смотрят рецепт, но не добавляют товары?
Возможные причины:
Нет кнопки «Добавить все ингредиенты в корзину» — слишком много шагов
Ингредиентов нет в наличии
Рецепты нерелевантны текущему поиску
Каннибализация: пользователь уходит в рецепты вместо покупки того, что искал
Рекомендации:
Добавить кнопку «Купить все ингредиенты» на странице рецепта
Показывать рецепты на основе того, что уже в корзине (дополнительные товары)
Персонализировать рецепты под историю покупок
Замерить отдельно: покупатели рецептов покупают больше товаров? Если да — проблема в цене/марже
Вкусвилл
КейсыСложныйкейс
Разработали новую логику построения маршрута в 2гис. Как понять, что она рабо…
Разработали новую логику построения маршрута в 2гис. Как понять, что она работает лучше?
Подход: A/B тест
Метрики:
Целевые: время в пути, длина маршрута, доля пользователей, следовавших маршруту до конца
Защитные: количество перестроений маршрута, удовлетворённость пользователей (рейтинг), crash rate
Информационные: среднее количество манёвров, доля маршрутов через платные дороги
Дизайн:
Сплит по пользователям (не по сессиям — избежать перетекания)
Учесть географию (разные регионы — разные карты)
Достаточная длительность для разных сценариев (будни/выходные)
Анализ:
Сравнить среднее время в пути (t-test)
Контролировать SRM
Сегментация: город vs. межгород, утро/вечер, короткие/длинные маршруты
Вкусвилл
КейсыСложныйкейс
SaaS-продукт по подписке. Бесплатный период — 1 месяц. Пользователи жалуются,…
SaaS-продукт по подписке. Бесплатный период — 1 месяц. Пользователи жалуются, что не успевают всё настроить за месяц. Стоит ли продлевать бесплатный период до 3 месяцев?
Анализ:
Текущие данные: какой % пользователей конвертируется в платных за 1 месяц? Какой % завершает настройку?
Сегментация: кто жалуется? Если это крупные клиенты с долгим onboarding — возможно стоит. Если мелкие — это может быть предлог не платить.
Риски продления до 3 месяцев:
Снижение выручки: 2 дополнительных месяца бесплатно
Пользователи могут пользоваться бесплатно и уходить
Размытие urgency — нет мотивации настраивать быстро
Альтернативы:
Улучшить onboarding (мастера настройки, шаблоны)
Персональный менеджер для крупных клиентов
Гибкий trial: продлить на 2 недели по запросу
Ограниченный функционал в free, полный — в trial (freemium)
Как проверить: A/B тест с разной длительностью trial. Метрика: конверсия в платную подписку и LTV за 6 месяцев.
Вкусвилл
A/B тестыСложныйкейс
A/B тест серый — увеличилась только одна прокси-метрика (не основная). Какие …
A/B тест серый — увеличилась только одна прокси-метрика (не основная). Какие будут рекомендации?
Рекомендации:
Проверить достоверность:
Нет ли SRM (Sample Ratio Mismatch)?
Достаточно ли наблюдений для MDE основной метрики?
Не слишком ли короткий тест?
Анализ прокси-метрики:
Насколько она коррелирует с основной?
Возможно, эффект проявится позже (lag effect)
Сегментный анализ:
Есть ли сегменты, где основная метрика выросла?
Новые vs. старые пользователи
Решение:
Если прокси-метрика значимо коррелирует с основной и нет негативного влияния на защитные метрики — можно раскатать с мониторингом
Если нет — продлить тест или отказаться от изменения
Не принимать решение только по прокси-метрике
Т-Банк
СтатистикаСреднийзадача
Кубик бросают три раза. Какова вероятность, что выпадет хотя бы 2 одинаковых …
Кубик бросают три раза. Какова вероятность, что выпадет хотя бы 2 одинаковых числа?
Используем подход «от противного» — считаем вероятность того, что все числа разные, и вычитаем из 1.
Когда медиана > среднего, это означает, что длинный хвост распределения тянется влево (в сторону меньших значений). Среднее «утягивается» за выбросами в левом хвосте.
Мнемоника:
Медиана > Среднего → Left-skewed (левый хвост длиннее)
Медиана < Среднего → Right-skewed (правый хвост длиннее)
Медиана ≈ Среднего → Симметричное распределение
Т-Банк
A/B тестыЛегкийвопрос
Как изменится длительность A/B теста, если трафик увеличится
Как изменится длительность A/B теста, если трафик увеличится?
Длительность уменьшится, так как скорость набора выборок станет выше.
Формула размера выборки: n = (Z_α + Z_β)² × 2σ² / δ²
Размер выборки зависит от α, β, σ², δ (MDE) — но не от трафика. Трафик влияет только на то, за сколько дней мы наберём нужный размер выборки.
Если трафик × 2 → длительность теста ≈ / 2 (при прочих равных).
Важно: нельзя останавливать тест раньше, чем набран минимальный размер выборки, даже если p-value уже низкий (проблема peeking).
Т-Банк
SQLЛегкийвопрос
Какая операция в SQL соединяет две таблицы и удаляет дубликаты
Какая операция в SQL соединяет две таблицы и удаляет дубликаты?
UNION — объединяет результаты двух SELECT-запросов и автоматически удаляет дубликаты.
Важные отличия:
UNION — удаляет дубликаты (выполняет сортировку / хеширование для дедупликации)
UNION ALL — оставляет все строки, включая дубликаты (быстрее, так как нет дедупликации)
Требования:
Оба запроса должны возвращать одинаковое количество столбцов
Типы данных соответствующих столбцов должны быть совместимы
UNION ALL предпочтительнее, если дубликаты невозможны или допустимы — он работает быстрее.
Т-Банк
СтатистикаСреднийзадача
В мае было 100к пользователей, в июне из них зашло 20к, в июле — 30к. Какой м…
В мае было 100к пользователей, в июне из них зашло 20к, в июле — 30к. Какой минимальный и максимальный Rolling Retention?
Rolling Retention считает пользователя вернувшимся, если он вернулся в любой из последующих месяцев.
Считаем от майской когорты (100к):
Минимальный RR:
Если пользователи июня и июля полностью пересекаются (все 20к июня вошли в 30к июля)
Вернулось: max(20к, 30к) = 30к
Min RR = 30к / 100к = 30%
Максимальный RR:
Если пользователи июня и июля не пересекаются вообще
Вернулось: 20к + 30к = 50к
Max RR = 50к / 100к = 50%
Ответ: RR ∈ [30%, 50%]
Т-Банк
СтатистикаЛегкийвопрос
Можно ли считать отличия в A/B тесте статистически значимыми, если p_value = …
Можно ли считать отличия в A/B тесте статистически значимыми, если p_value = 0.07 при уровне значимости alpha = 0.05?
Нет, отличия нельзя считать статистически значимыми.
p-value = 0.07 > α = 0.05 → мы не отвергаем нулевую гипотезу.
Это означает: наблюдаемая разница между группами могла получиться случайно с вероятностью 7%, что выше допустимого порога в 5%.
Важно:
p-value ≠ вероятность того, что нулевая гипотеза верна
p-value — это вероятность получить такой же или более экстремальный результат при условии, что H0 верна
p = 0.07 не означает «почти значимо» — порог α выбирается до начала теста и не меняется
ММосБилет
SQLСреднийзадача
Посчитать количество визитов разработчиков в репозиторий n8n-io/n8n за сентяб…
Посчитать количество визитов разработчиков в репозиторий n8n-io/n8n за сентябрь 2025. Таблица github.events (created_at, actor_login, repo_name). Визит — последовательность событий одного пользователя, где перерыв между событиями не больше 30 минут.
WITH data AS (
SELECT
actor_login,
created_at,
LAG(created_at) OVER (
PARTITIONBY actor_login ORDERBY created_at
) AS prev_time,
CASEWHEN DATEDIFF('minute',
LAG(created_at) OVER (PARTITIONBY actor_login ORDERBY created_at),
created_at
) >=30ORLAG(created_at) OVER (PARTITIONBY actor_login ORDERBY created_at) ISNULLTHEN1ELSE0ENDAS session_flag
FROM github.events
WHERE
created_at BETWEEN'2025-09-01'AND'2025-10-01'AND repo_name ='n8n-io/n8n'
)
SELECTSUM(session_flag) AS total_sessions
FROM data;
Идея: помечаем флагом 1 каждое событие, если пауза от предыдущего ≥ 30 минут (или это первое событие). Сумма флагов = количество сессий (визитов). Используем LAG для доступа к предыдущему времени в окне по пользователю.
СберЗдоровье
PythonСреднийзадача
Дан датафрейм продаж (event_dt, store, item, amount, price, customer). Провес…
Дан датафрейм продаж (event_dt, store, item, amount, price, customer). Провести агрегированный анализ: для каждого магазина вывести общую сумму продаж, среднюю цену товара, количество уникальных товаров.
import pandas as pd
df['item_sum'] = df['amount'] * df['price']
result = df.groupby('store').agg(
total_sales=('item_sum', 'sum'),
avg_price=('price', 'mean'),
unique_items=('item', 'nunique')
).reset_index()
print(result)
Используем groupby + agg с именованными агрегациями (named aggregation) — это более читаемый синтаксис, чем передача словаря. Сначала создаём столбец item_sum (выручка по позиции), затем агрегируем по магазинам.
СберЗдоровье
PythonСреднийзадача
Рассчитать средний чек для каждого клиента и вывести топ-5 клиентов с наиболь…
Рассчитать средний чек для каждого клиента и вывести топ-5 клиентов с наибольшим средним чеком.
import pandas as pd
df['item_sum'] = df['amount'] * df['price']
# Считаем сумму заказа (группируем по клиенту, дате и магазину)
order_totals = (
df.groupby(['customer', 'event_dt', 'store'])
.agg(order_sum=('item_sum', 'sum'))
.reset_index()
)
# Средний чек на клиента
avg_check = (
order_totals.groupby('customer')
.agg(avg_check=('order_sum', 'mean'))
.reset_index()
.sort_values('avg_check', ascending=False)
)
print(avg_check.head(5))
Важно: «чек» = один заказ (уникальная комбинация клиент + дата + магазин). Сначала считаем сумму каждого заказа, потом среднее по клиенту.
СберЗдоровье
SQLСреднийзадача
Таблицы country (country_name, city) и sales (date, city, income). Вывести ра…
Таблицы country (country_name, city) и sales (date, city, income). Вывести разницу income в % по каждой стране YoY, сравнивая октябрь 2022 с октябрём 2023.
WITH data AS (
SELECTYEAR(s.date) AS yr,
c.country_name,
SUM(s.income) AS country_income
FROM sales s
LEFTJOIN country c ON s.city = c.city
WHERE DATE_TRUNC('month', s.date) IN ('2022-10-01', '2023-10-01')
GROUPBY yr, c.country_name
)
SELECT
country_name,
MAX(CASEWHEN yr =2022THEN country_income END) AS income_22,
MAX(CASEWHEN yr =2023THEN country_income END) AS income_23,
(MAX(CASEWHEN yr =2023THEN country_income END)
-MAX(CASEWHEN yr =2022THEN country_income END))
/NULLIF(MAX(CASEWHEN yr =2022THEN country_income END), 0)
*100AS delta_pct
FROM data
GROUPBY country_name;
Используем условную агрегацию (MAX(CASE WHEN ...)) для pivot из строк в столбцы. NULLIF защищает от деления на ноль.
Таблица event_log (event_uuid, ts, user_id, event_name). Подготовить запрос для retention анализа: неделя первой установки (Install), количество недель до Consultation, размер когорты, количество уников с Consultation.
WITH cohorts AS (
SELECT
user_id,
MIN(DATE_TRUNC('week', ts)) AS install_week
FROM event_log
WHERE event_name ='Install'GROUPBY user_id
),
diff AS (
SELECT
ev.user_id,
c.install_week,
DATE_TRUNC('week', ev.ts) AS consultation_week,
DATEDIFF('week', c.install_week, DATE_TRUNC('week', ev.ts)) AS week_diff
FROM cohorts c
LEFTJOIN event_log ev
ON ev.user_id = c.user_id
AND ev.event_name ='Consultation'
),
cohort_size AS (
SELECT install_week, COUNT(DISTINCT user_id) AS size
FROM cohorts
GROUPBY install_week
)
SELECT
d.install_week,
d.week_diff,
cs.size AS cohort_size,
COUNT(DISTINCT d.user_id) AS consultation_users
FROM diff d
JOIN cohort_size cs ON d.install_week = cs.install_week
GROUPBY d.install_week, d.week_diff, cs.size
ORDERBY d.install_week, d.week_diff;
Три CTE: когорты (неделя первого Install), интервалы (разница в неделях до Consultation), размер когорт. Финальный SELECT объединяет всё.
СберЗдоровье
КейсыСложныйкейс
DAU вырос, а выручка упала. Что может быть причиной
DAU вырос, а выручка упала. Что может быть причиной?
Декомпозиция:
GMV = Количество заказов × Средний чек
DAU ↑ + GMV ↓ → значит CR в покупку ↓ или средний чек ↓ (или оба)
Возможные причины:
Трафик:
Нерелевантный трафик из рекламы (много новых пользователей, которые не покупают)
Боты / фродовый трафик
Конверсия (CR):
Техническая ошибка на каком-то шаге воронки
Ошибка интеграций (платёжный шлюз, авторизация)
Плохой релиз (UI/UX регрессия)
Средний чек:
Ушли акции/скидки → пользователи покупают меньше
Проблема с рекомендатором → меньше допродаж
Перетекание пользователей в более дешёвые категории
Сезонность
Проверить: технические метрики (error rate, время загрузки), источники трафика, воронку конверсии по шагам.
СберЗдоровье
A/B тестыСложныйкейс
A/B тест: на выдаче врачей в тестовой группе половине врачей повесили шильдик…
A/B тест: на выдаче врачей в тестовой группе половине врачей повесили шильдик «лучший врач». Конверсия в запись на выдаче к любому врачу упала. Предположи, почему.
Первым делом проверить технику:
Нет SRM (соотношение групп правильное)
Ивенты в обеих группах доходят корректно
Ранжирование одинаковое
Других изменений, кроме UI, нет
Продуктовые причины падения:
Парадокс выбора: появление шильдика создаёт «лучших» и «худших» врачей. Пользователи хотят к «лучшему», но у него нет свободных слотов → уходят.
Нерелевантное распределение метки: если шильдик получили не те врачи, пользователи теряют доверие к выдаче.
Эффект сравнения: пользователи дольше выбирают, сравнивая «с шильдиком» vs. «без», и откладывают запись.
Дефицит у «лучших»: все хотят к врачам с меткой → мест нет → пользователь уходит совсем, а не записывается к другому.
HH.ru
SQLСреднийзадача
Нужно отправить рассылку всем работодателям hh, у которых не более 5 активных…
Нужно отправить рассылку всем работодателям hh, у которых не более 5 активных вакансий. Таблицы: employer (employer_id, name) и vacancy (vacancy_id, active, employer_id). Вывести имена таких работодателей.
SELECT e.name
FROM employer e
LEFTJOIN vacancy v ON e.employer_id = v.employer_id
GROUPBY e.name
HAVINGCOUNT(CASEWHEN v.active =TRUETHEN1END) <=5;
Важно использовать LEFT JOIN, чтобы включить работодателей с 0 вакансий. HAVING COUNTIF(active) <= 5 (ClickHouse-синтаксис) или COUNT(CASE WHEN ...) в стандартном SQL.
Альтернатива с подзапросом:
SELECT e.name
FROM employer e
WHERE (
SELECTCOUNT(*)
FROM vacancy v
WHERE v.employer_id = e.employer_id AND v.active =TRUE
) <=5;
HH.ru
SQLСреднийзадача
Таблицы: search (user_id, search_number, vacancy_id, vacancy_position) и clic…
Таблицы: search (user_id, search_number, vacancy_id, vacancy_position) и clicks (ts, user_id, search_number, vacancy_id). Подсчитать среднюю позицию первых трёх кликов пользователей в каждом поиске. Если кликов < 3, поиск не учитывать.
WITH base AS (
SELECT
s.user_id,
s.search_number,
s.vacancy_position,
ROW_NUMBER() OVER (
PARTITIONBY s.user_id, s.search_number
ORDERBY c.ts
) AS click_number
FROMsearch s
INNERJOIN clicks c
ON s.user_id = c.user_id
AND s.search_number = c.search_number
AND s.vacancy_id = c.vacancy_id
)
SELECT
user_id,
search_number,
AVG(vacancy_position) AS avg_position
FROM base
WHERE click_number <=3GROUPBY user_id, search_number
HAVINGCOUNT(*) =3;
JOIN search с clicks по трём ключам. ROW_NUMBER() нумерует клики по времени внутри каждого поиска. Берём первые 3, фильтруем поиски с < 3 кликами через HAVING COUNT(*) = 3.
HH.ru
PythonСреднийзадача
Написать функцию, которая считает факториал от целого неотрицательного числа.…
Написать функцию, которая считает факториал от целого неотрицательного числа. n! = 1 × ... × n, 0! = 1.
# Итеративный подходdeffactorial(n: int) -> int:
if n < 0:
raise ValueError('n должно быть >= 0')
result = 1for i inrange(1, n + 1):
result *= i
return result
# Рекурсивный подходdeffactorial_rec(n: int) -> int:
if n < 0:
raise ValueError('n должно быть >= 0')
if n <= 1:
return1return n * factorial_rec(n - 1)
# Встроенныйfrom math import factorial
print(factorial(5)) # 120print(factorial(0)) # 1
Итеративный вариант предпочтительнее — нет риска переполнения стека при больших n. В Python есть math.factorial(), но на собеседовании обычно просят написать вручную.
HH.ru
PythonЛегкийвопрос
a = [3, 1, 2]. Чем отличается b = a[::-1] от a.reverse()
a = [3, 1, 2]. Чем отличается b = a[::-1] от a.reverse()?
a = [3, 1, 2]
b = a[::-1] # Создаёт НОВЫЙ перевёрнутый список# a = [3, 1, 2] — не изменился# b = [2, 1, 3] — новый объект
a.reverse() # Переворачивает список IN-PLACE# a = [2, 1, 3] — изменился# Возвращает None
Ключевые отличия:
a[::-1] — создаёт новый список, a не меняется. Возвращает новый список.
a.reverse() — изменяет aна месте (in-place). Возвращает None.
a[::-1] использует больше памяти (O(n) — копия), reverse() — O(1).
Также есть reversed(a) — возвращает итератор (ленивый, не копирует).
HH.ru
PythonЛегкийвопрос
В чём разница между list, tuple и set в Python
В чём разница между list, tuple и set в Python?
Свойство
list
tuple
set
Мутабельность
Мутабельный
Иммутабельный
Мутабельный
Порядок
Упорядоченный
Упорядоченный
Неупорядоченный
Дубликаты
Допускает
Допускает
Нет дубликатов
Индексация
Да [i]
Да [i]
Нет
Синтаксис
[1, 2, 3]
(1, 2, 3)
{1, 2, 3}
Хешируемость
Нет
Да (если элементы хешируемы)
Нет
Когда что использовать:
list — изменяемая коллекция с порядком (массив данных, стек)
tuple — неизменяемые данные (координаты, ключи словаря, возврат нескольких значений)
set — уникальные элементы, быстрый поиск O(1), операции пересечения/объединения
HH.ru
КейсыСложныйкейс
Метрика: среднее от «Отклики» на вакансию. Что с ней может быть не так, как е…
Метрика: среднее от «Отклики» на вакансию. Что с ней может быть не так, как её можно улучшить, что можно предложить вместо неё?
Проблемы метрики «среднее откликов»:
Чувствительна к выбросам: одна вакансия с 10000 откликов сильно сдвигает среднее.
Не учитывает качество откликов — много нерелевантных откликов ≠ хорошо.
Не учитывает тип вакансий — массовые vs. экспертные позиции несопоставимы.
Среднее скрывает распределение — 50% вакансий могут иметь 0 откликов.
Улучшения:
Использовать медиану вместо среднего (устойчива к выбросам)
Сегментировать по типу вакансии (категория, уровень, регион)
Считать долю вакансий с хотя бы N откликами (>= 1, >= 5)
Альтернативные метрики:
CR отклик → приглашение (качество откликов)
Время до первого отклика (скорость)
Доля закрытых вакансий (финальный результат)
Время до найма (time to hire)
HH.ru
СтатистикаЛегкийвопрос
X распределена по N(0, 1). Чему равна P(X = 0)
X распределена по N(0, 1). Чему равна P(X = 0)?
P(X = 0) = 0
Для непрерывного распределения вероятность попадания в любую конкретную точку равна нулю.
Нормальное распределение — непрерывное: случайная величина может принять любое значение на числовой прямой. Вероятность определена только для интервалов, а не для отдельных точек.
P(X = a) = 0 для любого a, но P(a ≤ X ≤ b) > 0 при a < b.
Это следствие того, что вероятность для непрерывного распределения — это интеграл от плотности, а интеграл по точке (интервалу нулевой длины) равен нулю.
Детский мир
КейсыЛегкийвопрос
Расскажи про стек аналитика в крупном e-commerce: какие инструменты и платфор…
Расскажи про стек аналитика в крупном e-commerce: какие инструменты и платформы используются?
Типичный стек в крупном e-commerce (на примере Детского мира):
Хранение и обработка:
Hive + Hadoop — хранение больших объёмов данных
ClickHouse — быстрые аналитические запросы
PySpark — обработка данных на кластере
Сбор данных:
Snowplow — сбор событий (event tracking)
Data Hub — каталог данных (data discovery)
Оркестрация:
Airflow — планирование и мониторинг ETL-пайплайнов
Визуализация:
Superset — дашборды и BI
Эксперименты:
Sigma или собственная AB-платформа
Особенности e-commerce: наличие офлайн-тестов (в магазинах), маркетплейс-модель, мультиканальность (онлайн + офлайн).
ВсеИнструменты
КейсыСложныйкейс
Как посчитать долю риелторов от рынка риелторов России на площадке объявлений
Как посчитать долю риелторов от рынка риелторов России на площадке объявлений? Данные: внутренние объявления + данные конкурентов (Циан, Суточно и др.).
Подход:
1. Внутри площадки:
Считаем общее количество объявлений с квартирами
Определяем риелторов через:
Метки на объявлениях (статус «агентство»)
Количество объявлений с одного аккаунта (> N → агент)
Анализ текста описания (LLM/NLP для выявления агентского стиля)
2. Для конкурентов:
Парсинг данных с других площадок
Применяем аналогичную логику определения риелторов
3. Дедупликация:
Мэтчинг объявлений между площадками по: имени пользователя, адресу, стоимости, площади, описанию
Убираем дубликаты
4. Итог:
Доля квартир с риелторами = квартиры_с_риелторами / все_квартиры
Количество уникальных риелторов = уникальные аккаунты с метками
ВсеИнструменты
A/B тестыСложныйкейс
Акция в Казани для B2C: промо на первую покупку 30%. A/B теста нет — на 100%.…
Акция в Казани для B2C: промо на первую покупку 30%. A/B теста нет — на 100%. Начало акции совпало с индексацией цен. CR упал в Казани на 5%, в других городах — на 10%. Как оценить эффект акции?
Проблема: нет контрольной группы, эффект акции смешан с индексацией цен.
Подход — Difference-in-Differences (DiD):
Используем другие города как контроль:
Казань: CR упал на 5%
Другие города (без акции): CR упал на 10%
Инкрементальный эффект акции: 10% − 5% = +5% (акция компенсировала часть падения)
Расчёт привлечённых клиентов:
Прогноз без акции и без индексации: 10000 клиентов
Коэффициент падения от индексации: −10% → 9000
Фактическое количество: 9999
Аплифт от акции: 9999 − 9000 = 999 клиентов
Сегментация по флагам:
Перешли по рекламе + купили с промокодом → точно привлечённые
Перешли по рекламе + купили без промокода → частично
Не видели рекламу + использовали промокод → органическое распространение
ВсеИнструменты
A/B тестыСложныйкейс
Маркетплейс запускает программу лояльности для продавцов (уровни на основе ме…
Маркетплейс запускает программу лояльности для продавцов (уровни на основе метрик, плюшки: скидка на аналитику, продвижение, вес в ранжировании). Нужно оценить эффект через A/B. Как спроектировать?
Дизайн A/B теста:
Группы:
A (контроль): не видят программу лояльности (но уровни ведём внутренне)
B (тест): видят программу и плюшки
Начальные уровни рассчитаны на основе исторических данных
Метрики:
Целевые: выручка на магазин, количество заказов
Вторичные: средний чек, количество поднятий уровня
Защитные: качество товаров (возвраты), скорость доставки
Сложности:
Network effects: продавцы B получают преимущество в ранжировании → это влияет на продавцов A
Длительность: эффект лояльности проявляется не сразу
Сплит: по продавцам, не по пользователям
Решение network effects:
Можно сплитить по регионам или категориям
Switchback design (попеременное включение)
Или сравнивать когорты (до/после) с DiD
ВсеИнструменты
A/B тестыСреднийзадача
Спроектируй дизайн A/B теста для новой модели ранжирования товаров: какие мет…
Спроектируй дизайн A/B теста для новой модели ранжирования товаров: какие метрики, где проводить, как определить длительность.
Метрики:
Целевые:
Доля нажатий на первые N карточек товара
CR в карточку товара в целом
Защитные:
CR в покупку
Скорость загрузки страницы
Доля пустых выдач
Информационные:
Средний чек
Gross / Net revenue
Количество заказов
Платформа: определить веб / приложение (или оба).
Длительность:
Определить текущий CR и желаемый MDE (минимальный детектируемый эффект)
Рассчитать размер выборки: n = (Z_α + Z_β)² × 2p(1−p) / δ²
Длительность = n / (дневной трафик × доля в тесте)
Минимум 1-2 полных недели (учёт сезонности будни/выходные)
Проверки: SRM, отсутствие пересечений между группами, z-test / t-test для оценки разницы.
ВсеИнструменты
SQLСреднийзадача
Таблица employee (id, skill, salary). Написать запрос, который выберет сотруд…
Таблица employee (id, skill, salary). Написать запрос, который выберет сотрудников для бюджета в 500 тыс. руб. с приоритетом на их навыки (чем выше skill, тем приоритетнее).
WITH data AS (
SELECT
id,
skill,
salary,
SUM(salary) OVER (ORDERBY skill DESC, salary) AS cum_sum
FROM employee
)
SELECT id, skill, salary
FROM data
WHERE cum_sum <=500000;
Накапливающая сумма зарплат по убыванию скила. Берём всех сотрудников, пока кумулятивная сумма не превысит бюджет. При одинаковом скиле сначала берём с меньшей зарплатой (чтобы вместить больше людей).
ВсеИнструменты
SQLСреднийзадача
Таблица employee (id, skill, salary). Написать запрос, который выведет медиан…
Таблица employee (id, skill, salary). Написать запрос, который выведет медиану зарплаты без использования встроенной функции медианы.
WITH data AS (
SELECT
salary,
ROW_NUMBER() OVER (ORDERBY salary, id) AS rn
FROM employee
),
rowsAS (
SELECTCOUNT(*) AS cnt FROM employee
)
SELECTAVG(d.salary) AS median_salary
FROM data d
CROSSJOINrows r
WHERE-- нечётное количество: средний элемент
(r.cnt %2=1AND d.rn = (r.cnt +1) /2)
OR-- чётное количество: два центральных
(r.cnt %2=0AND d.rn IN (r.cnt /2, r.cnt /2+1));
Пример:
[1, 2, 3, 4, 5] → rn=3 → медиана = 3
[1, 2, 3, 4] → rn=2,3 → медиана = (2+3)/2 = 2.5
ВсеИнструменты
PythonСреднийзадача
Таблица items (item_id, name, price, update_date) — история изменений товаров…
Таблица items (item_id, name, price, update_date) — история изменений товаров. Написать код, который выведет актуальное состояние товаров на дату 01-06-2025.
import pandas as pd
# Фильтруем записи до нужной даты
df['update_date'] = pd.to_datetime(df['update_date'])
df_filtered = df[df['update_date'] <= '2025-06-01']
# Находим последнюю дату обновления для каждого товара
last_dates = (
df_filtered.groupby('item_id')['update_date']
.max()
.reset_index()
)
# Джойним обратно для получения актуальных строк
result = pd.merge(
df_filtered,
last_dates,
on=['item_id', 'update_date'],
how='inner'
)
print(result[['item_id', 'name', 'price', 'update_date']])
Альтернативный подход через sort_values + drop_duplicates:
result = (
df_filtered
.sort_values('update_date')
.drop_duplicates('item_id', keep='last')
)
ННе определено
SQLСреднийзадача
Объясни разницу между ROW_NUMBER(), RANK() и DENSE_RANK(). Напиши запрос, дем…
Объясни разницу между ROW_NUMBER(), RANK() и DENSE_RANK(). Напиши запрос, демонстрирующий отличие на примере таблицы с дубликатами.
WITH sample AS (
SELECT*FROM (VALUES
('Анна', 90), ('Борис', 90), ('Вера', 85), ('Глеб', 80)
) AS t(name, score)
)
SELECT
name,
score,
ROW_NUMBER() OVER (ORDERBY score DESC) AS row_num,
RANK() OVER (ORDERBY score DESC) AS rnk,
DENSE_RANK() OVER (ORDERBY score DESC) AS dense_rnk
FROM sample;
Результат:
name
score
row_num
rnk
dense_rnk
Анна
90
1
1
1
Борис
90
2
1
1
Вера
85
3
3
2
Глеб
80
4
4
3
ROW_NUMBER — уникальный номер для каждой строки (порядок дубликатов недетерминирован)
DENSE_RANK — одинаковый ранг, не пропускает (1, 1, 2, 3)
ННе определено
SQLСреднийзадача
Напиши SQL-запрос для вычисления медианы через PERCENTILE_CONT. В чём отличие…
Напиши SQL-запрос для вычисления медианы через PERCENTILE_CONT. В чём отличие от PERCENTILE_DISC?
-- PERCENTILE_CONT: интерполирует между значениямиSELECTPERCENTILE_CONT(0.5) WITHINGROUP (ORDERBY salary) AS median_cont
FROM employees;
-- PERCENTILE_DISC: берёт ближайшее реальное значениеSELECTPERCENTILE_DISC(0.5) WITHINGROUP (ORDERBY salary) AS median_disc
FROM employees;
Отличия:
PERCENTILE_CONT(0.5) — непрерывная медиана. Если количество строк чётное, интерполирует между двумя центральными значениями. Результат может не существовать в данных.
PERCENTILE_DISC(0.5) — дискретная медиана. Возвращает реальное значение из данных (ближайшее к позиции 50%).
Пример: [10, 20, 30, 40]
CONT: (20 + 30) / 2 = 25
DISC: 20 (или 30, зависит от реализации)
ННе определено
SQLСреднийзадача
Что такое задача Gaps & Islands
Что такое задача Gaps & Islands? Напиши запрос, который находит непрерывные интервалы дат активности пользователя (если пользователь заходил подряд несколько дней — это один «остров»).
Gaps & Islands — классическая задача SQL: найти непрерывные последовательности (islands) и пропуски (gaps) в данных.
WITH numbered AS (
SELECT
user_id,
activity_date,
activity_date -INTERVAL'1 day'*ROW_NUMBER() OVER (
PARTITIONBY user_id ORDERBY activity_date
) AS grp
FROM user_activity
)
SELECT
user_id,
MIN(activity_date) AS island_start,
MAX(activity_date) AS island_end,
COUNT(*) AS consecutive_days
FROM numbered
GROUPBY user_id, grp
ORDERBY user_id, island_start;
Идея: вычитаем из даты её порядковый номер. Для последовательных дат (01, 02, 03) разница будет одинаковой (01−1, 02−2, 03−3 = одна и та же дата). Это позволяет группировать «острова».
ННе определено
SQLЛегкийвопрос
Что такое SCD Type 2 (Slowly Changing Dimension)
Что такое SCD Type 2 (Slowly Changing Dimension)? Как реализовать запрос актуального состояния из таблицы с версионностью?
SCD Type 2 — подход к хранению истории изменений в аналитических хранилищах. Каждая строка имеет:
valid_from — дата начала действия
valid_to — дата окончания (NULL или '9999-12-31' для актуальной)
Type 2: новая строка с версионностью (полная история)
Type 3: дополнительный столбец (previous_value)
ННе определено
SQLСреднийзадача
Напиши запрос с использованием LATERAL JOIN (или CROSS APPLY). Когда он полез…
Напиши запрос с использованием LATERAL JOIN (или CROSS APPLY). Когда он полезен и чем отличается от обычного JOIN?
LATERAL JOIN позволяет подзапросу ссылаться на столбцы из предыдущих таблиц в FROM.
-- Топ-3 заказа для каждого клиентаSELECT c.name, o.order_date, o.amount
FROM customers c
CROSSJOINLATERAL (
SELECT order_date, amount
FROM orders
WHERE customer_id = c.id -- ссылка на внешнюю таблицу!ORDERBY amount DESC
LIMIT 3
) o;
Отличие от обычного JOIN:
Обычный JOIN: оба источника независимы, фильтрация через ON
LATERAL: правая часть может ссылаться на левую (как коррелированный подзапрос, но в FROM)
Когда полезен:
Топ-N для каждой группы (без оконных функций)
Раскрытие массивов / JSON
Вызов табличных функций с параметрами из другой таблицы
В SQL Server аналог — CROSS APPLY / OUTER APPLY.
ННе определено
SQLСреднийзадача
Напиши рекурсивный CTE: построй последовательность дат (date spine) за январь…
Напиши рекурсивный CTE: построй последовательность дат (date spine) за январь 2025 года.
WITHRECURSIVE date_spine AS (
-- Базовый случайSELECTDATE'2025-01-01'AS dt
UNIONALL-- Рекурсивный шагSELECT dt +INTERVAL'1 day'FROM date_spine
WHERE dt <DATE'2025-01-31'
)
SELECT dt FROM date_spine;
Результат: 31 строка с датами от 2025-01-01 до 2025-01-31.
Зачем нужен date spine:
LEFT JOIN с данными по дням — показать дни без событий (пропуски)
Напиши запрос для Pivot (строки в столбцы): таблица sales (month, product, re…
Напиши запрос для Pivot (строки в столбцы): таблица sales (month, product, revenue) → вывести продукты как столбцы с выручкой по месяцам.
-- Через условную агрегацию (универсально)SELECTmonth,
SUM(CASEWHEN product ='A'THEN revenue ELSE0END) AS product_a,
SUM(CASEWHEN product ='B'THEN revenue ELSE0END) AS product_b,
SUM(CASEWHEN product ='C'THEN revenue ELSE0END) AS product_c
FROM sales
GROUPBYmonthORDERBYmonth;
Unpivot (обратная операция):
SELECTmonth, 'A'AS product, product_a AS revenue FROM pivoted
UNIONALLSELECTmonth, 'B', product_b FROM pivoted
UNIONALLSELECTmonth, 'C', product_c FROM pivoted;
Варианты в разных СУБД:
PostgreSQL: crosstab() из tablefunc
SQL Server: PIVOT / UNPIVOT операторы
ClickHouse: условная агрегация или arrayJoin
ННе определено
SQLСреднийзадача
Напиши запрос с условной агрегацией через CASE WHEN и через FILTER (WHERE). В…
Напиши запрос с условной агрегацией через CASE WHEN и через FILTER (WHERE). В чём разница?
-- Вариант 1: CASE WHEN (работает везде)SELECT
department,
COUNT(CASEWHEN status ='active'THEN1END) AS active_count,
AVG(CASEWHEN status ='active'THEN salary END) AS active_avg_salary
FROM employees
GROUPBY department;
-- Вариант 2: FILTER (PostgreSQL, ClickHouse)SELECT
department,
COUNT(*) FILTER (WHERE status ='active') AS active_count,
AVG(salary) FILTER (WHERE status ='active') AS active_avg_salary
FROM employees
GROUPBY department;
Разница:
CASE WHEN — стандартный SQL, работает во всех СУБД
FILTER (WHERE) — более читаемый синтаксис, поддерживается в PostgreSQL 9.4+, ClickHouse (countIf, sumIf)
Семантически эквивалентны, но FILTER может быть чуть эффективнее (оптимизатор знает, что это фильтрация)
ClickHouse-вариант:countIf(status = 'active'), avgIf(salary, status = 'active')
ННе определено
SQLЛегкийвопрос
В чём разница между EXISTS и IN в SQL
В чём разница между EXISTS и IN в SQL? Когда что использовать и как это влияет на производительность?
-- IN: проверяет вхождение значения в списокSELECT*FROM orders
WHERE customer_id IN (SELECT id FROM vip_customers);
-- EXISTS: проверяет существование хотя бы одной строкиSELECT*FROM orders o
WHEREEXISTS (
SELECT1FROM vip_customers v WHERE v.id = o.customer_id
);
Ключевые различия:
IN
EXISTS
NULL-обработка
IN (NULL, 1, 2) — NULL не матчится, NOT IN (NULL, ...) — ловушка, вернёт пусто
EXISTS корректно работает с NULL
Производительность
Хорош при малом подзапросе
Хорош при большом внешнем запросе
Оптимизация
Подзапрос выполняется один раз
Коррелированный — может выполняться для каждой строки
Правило:
Малый подзапрос → IN
NOT IN с возможными NULL → всегда NOT EXISTS
Современные оптимизаторы часто делают одно и то же
ННе определено
SQLСреднийзадача
Напиши запрос для генерации date spine (календарной таблицы) и используй его …
Напиши запрос для генерации date spine (календарной таблицы) и используй его для заполнения пропусков в данных — покажи дни с нулевыми продажами.
WITHRECURSIVE date_spine AS (
SELECTMIN(order_date) AS dt FROM orders
UNIONALLSELECT dt +INTERVAL'1 day'FROM date_spine
WHERE dt < (SELECTMAX(order_date) FROM orders)
),
daily_sales AS (
SELECT
order_date,
SUM(amount) AS total_sales
FROM orders
GROUPBY order_date
)
SELECT
ds.dt ASdate,
COALESCE(s.total_sales, 0) AS sales
FROM date_spine ds
LEFTJOIN daily_sales s ON ds.dt = s.order_date
ORDERBY ds.dt;
Date spine генерирует все даты в диапазоне. LEFT JOIN с данными продаж показывает 0 для дней без транзакций. Это критично для:
Графиков без пропусков
Корректного расчёта скользящих средних
Обнаружения аномалий (дни без продаж)
ННе определено
PythonЛегкийвопрос
Объясни типы merge в Pandas: left, right, outer, inner, cross. Когда какой ис…
Объясни типы merge в Pandas: left, right, outer, inner, cross. Когда какой использовать?
import pandas as pd
df1 = pd.DataFrame({'key': [1, 2, 3], 'val_a': ['a', 'b', 'c']})
df2 = pd.DataFrame({'key': [2, 3, 4], 'val_b': ['x', 'y', 'z']})
# inner — только совпадающие ключи (пересечение)
pd.merge(df1, df2, on='key', how='inner') # key: 2, 3# left — все из левой + совпадения из правой
pd.merge(df1, df2, on='key', how='left') # key: 1, 2, 3# right — все из правой + совпадения из левой
pd.merge(df1, df2, on='key', how='right') # key: 2, 3, 4# outer — все из обеих (объединение)
pd.merge(df1, df2, on='key', how='outer') # key: 1, 2, 3, 4# cross — декартово произведение (каждый с каждым)
pd.merge(df1, df2, how='cross') # 3 × 3 = 9 строк
Когда использовать:
inner — нужны только записи с совпадениями в обеих таблицах
left — сохранить все записи основной таблицы, дополнив данными
outer — полная картина, включая записи без пары
cross — генерация комбинаций (например, все пары товар × магазин)
ННе определено
PythonЛегкийвопрос
В чём разница между groupby().transform() и groupby().apply() в Pandas
В чём разница между groupby().transform() и groupby().apply() в Pandas? Когда что использовать?
import pandas as pd
df = pd.DataFrame({
'group': ['A', 'A', 'B', 'B'],
'value': [10, 20, 30, 40]
})
# transform — возвращает Series того же размера, что и исходный df
df['group_mean'] = df.groupby('group')['value'].transform('mean')
# [15, 15, 35, 35] — каждой строке приписано среднее её группы# apply — возвращает результат произвольной формы
result = df.groupby('group')['value'].apply(list)
# A: [10, 20], B: [30, 40]
Ключевые различия:
transform
apply
Размер результата
Такой же, как вход
Произвольный
Применение
Поэлементные агрегаты
Произвольные функции
Скорость
Быстрее (оптимизирован)
Медленнее (Python loop)
Используй transform для: нормализации, z-score, заполнения пропусков средним по группе, процента от группы.
Используй apply для: сложных функций, возвращающих несколько столбцов или агрегат.
ННе определено
PythonСреднийзадача
Что такое декоратор в Python
Что такое декоратор в Python? Напиши декоратор с аргументами, который повторяет вызов функции N раз и возвращает список результатов.
pivot_table — когда данные уже в DataFrame и нужна агрегация по значениям
ННе определено
PythonСреднийзадача
Какие стратегии обработки пропусков (NaN) существуют в Pandas
Какие стратегии обработки пропусков (NaN) существуют в Pandas? Покажи fillna с разными подходами.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'value': [1, np.nan, 3, np.nan, 5],
'group': ['A', 'A', 'B', 'B', 'B']
})
# 1. Заполнить константой
df['value'].fillna(0)
# 2. Заполнить средним / медианой
df['value'].fillna(df['value'].mean())
df['value'].fillna(df['value'].median())
# 3. Заполнить средним по группе
df['value'] = df.groupby('group')['value'].transform(
lambda x: x.fillna(x.mean())
)
# 4. Forward fill / backward fill (временные ряды)
df['value'].ffill() # предыдущим значением
df['value'].bfill() # следующим значением# 5. Интерполяция
df['value'].interpolate(method='linear')
# 6. Удаление строк с пропусками
df.dropna(subset=['value'])
Выбор стратегии:ffill/bfill — для временных рядов; среднее по группе — для категориальных данных; удаление — если пропусков < 5% и они случайны (MCAR).
ННе определено
PythonЛегкийвопрос
Объясни lambda-функции и встроенные map, filter, reduce. Чем они отличаются о…
Объясни lambda-функции и встроенные map, filter, reduce. Чем они отличаются от list comprehension?
from functools import reduce
numbers = [1, 2, 3, 4, 5]
# lambda — анонимная функция
square = lambda x: x ** 2# map — применяет функцию к каждому элементуlist(map(lambda x: x ** 2, numbers)) # [1, 4, 9, 16, 25]# Эквивалент: [x ** 2 for x in numbers]# filter — оставляет элементы, для которых функция Truelist(filter(lambda x: x > 3, numbers)) # [4, 5]# Эквивалент: [x for x in numbers if x > 3]# reduce — последовательно применяет функцию к парам
reduce(lambda a, b: a + b, numbers) # 15 (сумма)
reduce(lambda a, b: a * b, numbers) # 120 (произведение)
List comprehension vs map/filter:
Comprehension — более Pythonic и читаемый
map/filter — бывают удобнее с готовыми функциями (map(str, numbers))
reduce — нет прямого аналога в comprehension; для суммы/произведения лучше sum()/math.prod()
ННе определено
PythonСреднийзадача
Покажи возможности f-строк в Python: базовое форматирование, выравнивание, чи…
Покажи возможности f-строк в Python: базовое форматирование, выравнивание, числа с разделителями, отладочный вывод.
Сформулируй центральную предельную теорему (ЦПТ). Почему она важна для аналитика
Сформулируй центральную предельную теорему (ЦПТ). Почему она важна для аналитика?
Центральная предельная теорема (ЦПТ):
При достаточно большом размере выборки (n → ∞), распределение выборочного среднего стремится к нормальному, независимо от распределения исходной генеральной совокупности.
X̄ ~ N(μ, σ²/n), где μ и σ² — параметры генеральной совокупности.
Почему это важно:
A/B тесты: даже если метрика (выручка, конверсия) распределена ненормально, среднее по большой выборке будет ~ нормальным → можно применять t-test.
Доверительные интервалы: формула X̄ ± Z × σ/√n работает благодаря ЦПТ.
Практический порог: обычно n ≥ 30 достаточно для «нормальности» среднего. Для сильно скошенных распределений может потребоваться n ≥ 100+.
Ограничения: ЦПТ требует конечной дисперсии. Для распределений с «тяжёлыми хвостами» (Cauchy) не работает.
ННе определено
СтатистикаЛегкийвопрос
Как правильно интерпретировать доверительный интервал
Как правильно интерпретировать доверительный интервал? Какие распространённые ошибки в интерпретации?
Корректная интерпретация:
95% доверительный интервал [a, b] означает: если мы повторим эксперимент много раз и построим ДИ каждый раз, то 95% таких интервалов будут содержать истинное значение параметра.
Распространённые ОШИБКИ:
❌ «Вероятность 95%, что истинное значение лежит в [a, b]»
→ Истинное значение — фиксированное число, а не случайная величина. Оно либо в интервале, либо нет.
❌ «95% данных попадают в этот интервал»
→ ДИ — про параметр (среднее), а не про отдельные наблюдения.
❌ «Если расширить ДИ, увеличится точность»
→ Расширение увеличивает уверенность (confidence), но снижает точность (precision).
Формула: X̄ ± Z_α/2 × σ/√n
Увеличить n → сузить ДИ (точнее)
Увеличить уровень доверия → расширить ДИ (надёжнее, но менее точно)
ННе определено
СтатистикаЛегкийвопрос
Что такое p-value
Что такое p-value? Что оно НЕ означает? Назови три распространённых заблуждения.
p-value — вероятность получить такой же или более экстремальный результат при условии, что нулевая гипотеза верна.
Три главных заблуждения:
❌ p-value = вероятность того, что H0 верна
✅ p-value — вероятность данных при H0, а не вероятность H0 при данных. Это P(data | H0), а не P(H0 | data).
❌ p = 0.03 значит, что эффект есть с вероятностью 97%
✅ p-value ничего не говорит о вероятности альтернативной гипотезы.
❌ p = 0.049 (значимо) и p = 0.051 (незначимо) — принципиально разные результаты
✅ Порог α произволен. Разница между 0.049 и 0.051 ничтожна. Важен размер эффекта и доверительный интервал.
Что делать вместо бинарного «значимо/незначимо»:
Смотреть на доверительный интервал для размера эффекта
Учитывать практическую значимость (MDE)
Отчитываться о p-value как числе, не только как да/нет
ННе определено
СтатистикаЛегкийвопрос
Объясни ошибки I и II рода. Приведи примеры из A/B тестирования.
Объясни ошибки I и II рода. Приведи примеры из A/B тестирования.
Ошибка I рода (α — False Positive):
Отвергли H0, когда она верна. Решили, что эффект есть, хотя его нет.
Пример: A/B тест показал значимый рост конверсии, мы раскатали изменение, но на самом деле роста не было — результат случайный.
Ошибка II рода (β — False Negative):
Не отвергли H0, когда она ложна. Не заметили реальный эффект.
Пример: Новая фича реально повышает конверсию на 2%, но тест не набрал достаточно данных и показал p > 0.05. Мы отклонили хорошую идею.
Связь:
α обычно = 0.05 (5% ложных срабатываний)
β обычно = 0.20 → мощность = 1 − β = 0.80 (80% шанс найти реальный эффект)
Уменьшение α → увеличение β (и наоборот)
Увеличение выборки → уменьшение обеих ошибок
H0 верна
H0 ложна
Отвергли H0
Ошибка I (α)
Верное решение
Не отвергли
Верное решение
Ошибка II (β)
ННе определено
СтатистикаЛегкийвопрос
Сформулируй закон больших чисел. Чем он отличается от ЦПТ
Сформулируй закон больших чисел. Чем он отличается от ЦПТ?
Закон больших чисел (ЗБЧ):
При увеличении числа наблюдений выборочное среднее сходится к математическому ожиданию генеральной совокупности.
X̄_n → μ при n → ∞
Отличие от ЦПТ:
ЗБЧ
ЦПТ
Говорит о
Сходимости к значению
Форме распределения
Утверждает
X̄ → μ
X̄ ~ N(μ, σ²/n)
Вопрос
«К чему сходится?»
«Как распределено?»
Пример: Бросаем монетку.
ЗБЧ: после 10000 бросков доля орлов ≈ 0.5
ЦПТ: если повторить серию из 100 бросков много раз, среднее количество орлов ~ N(50, 25)
Практическое следствие для аналитика: чем больше выборка, тем точнее наша оценка среднего. Но ЗБЧ не говорит, с какой скоростью идёт сходимость (это даёт ЦПТ через σ/√n).
ННе определено
СтатистикаЛегкийвопрос
Байесовский vs. частотный подход к статистике — в чём разница
Байесовский vs. частотный подход к статистике — в чём разница? Когда какой применяется?
Частотный (frequentist):
Параметр — фиксированное число
Вероятность — частота событий при многократном повторении
«Корреляция не означает причинность». Приведи 3 примера ложных корреляций и о…
«Корреляция не означает причинность». Приведи 3 примера ложных корреляций и объясни, почему они возникают.
Примеры ложных корреляций:
Продажи мороженого и утопления: оба растут летом. Причина — скрытая переменная (confounding variable): температура воздуха.
Количество пожарных и ущерб от пожара: чем больше пожарных на месте, тем больше ущерб. Причина — обратная причинность: большой пожар → вызывают больше пожарных.
Потребление сыра на душу населения и количество смертей от запутывания в простынях: spurious correlation — случайное совпадение трендов при большом количестве переменных.
Почему возникают:
Confounding (скрытая переменная) — Z влияет и на X, и на Y
Reverse causation — Y → X, а не X → Y
Spurious — случайное совпадение при множественных сравнениях
Selection bias — выборка не репрезентативна
Как установить причинность: рандомизированный контролируемый эксперимент (A/B тест).
ННе определено
СтатистикаЛегкийвопрос
Назови ключевые свойства нормального распределения. Что такое правило 68-95-99.7
Назови ключевые свойства нормального распределения. Что такое правило 68-95-99.7?
Нормальное распределение N(μ, σ²):
Свойства:
Симметрично относительно μ (среднее = медиана = мода)
Колоколообразная форма (bell curve)
Полностью определяется двумя параметрами: μ (среднее) и σ (стд. отклонение)
Сумма нормальных величин — тоже нормальная
Хвосты уходят в бесконечность, но быстро убывают
Правило 68-95-99.7 (эмпирическое правило):
68% данных в пределах μ ± 1σ
95% данных в пределах μ ± 2σ
99.7% данных в пределах μ ± 3σ
Примеры в аналитике:
Рост людей ~ N(170, 10²) → 95% людей ростом 150-190 см
Среднее время на сайте (после логарифмирования)
Ошибки измерений
Когда НЕ нормальное: выручка (right-skewed), время между событиями (экспоненциальное), количество событий (Пуассон).
ННе определено
СтатистикаСреднийзадача
Какие методы обнаружения выбросов существуют
Какие методы обнаружения выбросов существуют? Покажи IQR-метод и z-score на примере.
Бонферрони: α_adj = α / m (m — количество сравнений)
20 метрик: α_adj = 0.05 / 20 = 0.0025
Плюс: простой, консервативный
Минус: слишком строгий при большом m
Holm-Bonferroni: step-down процедура
Менее консервативный, чем Бонферрони
Сортируем p-value, сравниваем с α/(m−k+1)
FDR (Benjamini-Hochberg): контролирует долю ложных среди всех отвергнутых
Менее строгий, больше мощности
Подходит для exploratory analysis
Разделение метрик:
1-2 основные (primary) — полная коррекция
Защитные (guardrail) — без коррекции, но только для мониторинга
Информационные — для анализа, без принятия решений
ННе определено
A/B тестыСреднийзадача
Как определить необходимую длительность A/B теста
Как определить необходимую длительность A/B теста? Какие факторы учитывать?
Алгоритм определения длительности:
Определить метрики и baseline (текущее значение)
Определить MDE — минимальный эффект, который хотим поймать
Рассчитать размер выборки:
n = f(α, β, σ², MDE)
Длительность = n × 2 / дневной трафик
Факторы, влияющие на длительность:
Фактор
Влияние
Дисперсия метрики ↑
Длительность ↑
MDE ↓ (ловим мелкий эффект)
Длительность ↑
Трафик ↑
Длительность ↓
Мощность ↑ (1−β)
Длительность ↑
α ↓ (строже)
Длительность ↑
Дополнительные ограничения:
Минимум 1-2 полных недели (сезонность будни/выходные)
Novelty/primacy эффекты — первые 1-2 недели результат может быть нерепрезентативен
Праздники и акции — исключить или увеличить длительность
Нельзя останавливать досрочно при peeking (если не используется sequential testing)
ННе определено
A/B тестыЛегкийвопрос
Что такое метрики-гвардрейлы (guardrail metrics)
Что такое метрики-гвардрейлы (guardrail metrics)? Приведи примеры для e-commerce.
Guardrail metrics — защитные метрики, которые не должны значимо ухудшиться при раскатке изменения. Мы не оптимизируем их, а мониторим.
Примеры для e-commerce:
Техническике:
Скорость загрузки страницы (Core Web Vitals)
Error rate (500-ки, JS-ошибки)
Crash rate (мобильные приложения)
Пользовательские:
Bounce rate
Количество жалоб в поддержку
Доля возвратов
Churn rate
Бизнесовые:
Средний чек (если оптимизируем конверсию)
Конверсия (если оптимизируем средний чек)
Revenue per user (общая выручка)
Как использовать:
Гвардрейлы не участвуют в принятии решения о раскатке (если основная метрика выросла)
Но если гвардрейл значимо упал — стоп, разбираемся
Не применяем коррекцию множественного тестирования к гвардрейлам
ННе определено
A/B тестыЛегкийвопрос
Что такое стратификация в A/B тестах
Что такое стратификация в A/B тестах? Когда она полезна?
Стратификация — разделение пользователей на однородные подгруппы (страты) перед рандомизацией, чтобы обеспечить баланс между группами.
Как работает:
Делим пользователей по важному признаку (платформа, страна, сегмент)
Внутри каждой страты рандомизируем 50/50
Гарантируем одинаковое распределение признака в группах
Зачем:
Уменьшает дисперсию → уменьшает необходимый размер выборки
Гарантирует баланс по ключевым признакам
Особенно полезно при малом трафике
Пример:
Платформа (iOS/Android) сильно влияет на конверсию.
Без стратификации: может случайно попасть 60% iOS в контроль.
Со стратификацией: ровно 50/50 внутри каждой платформы.
Когда полезна:
Есть признак с сильным влиянием на метрику
Малый трафик (< 10000 в группе)
Высокая гетерогенность аудитории
Когда не нужна:
Большой трафик (рандомизация и так сбалансирует)
Нет явных сегментов с разным поведением
ННе определено
A/B тестыЛегкийвопрос
Что такое novelty effect и primacy effect в A/B тестах
Что такое novelty effect и primacy effect в A/B тестах? Как с ними бороться?
Novelty effect (эффект новизны):
Пользователи активнее взаимодействуют с новым вариантом просто потому, что он новый. Метрика B завышена в начале теста.
Пример: Новая кнопка яркого цвета → больше кликов в первые дни, потом привыкают.
Primacy effect (эффект привычки):
Пользователи продолжают вести себя по-старому, игнорируя изменения. Метрика B занижена в начале.
Пример: Переместили навигацию → пользователи не замечают, ходят по старым путям.
Как бороться:
Достаточная длительность — минимум 2-3 недели, чтобы эффекты «устаканились».
Анализ по когортам:
Новые пользователи (не видели старый вариант) — нет primacy/novelty
Старые пользователи — подвержены эффектам
Если метрика разная для когорт — эффект присутствует
Динамика по дням: построить график метрики по дням теста. Если тренд виден — эффект не «устоялся».
Тестировать только на новых пользователях (если возможно).
ННе определено
A/B тестыЛегкийвопрос
Зачем проводят AA-тест перед запуском A/B
Зачем проводят AA-тест перед запуском A/B? Какие проверки он включает?
AA-тест — эксперимент без изменений: обе группы видят одинаковый вариант.
Цель: убедиться, что инфраструктура A/B тестирования работает корректно.
Что проверяем:
SRM (Sample Ratio Mismatch):
Соотношение групп = ожидаемому (50/50)?
χ²-тест или binomial test
Баланс ковариат:
Возраст, платформа, регион — одинаково распределены?
DAU упал на 15% за неделю. Опиши фреймворк анализа: какие шаги предпримешь
DAU упал на 15% за неделю. Опиши фреймворк анализа: какие шаги предпримешь?
Фреймворк анализа падения DAU:
1. Определить масштаб:
Когда именно началось падение? (день, час)
Все платформы или одна (web/iOS/Android)?
Все регионы или один?
2. Внешние факторы:
Сезонность (праздники, каникулы)
Действия конкурентов
Изменения в App Store / Google Play (обновление рейтинга)
3. Технические проблемы:
Аварии серверов, деплои, увеличение латенси
Баги в трекинге (данные не доходят)
CDN/DNS проблемы
4. Продуктовые изменения:
Новые релизы (регрессия UX)
Изменения в онбординге
A/B тесты с негативным эффектом
5. Маркетинг:
Остановка рекламных кампаний
Изменение каналов привлечения
Пуш-уведомления (отключили/поменяли)
6. Декомпозиция DAU:
DAU = Новые + Вернувшиеся + Удержанные
Какая составляющая упала?
Если новые → проблема привлечения
Если удержанные → проблема продукта
ННе определено
КейсыСложныйкейс
Тебе нужно спроектировать систему метрик для новой фичи — рекомендации товаро…
Тебе нужно спроектировать систему метрик для новой фичи — рекомендации товаров на главной странице. Какие метрики выберешь?
Иерархия метрик для рекомендаций:
North Star (бизнес-цель):
Revenue per user (выручка на пользователя)
Целевые (primary):
CR просмотр рекомендации → клик на товар
CR клик → добавление в корзину
CR корзина → покупка
Доля выручки от рекомендованных товаров
Качество рекомендаций:
CTR блока рекомендаций
Разнообразие (% уникальных категорий в рекомендациях)
Покрытие каталога (% товаров, которые попадают в рекомендации)
Средняя позиция клика (ближе к 1 — лучше)
Защитные (guardrails):
Общая конверсия сайта (не упала ли?)
Bounce rate главной страницы
Скорость загрузки (рекомендации не замедляют страницу?)
Доля возвратов рекомендованных товаров
Долгосрочные:
7-day / 30-day retention
LTV пользователей, кликавших на рекомендации
ННе определено
КейсыСложныйкейс
Что такое North Star Metric
Что такое North Star Metric? Как выбрать правильную NSM для продукта?
North Star Metric (NSM) — единственная метрика, которая лучше всего отражает ценность, которую продукт даёт пользователям, и коррелирует с долгосрочным ростом бизнеса.
Критерии хорошей NSM:
Отражает ценность для пользователя (не только для бизнеса)
Является leading indicator (предсказывает будущий рост)
Все команды могут на неё влиять
Понятна всей компании
Примеры:
Продукт
NSM
Spotify
Время прослушивания
Airbnb
Количество забронированных ночей
Facebook
Количество DAU
Slack
Количество отправленных сообщений
E-commerce
Количество заказов (или частота покупок)
Антипаттерны:
Revenue как NSM (lagging, не отражает ценность для пользователя)
Vanity metrics (регистрации без активации)
Несколько NSM (теряется фокус)
Как выбрать:
Определить ключевое действие, показывающее, что пользователь получил ценность
Проверить корреляцию с retention и revenue
Убедиться, что метрика растёт при росте бизнеса
ННе определено
КейсыСложныйкейс
Конверсия воронки покупки упала. Как найти проблемный шаг
Конверсия воронки покупки упала. Как найти проблемный шаг? Опиши подход к анализу воронки.
Фреймворк анализа воронки:
1. Определить шаги воронки:
Главная → Каталог → Карточка товара → Корзина → Оформление → Оплата → Подтверждение
2. Найти проблемный шаг:
Построить конверсию каждого шага: сейчас vs. неделю/месяц назад
Где наибольшее абсолютное падение?
Учесть сезонность (сравнивать с аналогичным периодом)
3. Сегментировать проблемный шаг:
По платформе (web/iOS/Android)
По устройству (desktop/mobile)
По источнику трафика
По сегменту пользователей (новые/старые)
По категории товаров
4. Искать причину:
Технические: ошибки, увеличение времени загрузки, баги
Продуктовые: изменения UI, A/B тесты
Внешние: конкуренты, сезонность, цены
5. Дополнительные инструменты:
Session replay (Hotjar, FullStory)
Heatmaps (клики, скролл)
Error logs
Правило: начинать с самого широкого среза, сужать к конкретному сегменту + шагу.
ННе определено
КейсыСложныйкейс
Как построить retention analysis
Как построить retention analysis? Какие виды retention существуют?
Виды Retention:
Classic (N-day) Retention: вернулся именно в день N
Day 1, Day 7, Day 30
Самый строгий, может быть «шумным»
Rolling Retention: вернулся в день N или позже
Всегда ≥ Classic Retention
Показывает «живых» пользователей
Bracket Retention: вернулся в интервале [N, M]
Week 1 (день 1-7), Week 2 (день 8-14)
Сглаживает шум Classic Retention
Построение:
WITH cohorts AS (
SELECT user_id,
DATE_TRUNC('week', MIN(first_event)) AS cohort
FROM events GROUPBY user_id
),
activity AS (
SELECTDISTINCT user_id,
DATE_TRUNC('week', event_date) AS active_week
FROM events
)
SELECT
c.cohort,
COUNT(DISTINCT c.user_id) AS cohort_size,
COUNT(DISTINCTCASEWHEN a.active_week = c.cohort +INTERVAL'1 week'THEN a.user_id END) AS retained_w1
FROM cohorts c
LEFTJOIN activity a ON c.user_id = a.user_id
GROUPBY c.cohort;
Benchmarks: Day 1: 25-40%, Day 7: 10-20%, Day 30: 5-10% (зависит от продукта).
ННе определено
КейсыСложныйкейс
Как рассчитать unit-экономику продукта
Как рассчитать unit-экономику продукта? Когда продукт становится прибыльным?
За 5 секунд должно быть понятно: «всё хорошо» или «есть проблема»
Цветовая индикация: зелёный/жёлтый/красный
Антипаттерны:
❌ 50 графиков на одном экране
❌ Дашборд, который никто не смотрит
❌ Только абсолютные числа без контекста (без сравнения)
❌ Круговые диаграммы с 15 сегментами
❌ 3D-графики
Чеклист:
Есть заголовок и описание
Указан период данных и время обновления
Ключевые метрики видны без скролла
Есть фильтры (период, сегмент)
Графики подписаны (оси, легенды)
ННе определено
ПоведенческиеЛегкийвопрос
Как работать со стейкхолдерами: PM, разработчиками, руководством
Как работать со стейкхолдерами: PM, разработчиками, руководством? Какие типичные ошибки?
Работа с разными стейкхолдерами:
С Product Manager:
Помогай формулировать гипотезы на данных
Предлагай метрики, а не просто считай запрошенные
Предупреждай о подводных камнях AB-тестов
Ошибка: делать всё, что просят, без вопроса «зачем?»
С разработчиками:
Чётко формулируй требования к данным (какие ивенты нужны, какие поля)
Помогай с ТЗ на аналитические ивенты
Ошибка: «мне нужны данные» без спецификации
С руководством:
Выводы, не процесс: «Нужно делать X, потому что Y»
Один слайд > 10 таблиц
Риски и неопределённость — честно
Ошибка: 40-слайдовая презентация с подробным SQL
Типичные ошибки аналитика:
Отвечать на запрос, не поняв настоящую задачу
Перфекционизм: 2 недели на отчёт, который нужен был вчера
Не уточнять deadline и приоритет
Не документировать решения и предпосылки
Молчать, если задача невыполнима или бессмысленна
ННе определено
SQLЛегкийвопрос
Что такое технический долг в данных (data tech debt)
Что такое технический долг в данных (data tech debt)? Приведи примеры и способы борьбы.
Технический долг в данных — накопленные проблемы в данных, пайплайнах и аналитической инфраструктуре, которые замедляют работу и создают риски.
Примеры:
Недокументированные пайплайны: никто не знает, что делает скрипт 3-летней давности, но от него зависят 5 дашбордов.
Дубликаты метрик: 3 таблицы считают revenue по-разному. Какая правильная?
Сломанные тесты: проверки качества отключены, потому что «часто падали».
Legacy-код: SQL-запросы на 500 строк без комментариев.
Прямые запросы к production DB: аналитики ходят в прод вместо хранилища.
Способы борьбы:
Документация: каждая таблица/метрика — описание + владелец
Data contracts: соглашение с разработчиками о формате данных
Мониторинг: алерты на аномалии, freshness checks
Рефакторинг: выделять время (20%) на улучшение инфраструктуры
Code review: для SQL/dbt моделей так же, как для кода
Deprecation: явно помечать устаревшие таблицы и удалять через N месяцев
ННе определено
SQLЛегкийвопрос
Зачем и как документировать аналитические пайплайны
Зачем и как документировать аналитические пайплайны? Какие инструменты помогают?
Зачем документировать:
Новый аналитик должен за день понять, как устроена система
При инциденте быстро найти владельца и логику расчёта
Избежать «bus factor = 1» (один человек знает всё)
Что документировать:
Таблицы/модели:
Описание: что хранит, зачем, кто владелец
Описание полей: тип, значения, бизнес-смысл
Связи: откуда данные, куда используются
Пайплайны:
DAG: визуальная схема зависимостей
Расписание: когда запускается
SLA: когда данные должны быть готовы
Метрики:
Определение: точная формула
Источник: из какой таблицы
Ограничения: что не учитывает
Инструменты:
dbt docs — автогенерация документации из YAML-описаний
DataHub / Amundsen — каталог данных с lineage
Notion / Confluence — для бизнес-контекста
README в репозитории — для технических деталей
Правило: документация рядом с кодом (dbt YAML, SQL-комментарии) > отдельный документ (быстро устаревает).
Avito
КейсыСложныйкейс
Дизайн A/B теста для рекомендательной системы
Продакт просит запустить A/B тест для нового алгоритма рекомендаций. Как ты спроектируешь эксперимент? Опиши метрики, контрольную/тестовую группы, длительность теста и критерии остановки.
Шаги проектирования A/B теста:
1. Определить метрику успеха:
Первичная: CTR (клики по рекомендациям), конверсия в покупку
Guardrail: GMV, retention, DAU — убедиться, что не роняем
2. Сегментация и рандомизация:
Единица рандомизации: user_id (не сессия — избегаем перекрёстного загрязнения)
Стратифицированная выборка по активности пользователей
3. Размер выборки:
Через калькулятор мощности: MDE = 5%, α = 0.05, power = 0.8
Минимум 2 недели для учёта недельной сезонности
4. Критерии остановки:
Досрочная остановка только при guardrail-нарушении (SRM или значимое падение GMV)
Не пикать p-value каждый день — нужен sequential testing или фиксированный срок
5. Анализ после теста:
Проверка SRM (Sample Ratio Mismatch) перед интерпретацией
t-test или bootstrap для метрики
Анализ по сегментам (новые vs. старые пользователи)
Avito
КейсыСложныйкейс
Диагностика падения ключевой метрики
Ты замечаешь, что DAU упал на 15% за последние 3 дня. Опиши, как диагностируешь проблему: с чего начнёшь, какие гипотезы проверишь и в каком порядке.
Фреймворк диагностики:
1. Проверить данные, не бизнес:
Нет ли проблем в пайплайне сбора данных? (задержки, потеря событий)
Корректно ли работает трекинг?
2. Декомпозиция метрики:
DAU = новые + вернувшиеся + реактивированные
Что именно упало? Новые пользователи или удержание?
3. Сегментация:
По платформе (iOS / Android / web)
По географии, каналу привлечения, версии приложения
Позволяет локализовать источник
4. Внешние факторы:
Был ли релиз? Изменения в пуш-уведомлениях? Маркетинговые кампании?
Праздники, сезонность?
5. Гипотезы по приоритету:
Технический сбой (быстро проверяется)
Деградация UX после релиза
Изменение в привлечении (снизился бюджет / ухудшились объявления)
Органическое снижение (тренд)
Avito
КейсыСложныйкейс
Метрики качества поиска на маркетплейсе
Ты аналитик на маркетплейсе. Задача: оценить качество алгоритма поиска. Предложи набор метрик и поясни, как бы ты их собирал.
Ключ: связать запрос → клик → покупку через session_id
Avito
КейсыСложныйкейс
Влияние промокодов на LTV клиента
Маркетинг хочет понять, влияют ли промокоды положительно на LTV или просто переключают уже лояльных пользователей на скидку. Как подойдёшь к анализу?
Проблема: промокоды могут быть инкрементальными (привлекают новых / удерживают уходящих) или каннибализирующими (дают скидку тем, кто купил бы и так).
Подход 1 — Анализ без эксперимента:
Сегментировать пользователей по первому типу покупки (с промо / без)
Сравнить LTV-кривые (retention × средний чек) по когортам
Слабость: selection bias — промо могли получить изначально более ценные сегменты
Подход 2 — A/B тест (предпочтительный):
Случайно разделить аудиторию: получают промо (B) vs. не получают (A)
Единица рандомизации: user_id
Метрики: LTV за 30/60/90 дней, retention, GMV, частота покупок
Длительность: минимум 4-8 недель для LTV-сигнала
Дополнительный анализ:
Сегментировать по «ценности» пользователя до промо — каннибализация выше среди лояльных
Incremental Revenue = Revenue(B) - Revenue(A) — окупает ли скидку?
Avito
КейсыСложныйкейс
Приоритизация продуктовых фич на основе данных
У команды 10 идей для улучшения приложения, но спринт только на 3 фичи. Продакт просит тебя помочь приоритизировать на основе данных. Какой подход предложишь?
Фреймворк ICE-score с данными:
ICE = Impact × Confidence × Ease (каждый 1–10)
Impact (влияние):
Оценить по историческим данным: сколько пользователей затрагивает фича?
Если есть похожие прецеденты — смотри на delta-метрику из тех A/B тестов
Если нет — экспертная оценка + сравнение с бенчмарками
Confidence (уверенность):
Есть ли данные, что пользователи испытывают эту боль? (опросы, heat maps, funnel drops)
Качество гипотезы: основана на данных или на мнении?
Ease (сложность):
Оценка от разработки (story points или T-shirt size)
Процесс:
Собрать ICE-таблицу вместе с командой
Нормировать оценки (избежать «всё 10»)
Отсортировать по ICE-score
Проверить: нет ли зависимостей между фичами?
Топ-3 взять в спринт
Дополнительно: учитывать strategic alignment — даже низко-оценённая фича может быть важна для OKR.
ППридумано ИИ
SQLЛегкийзадача
Пользователи без покупок
Есть таблицы `users(id, name)` и `orders(id, user_id, amount)`. Напиши запрос, который вернёт всех пользователей, у которых ещё не было ни одного заказа.
SELECT u.id, u.name
FROM users u
LEFTJOIN orders o ON o.user_id = u.id
WHERE o.id ISNULL;
Альтернатива через NOT EXISTS:
SELECT id, name
FROM users u
WHERENOTEXISTS (
SELECT1FROM orders o WHERE o.user_id = u.id
);
LEFT JOIN + IS NULL и NOT EXISTS эквивалентны по результату, но оптимизатор может выбирать разные планы. На больших таблицах NOT EXISTS часто работает быстрее.
ППридумано ИИ
SQLЛегкийзадача
Процент от общей суммы
Есть таблица `sales(category, revenue)`. Выведи каждую категорию, её выручку и долю от общей выручки (в процентах, округлённую до 2 знаков).
SELECT
category,
revenue,
ROUND(revenue *100.0/SUM(revenue) OVER (), 2) AS pct
FROM sales
ORDERBY revenue DESC;
SUM(revenue) OVER () — оконная функция без секции PARTITION: суммирует по всем строкам. Результат можно также получить через CTE с предварительным подсчётом итога, но оконная функция короче.
ППридумано ИИ
SQLСреднийзадача
Топ-3 товара в каждой категории
Таблица `products(id, category, name, revenue)`. Выведи топ-3 товара по выручке в каждой категории. При одинаковой выручке порядок произвольный.
SELECT category, name, revenue
FROM (
SELECT
category, name, revenue,
ROW_NUMBER() OVER (PARTITIONBY category ORDERBY revenue DESC) AS rn
FROM products
) ranked
WHERE rn <=3;
ROW_NUMBER() даёт уникальный номер внутри каждой группы. Если нужно учесть ничьи (вернуть всех с одинаковой выручкой), используй RANK() или DENSE_RANK().
ППридумано ИИ
SQLСреднийзадача
Нарастающий итог по дням
Таблица `daily_sales(sale_date DATE, amount NUMERIC)`. Выведи для каждого дня нарастающий итог выручки (с начала периода). Дни отсортированы по возрастанию.
SELECT
sale_date,
amount,
SUM(amount) OVER (ORDERBY sale_date ROWSBETWEEN UNBOUNDED PRECEDING ANDCURRENTROW) AS running_total
FROM daily_sales
ORDERBY sale_date;
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW — явное указание рамки окна (по умолчанию для ORDER BY то же самое, но явность помогает избежать ошибок).
ППридумано ИИ
SQLСреднийзадача
Разница между текущей и предыдущей строкой (LAG)
Таблица `metrics(dt DATE, value INT)` содержит ежедневные значения метрики. Выведи дату, значение и изменение по сравнению с предыдущим днём (NULL, если предыдущей строки нет).
SELECT
dt,
value,
value-LAG(value) OVER (ORDERBY dt) AS delta
FROM metrics
ORDERBY dt;
LAG(value) возвращает значение из предыдущей строки в заданном порядке. Для первой строки возвращает NULL — разность тоже NULL, что корректно.
ППридумано ИИ
SQLСреднийзадача
Сотрудники с зарплатой выше менеджера
Таблица `employees(id, name, salary, manager_id)`. `manager_id` ссылается на `id` в той же таблице. Найди всех сотрудников, чья зарплата выше зарплаты их непосредственного менеджера.
SELECT e.name AS employee, e.salary, m.name AS manager, m.salary AS manager_salary
FROM employees e
JOIN employees m ON e.manager_id = m.id
WHERE e.salary > m.salary;
Self-join: таблица джойнится сама с собой — e (сотрудник) и m (менеджер). Условие соединения — e.manager_id = m.id.
ППридумано ИИ
SQLСреднийзадача
Дубликаты в таблице
Таблица `emails(id, email)`. Найди все email-адреса, которые встречаются более одного раза, и покажи, сколько раз каждый встречается.
SELECT email, COUNT(*) AS cnt
FROM emails
GROUPBY email
HAVINGCOUNT(*) >1ORDERBY cnt DESC;
Чтобы удалить дубликаты, оставив только первую запись:
DELETEFROM emails
WHERE id NOTIN (
SELECTMIN(id) FROM emails GROUPBY email
);
ППридумано ИИ
SQLСложныйзадача
Медиана без функции MEDIAN
Таблица `salaries(id, amount)`. Найди медианную зарплату, не используя встроенную функцию MEDIAN (она есть не во всех СУБД).
SELECTAVG(amount) AS median
FROM (
SELECT amount,
ROW_NUMBER() OVER (ORDERBY amount) AS rn,
COUNT(*) OVER () AS total
FROM salaries
) t
WHERE rn IN (FLOOR((total +1) /2.0), CEIL((total +1) /2.0));
Логика: для нечётного total оба FLOOR/CEIL дают одно и то же — средний элемент. Для чётного — два средних; AVG от них и есть медиана. PERCENTILE_CONT(0.5) — встроенный вариант в PostgreSQL.
ППридумано ИИ
SQLСложныйзадача
Последовательные дни активности
Таблица `logins(user_id INT, login_date DATE)`. Найди пользователей, которые заходили 7 и более дней подряд. Верни `user_id` и максимальную длину непрерывной серии.
WITH deduped AS (
SELECTDISTINCT user_id, login_date FROM logins
),
grouped AS (
SELECT
user_id,
login_date,
login_date -ROW_NUMBER() OVER (PARTITIONBY user_id ORDERBY login_date)::int*INTERVAL'1 day'AS grp
FROM deduped
),
streaks AS (
SELECT user_id, COUNT(*) AS streak_len
FROM grouped
GROUPBY user_id, grp
)
SELECT user_id, MAX(streak_len) AS max_streak
FROM streaks
GROUPBY user_id
HAVINGMAX(streak_len) >=7;
Трюк: если вычесть порядковый номер строки из даты, все даты одной непрерывной серии получат одинаковую «группу». Затем группируем и считаем длину.
ППридумано ИИ
SQLСложныйзадача
Вторая по величине зарплата
Таблица `employees(id, salary)`. Напиши запрос, который вернёт вторую по величине уникальную зарплату. Если такой нет — верни NULL.
SELECTMAX(salary) AS second_highest
FROM employees
WHERE salary < (SELECTMAX(salary) FROM employees);
Через OFFSET:
SELECTDISTINCT salary
FROM employees
ORDERBY salary DESC
LIMIT 1OFFSET1;
Через DENSE_RANK:
SELECT salary
FROM (
SELECT salary, DENSE_RANK() OVER (ORDERBY salary DESC) AS rnk
FROM employees
) t
WHERE rnk =2
LIMIT 1;
Первый вариант возвращает NULL автоматически (MAX пустого множества). OFFSET-вариант не вернёт строку, если второй зарплаты нет — нужна обёртка.
ППридумано ИИ
PythonЛегкийзадача
FizzBuzz
Напиши функцию `fizzbuzz(n: int) -> list[str]`, которая возвращает список строк от 1 до n:
- "Fizz" если число делится на 3
- "Buzz" если делится на 5
- "FizzBuzz" если делится на 15
- иначе строку с самим числом
deffizzbuzz(n: int) -> list[str]:
result = []
for i inrange(1, n + 1):
if i % 15 == 0:
result.append("FizzBuzz")
elif i % 3 == 0:
result.append("Fizz")
elif i % 5 == 0:
result.append("Buzz")
else:
result.append(str(i))
return result
Компактный вариант:
deffizzbuzz(n):
return [
"FizzBuzz"if i % 15 == 0else"Fizz"if i % 3 == 0else"Buzz"if i % 5 == 0elsestr(i)
for i inrange(1, n + 1)
]
Важно проверять делимость на 15 первым — иначе "FizzBuzz" не попадёт.
ППридумано ИИ
PythonЛегкийзадача
Анаграммы
Напиши функцию `are_anagrams(s1: str, s2: str) -> bool`, которая возвращает True, если строки являются анаграммами (игнорируя регистр и пробелы).
Counter — O(n), sorted — O(n log n). Для интервью оба варианта приемлемы, но упомяни разницу в сложности.
ППридумано ИИ
PythonЛегкийзадача
Генератор Фибоначчи
Напиши генератор `fib()`, который бесконечно генерирует числа Фибоначчи: 0, 1, 1, 2, 3, 5, 8, …
deffib():
a, b = 0, 1whileTrue:
yield a
a, b = b, a + b
# Использование:
gen = fib()
print([next(gen) for _ inrange(10)]) # [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
yield превращает функцию в генератор — значения вычисляются лениво, не хранятся в памяти. a, b = b, a + b — атомарное присваивание, временная переменная не нужна.
ППридумано ИИ
PythonСреднийзадача
Two Sum
Напиши функцию `two_sum(nums: list[int], target: int) -> tuple[int, int]`, которая возвращает индексы двух чисел из списка, дающих в сумме `target`. Гарантируется, что ровно одно решение существует.
deftwo_sum(nums: list[int], target: int) -> tuple[int, int]:
seen = {} # value -> indexfor i, num inenumerate(nums):
complement = target - num
if complement in seen:
return (seen[complement], i)
seen[num] = i
raise ValueError("No solution")
Сложность: O(n) по времени и памяти. Наивный вариант с двумя циклами — O(n²). За один проход сохраняем «нужный» дополняющий элемент и сразу проверяем, встречали ли мы его раньше.
ППридумано ИИ
PythonСреднийзадача
Flatten вложенного списка
Напиши функцию `flatten(lst)`, которая рекурсивно разворачивает произвольно вложенный список в плоский. Например: `flatten([1, [2, [3, 4]], 5])` → `[1, 2, 3, 4, 5]`.
defflatten(lst):
result = []
for item in lst:
ifisinstance(item, list):
result.extend(flatten(item))
else:
result.append(item)
return result
Генераторный вариант не строит промежуточные списки — лучше по памяти при глубокой вложенности.
ППридумано ИИ
PythonСреднийзадача
Подстрока без повторяющихся символов
Напиши функцию `length_of_longest_substring(s: str) -> int`, возвращающую длину самой длинной подстроки без повторяющихся символов.
deflength_of_longest_substring(s: str) -> int:
char_index = {} # char -> last seen index
max_len = 0
left = 0for right, char inenumerate(s):
if char in char_index and char_index[char] >= left:
left = char_index[char] + 1
char_index[char] = right
max_len = max(max_len, right - left + 1)
return max_len
Паттерн sliding window: left — левая граница окна без дублей. При встрече повтора сдвигаем left вправо. Сложность O(n).
ППридумано ИИ
PythonСреднийзадача
Декоратор для кэширования (memoize)
Напиши декоратор `memoize`, который кэширует результаты вызова функции по её аргументам.
from functools import wraps
defmemoize(func):
cache = {}
@wraps(func)defwrapper(*args):
if args notin cache:
cache[args] = func(*args)
return cache[args]
return wrapper
@memoizedeffib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(50)) # быстро
@wraps(func) сохраняет __name__ и __doc__ оборачиваемой функции. В стандартной библиотеке есть functools.lru_cache — более полная реализация с ограничением размера кэша.
ППридумано ИИ
PythonСреднийзадача
Подсчёт вхождений в вложенной структуре
Напиши функцию `count_occurrences(data, target)`, которая считает, сколько раз значение `target` встречается в произвольно вложенной структуре из списков и словарей.
defcount_occurrences(data, target):
if data == target:
return1
count = 0ifisinstance(data, dict):
for v in data.values():
count += count_occurrences(v, target)
elifisinstance(data, (list, tuple)):
for item in data:
count += count_occurrences(item, target)
return count
# Пример:print(count_occurrences({"a": [1, 2, 1], "b": {"c": 1}}, 1)) # 3
ППридумано ИИ
PythonСложныйзадача
LRU Cache
Реализуй класс `LRUCache(capacity: int)` с методами:
- `get(key) -> int` — вернуть значение или -1
- `put(key, value)` — добавить; при превышении `capacity` удалить наименее недавно использованный элемент.
from collections import OrderedDict
classLRUCache:
def__init__(self, capacity: int):
self.capacity = capacity
self.cache = OrderedDict()
defget(self, key: int) -> int:
if key notinself.cache:
return -1self.cache.move_to_end(key) # отмечаем как недавно использованныйreturnself.cache[key]
defput(self, key: int, value: int) -> None:
if key inself.cache:
self.cache.move_to_end(key)
self.cache[key] = value
iflen(self.cache) > self.capacity:
self.cache.popitem(last=False) # удаляем самый старый
Сложность: O(1) для обоих методов. OrderedDict хранит порядок вставки; move_to_end + popitem(last=False) — ключ к эффективности. Без OrderedDict нужен двусвязный список + хэш-таблица.
ППридумано ИИ
PythonСложныйзадача
Группировка анаграмм
Напиши функцию `group_anagrams(words: list[str]) -> list[list[str]]`, которая группирует слова-анаграммы вместе.
from collections import defaultdict
defgroup_anagrams(words: list[str]) -> list[list[str]]:
groups = defaultdict(list)
for word in words:
key = tuple(sorted(word))
groups[key].append(word)
returnlist(groups.values())
# Пример:print(group_anagrams(["eat","tea","tan","ate","nat","bat"]))
# [["eat","tea","ate"], ["tan","nat"], ["bat"]]
Сложность: O(n · k log k), где k — длина слова. Ключ — отсортированный кортеж символов: у всех анаграмм он одинаков.
ППридумано ИИ
СтатистикаЛегкийвопрос
Что такое p-value
Объясни, что такое p-value. Как правильно его интерпретировать, и что является распространённой ошибкой при интерпретации?
p-value — это вероятность получить наблюдаемый результат (или более экстремальный), при условии что нулевая гипотеза H₀ верна.
Корректная интерпретация:
Малый p-value (< α) означает, что данные маловероятны при H₀ — повод отвергнуть H₀.
Распространённые ошибки:
«p-value — это вероятность того, что H₀ верна» — неверно. Это вероятность данных при H₀, не вероятность H₀.
«p < 0.05 значит эффект большой» — неверно. При большой выборке даже ничтожный эффект даёт p < 0.05.
«p > 0.05 значит H₀ верна» — неверно. Мы просто не нашли достаточно доказательств против неё.
Практически: всегда смотри на размер эффекта вместе с p-value.
ППридумано ИИ
СтатистикаЛегкийвопрос
Среднее vs. медиана: когда что использовать
В каких случаях медиана предпочтительнее среднего, а в каких — наоборот? Приведи практические примеры из аналитики.
Среднее чувствительно к выбросам, медиана — устойчива к ним.
Медиана предпочтительнее:
Доходы пользователей: несколько очень богатых завышают среднее (медиана зарплат по стране, LTV)
Время ответа сервера: один тормозящий запрос искажает среднее → используют p95/p99
Любые метрики с тяжёлым хвостом
Среднее предпочтительнее:
Оптимизация по сумме: если нужно суммировать (GMV = n × avg_check), среднее напрямую связано с итогом
Симметричные распределения без выбросов: нормально распределённые данные
При агрегации метрик: avg легко считается инкрементально, медиана — нет
Практический совет: смотреть на оба показателя и распределение целиком.
ППридумано ИИ
СтатистикаЛегкийвопрос
Ошибки I и II рода
Что такое ошибки первого и второго рода в статистике? Объясни на примере A/B теста.
Ошибка I рода (α, ложноположительная):
Отвергаем H₀, когда она на самом деле верна.
→ В A/B тесте: объявляем фичу эффективной, хотя разницы нет.
→ Контролируется уровнем значимости α (обычно 0.05).
Ошибка II рода (β, ложноотрицательная):
Не отвергаем H₀, когда она ложна.
→ В A/B тесте: не замечаем реального улучшения от фичи.
→ Контролируется мощностью теста (1 − β), обычно задают 0.8.
Компромисс:
Снижая α (меньше ложных срабатываний), мы повышаем β (чаще пропускаем эффект). Увеличение размера выборки снижает обе ошибки одновременно.
Мнемоника: I рода — «казнить невиновного», II рода — «отпустить виновного».
ППридумано ИИ
СтатистикаСреднийвопрос
Центральная предельная теорема (ЦПТ)
Сформулируй центральную предельную теорему. Почему она важна для A/B тестирования и анализа данных?
ЦПТ: При достаточно большом n выборочное среднее из независимых одинаково распределённых случайных величин (с конечной дисперсией) стремится к нормальному распределению, независимо от формы исходного распределения.
В A/B тестах метрики редко нормально распределены (выручка, время на сайте — скошенные). ЦПТ позволяет применять t-тест к средним даже для таких данных.
Чем больше выборка, тем лучше приближение — обычно n > 30 считается достаточным для грубых расчётов.
Доверительные интервалы и p-values в t-тесте основаны на нормальности средних.
Ограничения: не работает для тяжёлых хвостов (Коши), очень маленьких выборок.
ППридумано ИИ
СтатистикаСреднийвопрос
Теорема Байеса и условная вероятность
Объясни теорему Байеса. Задача: тест на болезнь даёт ложноположительный результат в 5% случаев и ложноотрицательный в 1%. Болеет 0.1% населения. Какова вероятность болезни при положительном тесте?
Повторить 10 000 раз → получить эмпирическое распределение.
95% доверительный интервал: перцентили 2.5% и 97.5%.
Преимущества:
Не требует предположений о форме распределения
Работает для любой статистики (медиана, R², …)
Особенно полезен при малых выборках
Ограничения: вычислительно дорогой; не работает для зависимых данных (временные ряды — нужен block bootstrap).
ППридумано ИИ
СтатистикаСреднийвопрос
Множественное тестирование
Что такое проблема множественного тестирования? Назови два способа корректировки и объясни разницу между ними.
Проблема: при одновременной проверке k гипотез вероятность хотя бы одного ложноположительного результата резко растёт. При 20 тестах с α=0.05 вероятность хотя бы одной ошибки I рода ≈ 64%.
Поправка Бонферрони:
α_adjusted = α / k
Контролирует FWER (Family-Wise Error Rate) — вероятность хотя бы одной ошибки.
Консервативна — при большом k мощность падает.
FDR (False Discovery Rate), поправка Бенджамини-Хохберга:
Контролирует долю ложных отклонений среди всех отклонённых H₀.
Менее строга, больше мощность — подходит для исследовательского анализа и омиксных данных.
Практика:
В A/B тестах с несколькими метриками → FDR или Bonferroni для первичной метрики
В геномике / многомерных анализах → Benjamini-Hochberg стандарт
ППридумано ИИ
СтатистикаСреднийвопрос
Проверка нормальности распределения
Как проверить, нормально ли распределены данные? Назови минимум два теста и один визуальный метод.
Визуальные методы:
Q-Q plot (Quantile-Quantile): сравнивает квантили выборки с теоретическими квантилями нормального распределения. При нормальности точки лежат на диагонали.
Shapiro-Wilk (n < 5000): H₀ — данные нормально распределены. p > 0.05 → не отвергаем нормальность. Один из мощнейших.
Kolmogorov-Smirnov: сравнивает эмпирическое распределение с теоретическим. Менее мощный, чем Shapiro-Wilk.
D'Agostino-Pearson: тест на асимметрию и эксцесс.
Практически:
При большом n (> 1000) тесты почти всегда найдут отклонение — из-за ЦПТ это часто не важно. Важнее Q-Q plot и понимание, зачем нужна нормальность.
ППридумано ИИ
СтатистикаСложныйвопрос
ANOVA: дисперсионный анализ
Что такое ANOVA (дисперсионный анализ) и когда её применяют? Чем однофакторная ANOVA отличается от t-теста?
ANOVA (Analysis of Variance) проверяет, различаются ли средние трёх и более групп.
H₀: μ₁ = μ₂ = … = μk (все средние равны)
H₁: хотя бы одна пара различается
Ключевая идея:
Сравнивает дисперсию между группами (Between-group) с дисперсией внутри групп (Within-group). F-статистика = MS_between / MS_within. Если F велико → группы отличаются.
Vs. t-тест:
t-тест: только 2 группы
ANOVA: 3+ группы без раздувания α (несколько t-тестов надо корректировать Бонферрони)
ANOVA говорит «есть различие», но не «где именно» → post-hoc тесты (Tukey, Bonferroni)
Применение в аналитике:
Сравнение нескольких вариантов (A/B/C/D тест)
Влияние географии/платформы на метрику
Но при нарушении предположений (гомоскедастичность, нормальность) → Kruskal-Wallis (непараметрический аналог)
ППридумано ИИ
СтатистикаСложныйвопрос
Доверительный интервал: что он означает
Объясни, что означает 95% доверительный интервал. Какая интерпретация корректна, а какая — ошибочна?
Корректная интерпретация:
Если повторять эксперимент бесконечно и каждый раз строить 95% ДИ, то 95% из этих интервалов будут содержать истинный параметр.
Ошибочные интерпретации:
«Вероятность 95%, что истинное значение внутри интервала» — неверно (в частотной статистике истинный параметр фиксирован, не случаен)
«95% данных лежат в этом интервале» — неверно (это перцентильный диапазон данных, не ДИ)
Практически:
Ширина ДИ показывает точность оценки:
Узкий ДИ → много данных, высокая точность
Широкий ДИ → мало данных, неопределённость
Для интерпретации результатов A/B теста: если ДИ для разности эффектов не включает 0 — результат значим. Ширина ДИ говорит об экономической значимости эффекта.
ППридумано ИИ
A/B тестыЛегкийвопрос
Что такое MDE (минимальный детектируемый эффект)
Что такое MDE в A/B тестировании? Как его задают и от чего он зависит?
MDE (Minimum Detectable Effect) — наименьший эффект, который тест способен обнаружить с заданной мощностью.
Задают исходя из бизнес-значимости: «нам не интересен эффект меньше +1% конверсии».
Зависит от:
Размера выборки (n ↑ → MDE ↓)
Уровня значимости α (строже α → MDE ↑)
Мощности теста (1−β) (выше мощность → MDE ↓, нужно больше данных)
Baseline метрики и её дисперсии
Формула (приближённо для двух групп):
$n = \frac{(z_{\alpha/2} + z_\beta)^2 \cdot 2\sigma^2}{\delta^2}$
Где δ — MDE, σ² — дисперсия метрики.
Практика: использовать калькулятор размера выборки. Стандарт: α=0.05, мощность=0.8.
ППридумано ИИ
A/B тестыЛегкийвопрос
Единица рандомизации в A/B тесте
Что такое единица рандомизации в A/B тесте? Какие варианты бывают и как выбрать правильный?
Единица рандомизации — объект, по которому разделяют контрольную и тестовую группы.
Основные варианты:
user_id — наиболее распространён. Один пользователь всегда в одной группе. Нет загрязнения между сессиями.
session_id — один пользователь может попасть в обе группы. Нарушает независимость наблюдений (SUTVA). Использовать с осторожностью.
cookie — промежуточный вариант; теряется при смене браузера/устройства.
географический кластер / магазин — для экспериментов с сетевыми эффектами или физических точек.
Принципы выбора:
Единица должна быть стабильной на протяжении теста
Нет «перетекания» между группами (SUTVA)
Как можно ниже уровень агрегации — больше статистической мощности
ППридумано ИИ
A/B тестыСреднийвопрос
Peeking problem в A/B тестах
Что такое peeking problem (проблема «подглядывания») в A/B тестировании? К каким последствиям приводит?
Проблема: исследователь регулярно смотрит на p-value в процессе теста и останавливает его, как только p < 0.05. Это резко завышает реальный уровень ошибки I рода.
Почему: при каждом промежуточном взгляде мы проводим дополнительный статистический тест. При достаточном числе «взглядов» p-value обязательно упадёт ниже α случайно.
Симуляция: если смотреть каждый день в течение 20 дней, вероятность хотя бы раз увидеть p < 0.05 у нулевого эффекта ≈ 30-40% (вместо 5%).
Решения:
Фиксированный срок — определить n заранее, смотреть результат один раз
Bayesian подход — можно останавливать при достаточной вероятности эффекта
Always-valid p-values (Optimizely, Eppo) — промышленные решения
ППридумано ИИ
A/B тестыСреднийвопрос
SRM (Sample Ratio Mismatch)
Что такое SRM в A/B тесте? Как его обнаружить и каковы основные причины?
SRM (Sample Ratio Mismatch) — несоответствие фактического соотношения пользователей в группах ожидаемому.
Пример: ожидали 50/50, получили 48/52.
Обнаружение: тест χ² (chi-squared) на соответствие долей:
H₀: соотношение соответствует ожидаемому
p < 0.01 → SRM есть, результаты теста ненадёжны
Причины:
Ошибки в логировании (один вариант теряет события)
Redirect-тест: бот-трафик отфильтровывается иначе для разных вариантов
Кэширование на стороне клиента
Ошибка в рандомизаторе (hash collision)
Сбой в доставке фичи
Важно: при обнаружении SRM → не интерпретировать результаты теста. Сначала разобраться с источником смещения.
ППридумано ИИ
A/B тестыСреднийвопрос
Эффект новизны в A/B тестах
Что такое эффект новизны (novelty effect) в A/B тестировании? Как с ним бороться?
Эффект новизны — пользователи взаимодействуют с новым вариантом активнее просто потому, что он новый, а не потому что он лучше. Через какое-то время поведение нормализуется.
Обратный эффект (change aversion): пользователи, привыкшие к старому интерфейсу, хуже взаимодействуют с новым в начале.
Признаки: значимое улучшение в первые дни, затем сходится к нулю.
Как бороться:
Сегментация: смотреть отдельно на новых пользователей (не подвержены novelty) и на вернувшихся
Увеличить срок теста — запустить на 3–4 недели, смотреть на поведение в конце периода
Cohort analysis: анализировать поведение пользователей по дням после попадания в тест
Holdout groups: долгосрочные тесты с длинным горизонтом
ППридумано ИИ
A/B тестыСреднийвопрос
Guardrail-метрики
Что такое guardrail-метрики в A/B тестировании? Приведи примеры и объясни зачем они нужны.
Guardrail-метрики — показатели, которые не должны значимо ухудшиться при запуске фичи. Они защищают бизнес от непреднамеренного вреда.
Зачем нужны:
Оптимизируя одну метрику (CTR на рекомендации), можно ненароком ухудшить другую (время сессии, retention). Guardrails — страховочная сетка.
Типичные guardrail-метрики:
Revenue / GMV (не роняем выручку)
DAU / Retention (не теряем пользователей)
Latency (не ухудшаем скорость)
Crash rate / Error rate (не ломаем стабильность)
Customer support tickets
Логика принятия решений:
Первичная метрика ↑, guardrails в норме → запускаем
Первичная ↑, но guardrail ↓ → нужен дополнительный анализ
Guardrail существенно ухудшился → не запускаем, даже если первичная выросла
ППридумано ИИ
A/B тестыСреднийвопрос
Байесовский vs. частотный подход в A/B
В чём разница между байесовским и частотным (frequentist) подходами к A/B тестированию? Назови плюсы и минусы каждого.
Частотный (frequentist):
Понятие: p-value, доверительный интервал
Интерпретация: «вероятность данных при H₀»
Нельзя остановить тест досрочно без коррекции (peeking problem)
Широко принят, легко объяснить
Интуитивно сложен для нестатистиков («что значит p=0.03?»)
Байесовский:
Понятие: posterior probability, доверительная область (credible interval)
Интерпретация: «вероятность, что вариант B лучше, составляет 97%»
Понятен стейкхолдерам
Можно останавливать при достижении нужной вероятности
Естественно включает prior-знания
Чувствителен к выбору prior; при неинформативном prior может требовать больше данных
Вычислительно дороже
На практике: многие крупные компании (Booking, Netflix) используют байесовский подход для интерпретируемости.
ППридумано ИИ
A/B тестыСложныйвопрос
CUPED: снижение дисперсии в A/B тестах
Что такое CUPED (Controlled-experiment Using Pre-Experiment Data) и как он повышает мощность A/B теста?
CUPED — метод снижения дисперсии метрики за счёт использования ковариаты (чаще всего — предтестовых данных пользователя).
Идея:
Большая часть вариации метрики объясняется постоянными свойствами пользователя. Если вычесть предсказуемую часть, остаток (residual) будет иметь меньшую дисперсию → тест мощнее.
Формула:
$Y_{cuped} = Y - \theta \cdot X$
Где X — предтестовое значение той же метрики, θ = Cov(X,Y)/Var(X).
Результат: при высокой корреляции X и Y дисперсия уменьшается на (1 − ρ²) × 100%. При ρ=0.7 → экономия ~51% объёма выборки.
Требования:
X должна быть собрана до рандомизации
X независима от назначения в группу
Применение: Microsoft (изобрели метод), Booking.com, Netflix используют по умолчанию.
ППридумано ИИ
A/B тестыСложныйвопрос
Сетевые эффекты в A/B тестах
Почему стандартный A/B тест ненадёжен при наличии сетевых эффектов? Как адаптировать дизайн эксперимента?
Проблема:
При сетевых эффектах действия пользователя влияют на других пользователей. Контрольная и тестовая группы «заражают» друг друга → нарушается условие независимости (SUTVA).
Пример: тест фичи «Отправить приглашение другу». Пользователь из группы B приглашает друга из группы A → группа A «загрязнена».
Методы:
Cluster randomization (географические кластеры): разделить не пользователей, а города/регионы. Дороже (нужно больше кластеров), снижает мощность.
Graph-based clustering: разбить социальный граф на плотные сообщества, тестировать целые сообщества.
Ego-network experiments (LinkedIn): рандомизация по «эго-сетям» пользователей.
Two-sided marketplace experiments: тестировать отдельно supply и demand.
Компании: LinkedIn, Facebook, Airbnb публикуют кейсы своих подходов.
ППридумано ИИ
A/B тестыСложныйвопрос
Тестирование редких событий
Первичная метрика — конверсия в покупку (0.5%). Как провести A/B тест при таком низком baseline? Какие альтернативные подходы существуют?
Проблема: малый baseline → нужна огромная выборка для заданного MDE.
При baseline=0.5%, MDE=10% (т.е. 0.55%), α=0.05, мощность=0.8 → нужно ~1.6 млн пользователей на группу.
Подходы:
Суррогатные метрики (proxy metrics): использовать более частое событие на воронке (клик, добавление в корзину), которое коррелирует с покупкой. Экономит выборку, но нужно валидировать суррогат.
Увеличить MDE: протестировать более сильное изменение (не +10%, а +25%). Минус — нет информации о малых эффектах.
Байесовский подход: более эффективен при малых выборках за счёт prior-а.
Sequential design / SPRT: останавливать тест при накоплении доказательств (экономит время).
Сегментация: тестировать только на аудитории с высоким conversion propensity (например, пользователи, добавившие в корзину).
ППридумано ИИ
КейсыЛегкийкейс
Рост отказов на шаге оплаты
Конверсия со страницы оплаты упала на 10% за последние 3 дня. Как будешь диагностировать проблему?
Шаг 1 — Проверить данные:
Нет ли пропусков в логах или сбоя трекинга оплаты
Сравнить событие «страница открыта» с «оплата нажата» — где именно отвал
Шаг 2 — Разбить по сегментам:
Устройство: мобайл vs. десктоп (мобильная верстка сломана?)
Платёжная система: одна из систем (карта, SberPay) упала
Браузер/ОС: обновление приложения с багом
Тип пользователя: новые vs. старые
Шаг 3 — Внешние изменения:
Был ли деплой в эти дни? Изменения в форме оплаты?
Выросли ли ошибки от платёжного провайдера?
Шаг 4 — Качественные сигналы:
Записи сессий (Hotjar, Fullstory): куда кликают перед уходом
Тикеты в поддержку: жалобы на ошибки при оплате
Вывод и действие: определить сегмент → откатить деплой / исправить ошибку / заэскалировать в команду платёжного шлюза.
ППридумано ИИ
КейсыСреднийкейс
Падение retention у новых пользователей
7-дневный Retention новых пользователей упал с 35% до 28% за последний месяц. При этом DAU стабилен. Как подойдёшь к анализу?
Почему DAU стабилен при падении Ret? Скорее всего, вырос поток новых пользователей — они компенсируют отток. Важно разделить потоки.
Декомпозиция:
Ret падает только у новых? Проверить вернувшихся и реактивированных отдельно
В каком канале привлечения упал Ret? (платный трафик, органика, рефералы)
Новая когорта хуже по качеству (боты, нерелевантная аудитория)?
Анализ онбординга:
Построить воронку онбординга: регистрация → первое ключевое действие → возврат
Где падает воронка по сравнению с прошлыми когортами?
Гипотезы:
Изменился продукт (деплой, UX): новые пользователи попадают в ухудшенный опыт
Изменился маркетинг: привлекаем менее целевую аудиторию
Сезонность / праздники (активность ниже в выходные месяца)
Изменилась конкуренция
Рекомендации: сравнить cohort-based воронку новых когорт с когортами 2–3 месяца назад.
ППридумано ИИ
КейсыСреднийкейс
Выбор North Star метрики
Ты аналитик в стриминговом сервисе. Продакт просит помочь выбрать North Star метрику. Предложи кандидатов и обоснуй выбор.
North Star метрика — единственный показатель, лучше всего отражающий долгосрочную ценность для пользователей и связанный с выручкой.
Кандидаты для стриминга:
Часы просмотра на пользователя в месяц — отражает вовлечённость, предсказывает удержание
% активных пользователей, просмотревших >X часов — качественный порог активности
Monthly Active Subscribers — бизнесовая метрика, но не отражает ценность
Завершённые просмотры — качество: досмотрел ли пользователь
Рекомендация: Часы просмотра / активный пользователь — хорошо предсказывает отток (меньше смотришь → уходишь) и рост (больше контента → больше смотришь → выше готовность платить). Netflix использует близкую метрику.
Критерии хорошей NSM:
Ведущий индикатор (не запаздывает)
Понятен всей команде
Действенный (на него можно влиять)
ППридумано ИИ
КейсыСреднийкейс
Оценка экономического эффекта фичи
Фича «Быстрая повторная покупка» была запущена по результатам A/B теста: +3% конверсии в повторную покупку. Как перевести это в денежный эффект?
Шаг 1 — Понять охват:
Сколько пользователей видят эту фичу в месяц? (n_eligible)
Если повторные покупки повышают Retention → дополнительный LTV-эффект
Шаг 5 — Доверительный интервал:
Построить CI вокруг оценки (из ДИ A/B теста для конверсии)
ППридумано ИИ
КейсыСреднийкейс
Метрики жалуются пользователи, но данные в норме
В поддержку поступают жалобы на медленную загрузку приложения. Но средняя скорость в мониторинге в норме — 1.2 сек. Как объяснишь расхождение и что проверишь?
Почему среднее в норме при жалобах:
Хвост распределения: медленно только у части (p95 или p99 высокий). Среднее не показывает выбросы.
Сегмент пользователей: медленно только на старых устройствах / слабом интернете / конкретной платформе
Проблема в конкретном регионе: CDN упал в Сибири
Ошибка метрики: не учитываются тайм-ауты или failed-запросы
Что проверить:
Построить перцентили: p50, p75, p95, p99 по скорости
Сегментировать: ОС, версия, география, тип соединения
Посмотреть на error rate: ошибки ≠ медленные ответы в обычных метриках
Проверить инфраструктурный мониторинг: CDN, mobile backend
Вывод: использовать перцентильные метрики (p95 latency) вместо среднего для мониторинга пользовательского опыта.
ППридумано ИИ
КейсыСреднийкейс
Аномальный рост одной когорты
Одна когорта пользователей показывает в 2 раза выше Retention, чем остальные. Как это объяснить и что делать?
Первая мысль: не спешить радоваться — нужно разобраться в причинах.
Гипотезы:
Артефакт данных: ошибка в логировании для этой когорты
Изменение в продукте: в момент привлечения этой когорты запустили фичу, которая улучшила онбординг
Качество аудитории: когорта из другого канала (органика vs. платный), другая демография
Специальная акция: промокод или бонус при регистрации создал «искусственный» Retention
Сезонность: привлекали в период высокого product-market fit (праздники, новый контент)
Действия:
Проверить данные: нет ли дублей, проблем с трекингом
Посмотреть каналы и источники трафика когорты
Восстановить таймлайн: что менялось в продукте и маркетинге в тот период
Если изменение в продукте — запустить A/B тест, чтобы проверить гипотезу
ППридумано ИИ
КейсыСложныйкейс
Каннибализация: новая фича ест старую
Новый блок рекомендаций «Для вас» показал в A/B тесте +5% к общему CTR. Но команда контента заметила, что просмотры из каталога упали на 7%. Что произошло и как принять решение?
Диагноз: каннибализация.
Пользователи переключились с каталога на персональные рекомендации — рекомендации «съели» часть трафика каталога.
Ключевые вопросы:
Изменился ли общий объём потребления контента (суммарные просмотры), или просто перераспределился?
Одинакова ли ценность контента через каталог и через рекомендации? (CTR → покупка, LTV)
Есть ли долгосрочный эффект: рекомендации могут снижать разнообразие потребления (filter bubble)
Анализ:
Считать net-суммарный CTR + downstream метрики (retention, revenue per user)
Сравнить качество просмотров: завершение, оценки, покупки
Принятие решения:
Если суммарная вовлечённость и бизнес-метрики выросли → запускать
Если перераспределение с каннибализацией ключевого KPI команды контента → обсуждать компромисс на уровне продуктового комитета
Вывод: без анализа сквозных метрик выводы преждевременны.
ППридумано ИИ
КейсыСложныйкейс
Построение модели предсказания оттока
Тебе нужно построить модель предсказания оттока пользователей. Опиши процесс: от постановки задачи до внедрения.
1. Постановка задачи:
Определить «отток»: не логинился 30 дней? Отменил подписку?
Горизонт предсказания: за сколько дней до оттока хотим предупредить?
Целевая аудитория: все пользователи или только активные?
2. Данные и фичи:
Поведенческие: частота, давность, глубина активности (RFM)
Транзакционные: сумма, частота покупок, снижение активности
Не accuracy (классы несбалансированы)! Precision, Recall, F1, ROC-AUC
Бизнес-метрика: стоимость ложноположительного (ненужная акция) vs. ложноотрицательного (потерянный пользователь)
4. Модель:
Baseline: логистическая регрессия
Лучше: Gradient Boosting (XGBoost/LightGBM) — хорошо на табличных данных
5. Внедрение:
Дата-пайплайн: ежедневный расчёт score
Интеграция с CRM: триггер на retention-акцию для top-N риск-пользователей
Мониторинг: дрейф данных (PSI), качество модели во времени
ППридумано ИИ
КейсыСложныйкейс
Долгосрочный эффект A/B теста на LTV
A/B тест показал нейтральный результат за 2 недели. Но команда подозревает, что эффект фичи проявляется в долгосрочной перспективе. Как оценить долгосрочный эффект?
Проблема краткосрочных тестов:
Двухнедельный тест не улавливает изменения в retention, LTV, частоте покупок — они накапливаются месяцами.
Подходы:
1. Holdout groups (долгосрочные группы):
Оставить небольшой holdout (5-10%) без фичи на 3–6 месяцев. Дорого, но надёжно. Используют Netflix, Google.
2. Surrogate metrics:
Найти краткосрочный показатель, коррелирующий с LTV (например, 7-дневный Retention → 6-месячный LTV). Требует исторической валидации связи.
3. Cohort analysis:
Сравнивать когорты пользователей, получивших фичу, с аналогичными когортами без неё — через 1, 3, 6 месяцев. Проблема: cohort selection bias.
4. Causal inference методы:
Difference-in-Differences, Synthetic Control, если нельзя держать постоянный holdout.
Рекомендация: договориться с бизнесом о метрике и горизонте до запуска, а не после. «Нейтральный через 2 недели» — не финальный ответ.
ППридумано ИИ
КейсыСложныйкейс
Система рекомендаций: с чего начать
Стартап просит тебя с нуля построить систему рекомендаций для маркетплейса. Опиши архитектуру и как двигаться итерационно.
Принцип: начать с простого, усложнять по данным.
Итерация 0 — Baseline (правила):
Популярные товары (bestsellers)
«С этим часто берут» (co-purchase)
Новинки категории
→ Быстро, не требует ML, даёт первый сигнал
Итерация 1 — Коллаборативная фильтрация:
User-item матрица: кто купил / просмотрел что
Item-based CF: «если купил A — рекомендуем B (похожие пользователи брали B)
Проблема: cold start для новых пользователей / товаров
Итерация 2 — Контентная фильтрация:
Embedding товаров по атрибутам (категория, цена, описание)
Решает cold start для новых товаров
Итерация 3 — Двухуровневая архитектура:
Retrieval (кандидаты): ANN-поиск в embedding-пространстве, 100–1000 кандидатов
Ranking: ML-модель с учётом контекста (устройство, время, история)
Метрики: precision@K, recall@K, nDCG, Coverage (разнообразие), + A/B по конверсии
Инфраструктура: feature store, serving layer с кэшем, monitoring дрейфа.
ППридумано ИИ
SQLЛегкийвопрос
Data Warehouse vs. Data Lake
В чём разница между Data Warehouse и Data Lake? Когда что использовать?
Data Warehouse (DWH):
Структурированные данные, схема задаётся при загрузке (schema-on-write)
Оптимизирован для аналитических SQL-запросов
Высокое качество данных, медленная загрузка сырых данных
Примеры: Snowflake, BigQuery, Redshift
Data Lake:
Любые данные (структурированные, полуструктурированные, бинарные)
Схема задаётся при чтении (schema-on-read)
Дёшев для хранения, но требует обработки при использовании
Примеры: S3 + Spark, Azure Data Lake
Data Lakehouse (современный тренд): Delta Lake, Iceberg — объединяет плюсы обоих.
Когда что:
DWH → бизнес-отчётность, BI, регулярные запросы
Data Lake → ML-эксперименты, сырые логи, большие объёмы неструктурированных данных
ППридумано ИИ
SQLЛегкийвопрос
ETL vs. ELT: в чём разница
Объясни разницу между ETL и ELT-подходами. Когда применяется каждый?
ETL (Extract → Transform → Load):
Данные трансформируются до загрузки в хранилище
Логика преобразования — в пайплайне (Python, Spark)
Применяется при ограниченных ресурсах хранилища или строгих требованиях к качеству
Традиционный подход для DWH
ELT (Extract → Load → Transform):
Сырые данные грузятся как есть, трансформация — внутри хранилища (SQL)
Применяется в облачных DWH (BigQuery, Snowflake) с дешёвыми ресурсами
Инструменты: dbt, Dataform
Преимущества ELT:
Вся логика в SQL — понятно аналитикам
Исходные данные сохраняются (можно пересчитать)
Быстрее загрузка (нет предобработки)
Практика: современный стек → ELT с dbt поверх BigQuery/Snowflake.
ППридумано ИИ
SQLЛегкийвопрос
Нормализация баз данных
Что такое нормализация базы данных? Объясни 1NF, 2NF, 3NF на простых примерах.
Нормализация — процесс структурирования БД для минимизации избыточности и аномалий.
1NF (Первая нормальная форма):
Все значения атомарны (нет списков в ячейке)
Есть первичный ключ
Нарушение: {"телефоны": "79001, 79002"} в одной ячейке
2NF (Вторая нормальная форма):
1NF + каждый не-ключевой атрибут зависит от всего ключа (не от его части)
Актуально при составных ключах
Нарушение: (order_id, product_id) → product_name — product_name зависит только от product_id, выносим в отдельную таблицу
3NF (Третья нормальная форма):
2NF + нет транзитивных зависимостей (A → B → C, где A — ключ)
Нарушение: employee_id → department_id → department_name. Выносим отдел в отдельную таблицу.
Практика: OLTP-системы нормализуют (меньше аномалий при записи). DWH денормализуют ради скорости чтения.
ППридумано ИИ
СтатистикаСреднийвопрос
Precision и Recall
Объясни precision и recall. Когда важнее одно, а когда другое? Приведи примеры из data-аналитики.
Precision = TP / (TP + FP)
Из всего, что модель назвала положительным, какая доля действительно положительная?
→ «Насколько точны предсказания?»
Recall = TP / (TP + FN)
Из всего, что действительно положительное, какую долю модель нашла?
→ «Насколько полно находим?»
Спам-фильтр: лучше пропустить спам, чем потерять важное письмо
Рекомендации: плохая рекомендация раздражает
Когда важнее Recall:
Детектор рака: лучше ложная тревога, чем пропущенная болезнь
Fraud detection: лучше заблокировать честного, чем пропустить мошенника
Предсказание оттока: лучше предложить скидку лишнему пользователю
Баланс: F1 = 2 × (P × R) / (P + R)
ППридумано ИИ
PythonСреднийвопрос
Обработка пропущенных значений
Какие есть подходы к обработке пропущенных значений? Как выбрать правильный?
Типы пропусков:
MCAR (Missing Completely At Random): пропуск случаен — можно удалять строки
MAR (Missing At Random): пропуск зависит от других переменных — нужна импутация
MNAR (Missing Not At Random): пропуск зависит от самого значения — сложнее всего
Подходы:
Удаление строк/столбцов — только при MCAR и малом % пропусков (< 5%)
Заполнение константой — медиана/среднее для числовых, мода для категориальных. Быстро, не учитывает контекст.
Заполнение по группе — медиана по сегменту (age группа, регион). Лучше, чем глобальная медиана.
KNN Imputation — находит похожие записи и берёт их значение
Model-based (MICE) — итерационная модельная импутация, лучший результат при MAR
Добавить флаг — бинарная переменная «был пропуск» — иногда само по себе ценный признак (MNAR)
Правило: сначала разобраться в причине пропуска, потом выбирать метод.
ППридумано ИИ
КейсыСреднийвопрос
Метрики для оценки рекомендательной системы
Какие метрики используют для оценки качества рекомендательных систем? Объясни разницу между offline и online оценкой.
Offline метрики (на исторических данных):
Precision@K — доля релевантных среди первых K рекомендаций
Recall@K — доля всех релевантных элементов, попавших в топ-K
nDCG@K — учитывает позицию: релевантное выше → выше оценка
MAP (Mean Average Precision) — среднее AP по всем запросам
Coverage — какую долю каталога модель вообще рекомендует
Diversity/Serendipity — разнообразие и неожиданность рекомендаций
Online метрики (A/B тест):
CTR по рекомендациям
Конверсия: клик → покупка
Revenue через рекомендательный блок
Session depth (сколько страниц посетил после рекомендации)
Почему нельзя ограничиться offline:
Offline метрики не учитывают ответ пользователя в реальном контексте. Улучшение nDCG не всегда коррелирует с ростом CTR или выручки.
ППридумано ИИ
КейсыСреднийвопрос
Как строить дашборд для стейкхолдеров
Продакт просит тебя сделать дашборд для еженедельного совещания. Как подойдёшь к его построению?
Принципы хорошего дашборда:
1. Прояснить аудиторию и цель:
Кто будет смотреть: CEO, продакт, маркетинг?
Какие решения на основе дашборда? (инвестировать в канал, остановить фичу)
2. Выбрать 3–7 ключевых метрик:
North Star + 2–3 leading indicators + guardrails
Меньше метрик → быстрее понимание
3. Структура дашборда:
Верх: итоговые метрики (KPI за период)
Середина: тренды (линейные графики с периодом сравнения)
Низ: breakdown (по сегментам, каналам, платформам)
Accuracy = 97% ничего не говорит. Модель может просто предсказывать «норма» для всех — получит 97% accuracy, не обнаружив ни одного мошенника.
Правильные метрики для несбалансированных задач:
1. Precision и Recall:
Recall (Sensitivity) для класса мошенников: доля реальных мошенников, пойманных моделью
Precision: из тех, кого назвали мошенниками, сколько действительно ими были
2. F1-score (гармоническое среднее P и R)
3. ROC-AUC:
Площадь под ROC-кривой. Не зависит от порога, хорошо при несбалансированных классах. Идеал = 1, random = 0.5.
4. PR-AUC (Precision-Recall AUC):
Лучше, чем ROC-AUC, когда один класс очень мал. ROC может вводить в заблуждение при большом дисбалансе.
5. Cohen's Kappa / MCC:
Согласие с учётом случайного угадывания.
Дополнительно:
Техники: oversampling (SMOTE), undersampling, class_weight в sklearn
Выбор порога классификации исходя из бизнес-стоимости ошибок
ППридумано ИИ
ПоведенческиеЛегкийвопрос
Расскажи о себе
Расскажи о себе. (Классический открывающий вопрос HR-скрининга)
Структура ответа (1–2 минуты):
Текущая роль: «Сейчас я [должность] в [компания], где занимаюсь [основные задачи]»
Путь сюда: «До этого я [предыдущий опыт], что позволило мне [навык/результат]»
Специализация: «Особенно мне интересны [area] — работал с [инструменты/технологии]»
Зачем здесь: «Я смотрю на [эта компания], потому что [конкретная причина связанная с компанией]»
Советы:
Не пересказывай резюме дословно — дай контекст и цепочку
Говори о результатах, а не только об обязанностях
Заканчивай «переходом» на эту позицию — зачем ты здесь
Длина: 90–120 секунд
Чего не делать: не уходить в детали проектов (для этого будут другие вопросы), не рассказывать личную жизнь.
ППридумано ИИ
ПоведенческиеЛегкийвопрос
Почему аналитика данных
Почему ты выбрал профессию аналитика данных? Что тебя в ней привлекает?
Что ищет интервьюер: осознанность выбора, мотивацию, долгосрочный интерес.
Структура хорошего ответа:
Откуда пришёл интерес: конкретный момент или опыт (учёба, проект, задача)
Что нравится в работе: анализ данных → решения → влияние на продукт/бизнес
Что продолжает мотивировать: постоянно новые задачи, стык бизнеса и технологий
Пример: «Во время учёбы я заметил, что команды принимают решения на основе интуиции. Хотелось работать там, где решения опираются на данные. Мне нравится переводить вопрос бизнеса в задачу, а данные — в рекомендацию. Особенно интересно, когда анализ меняет направление продукта».
Что ищет интервьюер: амбиции, осознанность карьерного пути, соответствие возможностям компании.
Структура ответа:
Честная карьерная цель (рост в экспертизе, переход в lead/head of analytics, или в продукт)
Связь с этой ролью и компанией — «именно здесь это возможно, потому что…»
Гибкость: «это моё направление, но я готов его уточнять по мере роста»
Примеры целей аналитика:
Стать Senior/Lead аналитиком с экспертизой в growth analytics
Перейти в Product Analytics / DS
Построить аналитическую команду или функцию
Советы:
Не говори «хочу работать в вашей компании» — это не ответ на вопрос
Не говори «пока не знаю» — это тревожный сигнал
Не говори «хочу вашу должность» (если интервьюер — твой будущий менеджер)
Будь конкретен, но не жёстко запрограммирован
ППридумано ИИ
ПоведенческиеСреднийвопрос
Как работаешь с неопределёнными задачами
Расскажи, как ты работаешь, когда задача сформулирована нечётко или данных недостаточно?
Что ищет интервьюер: самостоятельность, структурность мышления, умение работать в условиях неопределённости.
Структура ответа (метод STAR):
Ситуация: задача пришла без чётких метрик и требований
Задача: понять, что реально нужно, и предложить подход
Действие: провёл Discovery — поговорил с продактом, нарисовал гипотезы, предложил MVP-анализ
Результат: согласовали метрику, анализ помог принять решение
Универсальный фреймворк:
Задать уточняющие вопросы: «Какое решение должен поддержать этот анализ?»
Зафиксировать допущения письменно
Предложить MVA (Minimum Viable Analysis) — быстрый first cut
Согласовать, нужно ли углубляться
Важно: не блокируйся на «нет данных». Скажи что знаешь, что неизвестно, и как принять решение при этой неопределённости.
ППридумано ИИ
ПоведенческиеСреднийвопрос
Конфликт с коллегой
Расскажи о случае, когда у тебя возник конфликт с коллегой или членом команды. Как ты его разрешил?
Что ищет интервьюер: зрелость, умение слушать, способность решать конфликты конструктивно.
Структура STAR:
Ситуация: разошлись с разработчиком в оценке приоритетности трекинга
Задача: нужно было запустить аналитику к релизу
Действие: предложил отдельную встречу 1:1 (не в общем чате), объяснил бизнес-контекст, услышал его ограничения, предложили компромисс
Результат: запустили минимальный трекинг к дедлайну, полный — следующим спринтом
Принципы хорошего ответа:
Не говори «конфликтов у меня не бывает» — неправдиво
Покажи свою роль в решении, не только чужую ошибку
Не вини коллегу — фокус на процессе
Демонстрируй эмпатию: «я понял, что у него были другие приоритеты»
ППридумано ИИ
ПоведенческиеСреднийвопрос
Задача, где данные не дали ответа
Приведи пример задачи, где данных было недостаточно, чтобы дать однозначный ответ. Что ты сделал?
Что ищет интервьюер: честность, зрелость, умение работать с неопределённостью, коммуникация с бизнесом.
Структура STAR:
Ситуация: попросили оценить влияние промо-акции на LTV. Данные были только за 2 недели, слишком мало для LTV-сигнала.
Задача: дать оценку к встрече с маркетингом.
Действие:
Честно обозначил ограничение: «LTV за 2 недели не измерить»
Предложил прокси: удержание за 7 дней и средний чек первой покупки — ранние индикаторы LTV
Показал scenario-анализ: «при росте retention на 5% долгосрочный эффект составит X, при падении — Y»
Результат: команда приняла решение с ясным пониманием неопределённости
Ключевой вывод для ответа: «Я понял, что моя задача — помочь принять решение при имеющихся данных, а не найти идеальный ответ».
ППридумано ИИ
ПоведенческиеСреднийвопрос
Самый сложный аналитический проект
Расскажи о самом сложном проекте в твоей карьере. Что делало его сложным и как ты с этим справился?
Что ищет интервьюер: глубину опыта, подход к решению проблем, рефлексию.
Структура STAR:
Ситуация: Проект по атрибуции маркетинговых каналов. Данные из 5 источников с разным форматом, без единого user_id.
Задача: дать ответ на вопрос «какой канал приносит больше ценных пользователей».
Действие:
Провёл аудит данных — нашёл расхождения между источниками
Договорился с командой на единое определение «привлечение» и «ценный пользователь»
Построил identity resolution по email+device fingerprint
Использовал Shapley-атрибуцию вместо last-click
Результат: команда перераспределила бюджет, ROAS улучшился на 15%
Советы:
Будь конкретен: назови инструменты, метрики
Покажи, что именно ты делал — не «мы решили»
Упомяни что нового узнал из этого проекта
ППридумано ИИ
ПоведенческиеСреднийвопрос
Расстановка приоритетов
Как ты расставляешь приоритеты, когда у тебя несколько задач с одинаково высоким приоритетом?
Что ищет интервьюер: самостоятельность, системность, умение коммуницировать о нагрузке.
Фреймворк ответа:
Прояснить приоритеты: «Когда всё горит — это сигнал к диалогу, а не к параллельной работе над всем сразу»
Оценить по критериям:
Срок: когда нужен результат?
Стейкхолдер: кто просит и насколько критично для бизнеса?
Сложность: что можно быстро сделать (quick win)?
Прозрачно коммуницировать: «Я могу сделать A к пятнице и B к следующей неделе — или другой порядок, если B важнее?»
Зафиксировать договорённости письменно
Пример: «Однажды от продакта, маркетинга и CEO пришли три "срочных" запроса одновременно. Я написал всем троим, что могу взять первым — и попросил каждого оценить срок. Договорились на порядок, который устроил всех».
Чего не делать: тихо тонуть в задачах или рандомно делать «самое первое».
ППридумано ИИ
ПоведенческиеСложныйвопрос
Убеждение команды через данные
Опиши момент, когда тебе пришлось убеждать команду или менеджера принять решение на основе данных, несмотря на сопротивление.
Что ищет интервьюер: влияние, коммуникация, умение работать с resistance.
Структура STAR:
Ситуация: продакт хотел запустить фичу без A/B теста — «и так понятно, что улучшит». По историческим данным у меня были основания сомневаться.
Задача: убедить провести тест перед роллаутом.
Действие:
Показал исторические случаи «очевидных улучшений», которые не подтвердились (внутренние данные)
Предложил быстрый тест (2 недели, 10% аудитории) с минимальными затратами
Объяснил риск: «если запустим без теста и окажется хуже — откатывать труднее, чем не запускать»
Согласовал конкретный KPI для принятия решения
Результат: тест запустили. Метрика оказалась нейтральной. Команда стала скептичнее к «очевидным» идеям.
Ключевой тезис: «Я не отстаивал своё мнение — я снижал риск для команды».
ППридумано ИИ
ПоведенческиеСложныйвопрос
Провальный проект: чему научил
Расскажи о проекте, который пошёл не по плану или провалился. Что ты из него вынес?
Что ищет интервьюер: честность, рефлексию, рост из ошибок.
Типичные «провалы» в аналитике:
Анализ привёл к неверному выводу из-за ошибки в данных
Дашборд не использовался, потому что не решал реальную задачу
A/B тест запустили неправильно, результаты невалидны
Структура STAR:
Ситуация: построил прогнозную модель оттока. На тесте — хорошие метрики. В проде — бесполезна.
Задача: понять почему и что делать дальше.
Действие: провёл post-mortem. Оказалось — обучающая выборка была несвежей (data leakage на уровне фичей). Не проверил distribution drift перед деплоем.
Результат: переобучил с правильной временной валидацией. Добавил мониторинг дрейфа. Написал checklist для будущих моделей.
Советы:
Не прячь провал за «обстоятельствами» — возьми личную ответственность за свою часть