makut

Untitled

Dec 2nd, 2021 (edited)
124
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. """Домашнее задание.
  2.  
  3. Нужно написать функцию для определения продолжительности эксперимента.
  4.  
  5. В качестве метрики в эксперименте используется не среднее, а 90% квантиль.
  6. Нулевая гипотеза - 90% квантили равны, альтернативная гипотеза - 90% квантили не равны.
  7. Эксперимент будет оцениваться с помощью 1000 итераций бутстрепа и центрального доверительного интервала c уровнем
  8. значимости alpha=0.05.
  9. По историческим данным известно, что измеряемые значения распределены нормально с параметрами mu=100 и std=10.
  10. Для синтетических АБ экспериментов значения измерений в экспериментальной группе следует умножать на (1 + effect).
  11. Допустимая сумма вероятностей ошибок и ожидаемый размер эффекта передаются в функцию в качестве аргументов.
  12.  
  13. Эксперимент может проводиться целое число дней. За один день получаем по 10 измерений в каждой из групп.
  14. Нужно определить минимальное кол-во дней, которое позволит собрать необходимое кол-во данных, чтобы тест контролировал
  15. сумму ошибок I и II рода на заданном уровне.
  16. Если для проведения эксперимента с заданными параметрами требуется более 30 дней, то функция должна вернуть 30.
  17.  
  18. ПРИМЕР
  19. - Если для эксперимент нужно 33 наблюдения в каждой группе, то необходимо собрать данные за 4 дня. Ответ = 4.
  20. - Если для эксперимент нужно 9999 наблюдений в каждой группе, то необходимо более 30 дней. Ответ = 30.
  21.  
  22. ОЦЕНКА КАЧЕСТВА
  23. Будет произведено 3 запуска функции с некоторыми параметрами, по полученным результатам будет вычислено MAE.
  24. Оценка будет посчитана так:
  25. SCORE = np.clip(11 - int(MAE) - penalty, 0, 10)
  26. где penalty - штраф за медленную скорость вычисления. Ожидается, что три запуска функции отработают за 5 минут.
  27. Каждые 30 секунд сверх 5 минут приводят к штрафному баллу. За 05:29 - не штрафа, за 05:31 - 1 штрафной балл, и тд.
  28. Решение будет запускаться в Colab.
  29. """
  30.  
  31. import time
  32.  
  33. import numpy as np
  34. import tqdm.notebook
  35.  
  36.  
  37. def test_two(X, Y, alpha=0.05):
  38.     X_boot = X[np.random.randint(0, X.shape[0], size=(X.shape[0], 1000, X.shape[1])), np.arange(X.shape[1])]
  39.     X_boot_q = np.quantile(X_boot, 0.9, axis=0)
  40.     Y_boot = Y[np.random.randint(0, Y.shape[0], size=(Y.shape[0], 1000, Y.shape[1])), np.arange(Y.shape[1])]
  41.     Y_boot_q = np.quantile(Y_boot, 0.9, axis=0)
  42.  
  43.     boot_metrics = X_boot_q - Y_boot_q
  44.     pe_metric = np.quantile(X, 0.9, axis=0) - np.quantile(Y, 0.9, axis=0)
  45.     left = 2 * pe_metric - np.quantile(boot_metrics, 1 - alpha / 2, axis=0)
  46.     right = 2 * pe_metric - np.quantile(boot_metrics, alpha / 2, axis=0)
  47.  
  48.     return ((left <= 0) & (right >= 0)).mean()  # Доля не отвержений нулевой гипотезы
  49.  
  50.  
  51. def get_experiment_duration(error: float, effect: float) -> int:
  52.     """Возвращает продолжительность эксперимента в днях.
  53.  
  54.    error - допустимая сумма ошибок I и II рода, возможны значения из отрезка [0.05, 0.5].
  55.    effect - размер эффекта в процентах, возможны любые значения строго больше 0.
  56.        Пример, effect=0.1 означает, что ожидается увеличение метрики на 10%.
  57.    """
  58.     for days in tqdm.notebook.tqdm(range(1, 31, 2)):
  59.         X, Y1, Y2 = np.random.normal(100, 10, size=(3, 10 * days, 1000))
  60.         Y2 = Y2 * (1 + effect)
  61.        
  62.         alpha = 1 - test_two(X, Y1)  # Ошибки первого рода
  63.         beta = test_two(X, Y2)  # Ошибки второго рода
  64.         print(alpha, beta)
  65.  
  66.         if alpha + beta < error:
  67.             return days
  68.     return 30
  69.  
  70.  
  71. if __name__ == "__main__":
  72.     errors = []
  73.  
  74.     # при проверке тут будут другие значения
  75.     experiments = [
  76.         {
  77.             'params': {'error': 0.4, 'effect': 10},
  78.             'true_answer': 1    
  79.         },
  80.         {
  81.             'params': {'error': 0.05, 'effect': 100.0},
  82.             'true_answer': 30  
  83.         },
  84.         # {
  85.         #     'params': {'error': 0.05, 'effect': 0.00000001},
  86.         #     'true_answer': 30  
  87.         # },
  88.     ]
  89.  
  90.     t1 = time.time()
  91.     for experiment in experiments:
  92.         answer = get_experiment_duration(**experiment['params'])
  93.         errors.append(answer - experiment['true_answer'])
  94.     t2 = time.time()
  95.  
  96.     penalty = int(max(0, (t2 - t1 - 5 * 60) / 30))
  97.     MAE = np.mean(np.abs(errors))
  98.     SCORE = np.clip(11 - int(MAE) - penalty, 0, 10)
  99.  
  100.     print(f'time = {t2 - t1}')
  101.     print(f'penalty = {penalty}')
  102.     print(f'errors = {errors}')
  103.     print(f'MAE = {MAE}')
  104.     print(f'SCORE = {SCORE}')
RAW Paste Data