Search
Write a publication
Pull to refresh
10
0
Павел Мосин @Atlamos

Старший аналитик данных

Send message

Посмотрел. Пуассоновский бутсрап не решает проблему вычислительных мощностей для повторного отбора (по крайней мере на одной машине), в статье такого тезиса просто нет. Там с помощью пуассоновского бутстрапа решается проблема как сгенерировать бутстрапированные выборки, не вынимая всю выборку при параллельных вычислениях, когда размер выборки n заранее не известен, а данные хранятся распределено.

Проверил разные реализации на одной машина на Python по самым затратным операциям — генерациям подвыборок. Пуассоновский бутстрап по времени оказывался не быстрее отбора с повторением, а иногда и медленнее.

import numpy as np
import pandas as pd

# df = pd.read_csv('file_name.csv')

data = df.n_bnr_clkd.values
n_trial = 5_000
print(n_trial, len(data))  # 5000, 449417


# Итерации отбора с повторением
%%time
for _ in range(n_trial):  
  _ = np.random.choice(data, size=len(data))
 # Wall time: 11.8 s


# Итерации Пуассона
%%time
for _ in range(n_trial):  
  _ = np.random.poisson (1, size=len(data))
 # Wall time: 58.7 s


# Генерация матрицы отбора с повторением
%%time
_ = np.random.choice(data, size=(n_trial, len(data)))
#  Wall time: 59.7 s


# Генерация матрицы Пуассона
%%time
_ = np.random.poisson(1, size=(n_trial, len(data)))
# Wall time: 1min 8s


О, хороший пример, на самом деле имхо тут вопрос интерпретации метрики и всех преобразований которые применяешь к юзерам.
Условно ты можешь попробовать посчитать adv_revenue per adv_gmv (т.е. только по тому gmv >0 и где была рек выручка) и ответить на вопрос, а стала ли реклама "отъедать" больше gmv где она была. Но думая в таком ключе можно продолжить и сказать что и твоя метрика adv_revenue per gmv интерпритируется также, что реклама могла "съесть" весть gmv, т.е. он будет 0.

Это по сути та же ratio-метрика, где ты имеешь у отдельного юзера adv_revenue и gmv . При линеаризации будет два случая когда gmv == 0 и gmv > 0 , тогда для юзера будет соответственно:
1) adv_revenue - CONTROL_RATIO * 0 = adv_revenue
2) adv_revenue - CONTROL_RATIO * gmv = lin_value
И всегда adv_revenue будет больше чем lin_value , т.е. у одного юзера вклад в метрику как бы только за счет рекламной выручки (съеден весь gmv), а у другого получился какой-то вклад в метрику меньше чем его рекламная выручка (он принес какой-то gmv). Так что я бы попробовал на самом деле и с нулями.
Только не стоит забывать, что обычно ratio-метрики еще парадоксу Симпсона подвержены, т.е. надо отдельно смотреть на суммарную рекламную выручку и суммарный gmv, чтобы понимать за счет чего произошло изменение, чтоб подстраховаться.

Знаю, на практике такой пример как у тебя считают бакетным методом на самом деле, но для него желательно иметь оооочень много наблюдений.
Да, когда нет уверенности, бутстрап всегда можно применять и для ratio-метрик в том числе.

Привет, да, в табличке я осознано на это пошел, чтобы указать на общую поюзерную структуру в экспе, где у нас единица рандомизации и единица анализа совпадают. Но когда у нас единица анализа non-user, например, чек, чтобы посчитать его среднее значение, то надо оставлять только тех юзеров, у которых сигналы знаменателя больше 0, так как если пользователь "не сделал" чек, то и не участвует в определении ratio-метрики. Соответственно линеаризация сигналов и статоценка линеаризованных сигналов происходит только по тем, где сигнал знаменателя больше 0.

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

В Python определение любой метрики в таком случае будет следующим:

# num and denom are numpy arrays with user signals
numerator = numerator[denominator>0]
denominator = denominator[denominator>0]

metric = numerator.sum() / denominator.sum()

Да, действительно все так, в бутстрапе заложена такая идея.
Помимо бутстрапа есть еще перестановочные тесты, там элементы не возвращаются в исходную выборку. В таких тестах мы две выборки объединяем в одну и потом опять делим рандомно на 2 и так много раз.
Можно сделать исчерпывающий перестановочный тест, т.е. перебрать все имеющиеся сочетания, но их будет очень мноооого, а можно приблизительный, ограничив константой, это будет уже больше похоже на монте-карло)

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

Information

Rating
Does not participate
Location
Россия
Registered
Activity

Specialization

Data Analyst, Product Analyst
Senior
Data Analysis
Math statistics
Python
SQL