Собесов

Retentioneering: момент времени, после которого человек спит с вероятностью 0.9

PythonКвантили и доверительные интервалыСредняяMiddle

Условие

В файле sleep.csv приведено время засыпания одного человека в разные дни. Нужно:

  1. Указать момент времени суток (с точностью до секунды), после которого с вероятностью 0.9 этот человек уже спит.
  2. Какова ошибка определения этого момента?
  3. Сколько дней наблюдения нужно добавить, чтобы уменьшить эту ошибку в 10 раз?

Решение

Подход

«Время, после которого с вероятностью 0.9 уже спит» = 0.9-квантиль распределения времени засыпания. Решение в три шага:

  1. Оценить квантиль по выборке.
  2. Оценить ошибку оценки квантиля — bootstrap-доверительный интервал или асимптотическая формула.
  3. Использовать связь «ошибка ∝ 1/√n» для оценки нужного числа наблюдений.

Реализация

import pandas as pd
import numpy as np
 
df = pd.read_csv("sleep.csv", parse_dates=["sleep_time"])
 
# приводим к "секундам с полуночи" для скалярного анализа
def time_to_seconds(ts):
    return ts.dt.hour * 3600 + ts.dt.minute * 60 + ts.dt.second
 
x = time_to_seconds(df["sleep_time"]).values
n = len(x)
 
# 1. Точечная оценка квантиля
q90 = np.quantile(x, 0.9)
print(f"q90 = {q90:.0f} sec ({q90/3600:.2f}h)")
 
# 2. Bootstrap-CI для квантиля
def bootstrap_quantile_ci(x, q=0.9, B=10000, alpha=0.05):
    n = len(x)
    boot = np.empty(B)
    for i in range(B):
        boot[i] = np.quantile(np.random.choice(x, n, replace=True), q)
    return np.percentile(boot, [100*alpha/2, 100*(1-alpha/2)])
 
lo, hi = bootstrap_quantile_ci(x, 0.9, B=10000)
half_width = (hi - lo) / 2
print(f"95% CI: [{lo:.0f}, {hi:.0f}], half-width = {half_width:.0f} sec")

Сколько дней нужно для уменьшения ошибки в 10 раз

Стандартная ошибка квантиля при асимптотике:

SE(q^p)1f(qp)p(1p)nSE(\hat q_p) \approx \frac{1}{f(q_p)} \sqrt{\frac{p(1-p)}{n}}

где f(q_p) — плотность распределения в точке квантиля. Главный множитель — 1/√n. Чтобы ошибка уменьшилась в 10 раз, нужно увеличить n в 100 раз:

# Текущая ошибка half_width при n наблюдений
# Цель: half_width / 10
# n_new = n * 100
n_new = n * 100
extra_days = n_new - n
print(f"Текущее n={n}, нужно n={n_new}, добавить {extra_days} дней")

Если в sleep.csv 30 дней наблюдения — потребуется 3000 дней (~8 лет). Это и есть ответ — обычно вызывает удивление, но 1/√n даёт именно такую асимптотику.

Альтернативная (более точная) формула

Если плотность f(q_p) оценить через KDE:

from scipy.stats import gaussian_kde
kde = gaussian_kde(x)
f_at_q = kde(q90)[0]
SE = np.sqrt(0.9 * 0.1 / n) / f_at_q
print(f"Asymptotic SE = {SE:.0f} sec")

И сравнить с bootstrap-эстимейтом — должны быть в одном порядке.

Анализ результата

  • Bootstrap менее чувствителен к форме распределения, чем асимптотика. На малом n (например, 30 дней) лучше bootstrap.
  • 0.9-квантиль — экстремальная точка; оценка хвоста требует больше наблюдений, чем медиана. Поэтому даже 100 дней может быть мало.
  • Если человек ложится «обычно в 23:00, иногда в 02:00» — выборка многомодальная, обычная экспонента/нормаль не подойдёт, а медиана и квантили распределены хорошо.

Подводные камни

  1. Время по кругу. Если человек ложится после полуночи (01:30), а другие дни — в 23:00, нельзя усреднять «секунды с полуночи». Сдвиньте «начало дня» на 18:00 или работайте с разностями относительно опорной точки.
  2. Малая выборка. На n=10 квантиль 0.9 — это фактически 9-я из 10 точек. CI огромный.
  3. Зависимость наблюдений. Дни недели коррелированы (выходные — позже). Bootstrap iid недостоверен; используйте block bootstrap.
  4. n×100 — формальная асимптотика. В реальности это нижняя граница; на конечном распределении может потребоваться ещё больше.
  5. Ошибка ≠ CI. «Ошибка» неоднозначна: standard error, half-width CI, RMSE? Уточняйте; в собеседовании предпочтительно — half-width CI.
  6. Точность до секунды. Современные часы измеряют поминутно; не имеет смысла указывать секунды, если в данных округление.

Эталонный ответ

  1. q90 = np.quantile(x, 0.9) — точечная оценка.
  2. Ошибка — half-width 95%-bootstrap-CI (~10000 ресемплов). Альтернативно — асимптотическая формула sqrt(0.9·0.1/n)/f(q90).
  3. Чтобы ошибка уменьшилась в 10 раз, нужно n в 100 раз больше — это следствие SE ∝ 1/√n. Если сейчас 30 дней — потребуется 3000.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти