![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Ogni esperimento comporta un compromesso tra risultati rapidi e sensibilità metrica. Se la metrica scelta è ampia in termini di varianza, dobbiamo attendere molto tempo per garantire che i risultati dell'esperimento siano accurati. Consideriamo un metodo per aiutare gli analisti a potenziare i loro esperimenti senza perdere troppo tempo o sensibilità metrica.
Supponiamo di condurre un esperimento standard per testare un nuovo algoritmo di ranking, con la durata della sessione come metrica primaria. Inoltre, considera che il nostro pubblico può essere approssimativamente categorizzato in tre gruppi: 1 milione di adolescenti, 2 milioni di utenti di età compresa tra 18 e 45 anni e 3 milioni di utenti di età pari o superiore a 45 anni. La risposta a un nuovo algoritmo di ranking varierebbe in modo significativo tra questi gruppi di pubblico. Questa ampia variazione riduce la sensibilità della metrica.
In altre parole, la popolazione può essere divisa in tre strati, descritti di seguito:
Diciamo che ogni componente ha una distribuzione normale. Quindi, anche la metrica principale per la popolazione ha una distribuzione normale.
Dividiamo casualmente tutti gli utenti dalla popolazione in un disegno sperimentale classico senza considerare le differenze tra i nostri utenti. Quindi, consideriamo il campione con il seguente valore atteso e varianza.
Un altro modo è quello di dividere casualmente all'interno di ogni strato in base al peso dello strato nella popolazione generale.
In questo caso, il valore atteso e la varianza sono i seguenti.
Il valore atteso è lo stesso della prima selezione. Tuttavia, la varianza è minore, il che garantisce una maggiore sensibilità metrica.
Ora, consideriamo il metodo di Neyman . Suggeriscono di dividere gli utenti in modo casuale all'interno di ogni strategia con pesi specifici.
Pertanto, in questo caso, il valore atteso e la varianza sono uguali a quanto segue.
Il valore atteso è uguale al valore atteso nel primo caso asintoticamente. Tuttavia, la varianza è molto minore.
Abbiamo dimostrato l'efficienza di questo metodo teoricamente. Simuliamo campioni e testiamo empiricamente il metodo di stratificazione.
Consideriamo tre casi:
Applicheremo tutti e tre i metodi in tutti i casi e tracceremo un istogramma e un boxplot per confrontarli.
Per prima cosa, creiamo una classe in Python che simuli la nostra popolazione generale composta da tre strategie.
class GeneralPopulation: def __init__(self, means: [float], stds: [float], sizes: [int], random_state: int = 15 ): """ Initializes our General Population and saves the given distributions :param means: List of expectations for normal distributions :param stds: List of standard deviations for normal distributions :param sizes: How many objects will be in each strata :param random_state: Parameter fixing randomness. Needed so that when conducting experiment repeatedly with the same input parameters, the results remained the same """ self.strats = [st.norm(mean, std) for mean, std in zip(means, stds)] self._sample(sizes) self.random_state = random_state def _sample(self, sizes): """Creates a general population sample as a mixture of strata :param sizes: List with sample sizes of the corresponding normal distributions """ self.strats_samples = [rv.rvs(size) for rv, size in zip(self.strats, sizes)] self.general_samples = np.hstack(self.strats_samples) self.N = self.general_samples.shape[0] # number of strata self.count_strats = len(sizes) # ratios for every strata in GP self.ws = [size/self.N for size in sizes] # ME and Std for GP self.m = np.mean(self.general_samples) self.sigma = np.std(self.general_samples) # ME and std for all strata self.ms = [np.mean(strat_sample) for strat_sample in self.strats_samples] self.sigmas = [np.std(strat_sample) for strat_sample in self.strats_samples]
Aggiungiamo quindi le funzioni per i tre metodi di campionamento descritti nella parte teorica.
def random_subsampling(self, size): """Creates a random subset of the entire population :param sizes: subsample size """ rc = np.random.choice(self.general_samples, size=size) return rc def proportional_subsampling(self, size): """Creates a subsample with the number of elements, proportional shares of strata :param sizes: subsample size """ self.strats_size_proport = [int(np.floor(size*w)) for w in self.ws] rc = [] for k in range(len(self.strats_size_proport)): rc.append(np.random.choice(self.strats_samples[k], size=self.strats_size_proport[k])) return rc def optimal_subsampling(self, size): """Creates a subsample with the optimal number of elements relative to strata :param sizes: subsample size """ sum_denom = 0 for k in range(self.count_strats): sum_denom += self.ws[k] * self.sigmas[k] self.strats_size_optimal = [int(np.floor((size*w*sigma)/sum_denom)) for w, sigma in zip(self.ws, self.sigmas)] if 0 in self.strats_size_optimal: raise ValueError('Strats size is 0, please change variance of smallest strat!') rc = [] for k in range(len(self.strats_size_optimal)): rc.append(np.random.choice(self.strats_samples[k], size=self.strats_size_optimal[k])) return rc
Inoltre, per la parte empirica, abbiamo sempre bisogno di una funzione per simulare il processo sperimentale.
def run_experiments(self, n_sub, subsampling_method, n_experiments=1000): """Conducts a series of experiments and saves the results :param n_sub: size of sample :param subsampling_method: method for creating a subsample :param n_experiments: number of experiment starts """ means_s = [] if(len(self.general_samples)<100): n_sub = 20 if(subsampling_method == 'random_subsampling'): for n in range(n_experiments): rc = self.random_subsampling(n_sub) mean = rc.sum()/len(rc) means_s.append(mean) else: for n in range(n_experiments): if(subsampling_method == 'proportional_subsampling'): rc = self.proportional_subsampling(n_sub) elif(subsampling_method == 'optimal_subsampling'): rc = self.optimal_subsampling(n_sub) strats_mean = [] for k in range(len(rc)): strats_mean.append(sum(rc[k])/len(rc[k])) # Mean for a mixture means_s.append(sum([w_k*mean_k for w_k, mean_k in zip(self.ws, strats_mean)])) return means_s
Se consideriamo la popolazione generale, in cui tutte le nostre strategie hanno gli stessi valori e le stesse varianze, ci si aspetta che i risultati di tutti e tre i metodi siano più o meno uguali.
Medie diverse e varianze uguali hanno ottenuto risultati più entusiasmanti. L'uso della stratificazione riduce drasticamente la varianza.
Nei casi con medie uguali e varianze diverse, osserviamo una riduzione della varianza nel metodo di Neyman.
Ora puoi applicare il metodo di stratificazione per ridurre la varianza metrica e potenziare l'esperimento se raggruppi il tuo pubblico e lo dividi tecnicamente in modo casuale all'interno di ciascun cluster con pesi specifici!