Я реорганизовал ваше решение с помощью мультипроцессинга. Если у вас много метрик и измерений, то оно должно хорошо масштабироваться. run_test_details
можно оптимизировать с помощью некоторого кэширования, но я не знаю, насколько велики ваши данные, поэтому это может быть проблематично. Также, если бы это было стандартным статистическим процессом, я бы проверил R
.
Пожалуйста, дайте мне знать, если это улучшит ваше время выполнения.
import pandas as pd
import numpy as np
from scipy import stats
import multiprocessing as mp
data_metric1 = list(np.random.rand(100)) + list(np.random.rand(100) + np.random.randint(-1, 1, 100) * 0.1)
data_metric2 = list(np.random.rand(100)) + list(np.random.rand(100) + np.random.randint(-1, 1, 100) * 0.1)
test_label = list(np.random.choice(['test', 'control'], 100))
dimensions = list(np.random.choice(['a', 'b'], 100))
df = pd.DataFrame(list(zip(test_label, dimensions, data_metric1, data_metric2)), columns=['tc', 'dim', 'metric1', 'metric2'])
##############
def run_test_detail(df, dim, col):
control_data = df[df.tc == 'control'][col]
test_data = df[df.tc == 'test'][col]
mean_control = control_data.mean()
mean_test = test_data.mean()
control_count = control_data.size
test_count = test_data.size
lift = (mean_test - mean_control) / mean_control * 100
p_value_utest = stats.mannwhitneyu(control_data, test_data)[1]
r = [dim, col, control_count, test_count, mean_control, mean_test, lift, p_value_utest]
return r
##############
pool = mp.Pool(processes=mp.cpu_count())
result1 = pool.starmap(run_test_detail, [(df, 'all', col)
for col in df.columns.difference(['tc', 'dim'])])
result2 = pool.starmap(run_test_detail, [(df[df['dim'] == dim], dim, col)
for col in df.columns.difference(['tc', 'dim'])
for dim in df['dim'].unique()])
##############
cols = ['dim', 'col', 'control_count', 'test_count', 'mean_control', 'mean_test', 'lift', 'p_value_utest']
out_df = pd.DataFrame(data=result1+result2, columns=cols)