![Search icon](https://hackernoon.imgix.net/search-new.png?w=19&h=19)
Elk experiment omvat een afweging tussen snelle resultaten en metrische gevoeligheid. Als de gekozen metrische groot is in termen van variantie, moeten we lang wachten om ervoor te zorgen dat de resultaten van het experiment nauwkeurig zijn. Laten we eens kijken naar een methode om analisten te helpen hun experimenten te verbeteren zonder te veel tijd of metrische gevoeligheid te verliezen.
Stel dat we een standaardexperiment uitvoeren om een nieuw rangschikkingsalgoritme te testen, met sessielengte als primaire metriek. Bedenk daarnaast dat ons publiek grofweg in drie groepen kan worden ingedeeld: 1 miljoen tieners, 2 miljoen gebruikers van 18-45 jaar en 3 miljoen gebruikers van 45 jaar en ouder. De respons op een nieuw rangschikkingsalgoritme zou aanzienlijk verschillen tussen deze doelgroepen. Deze grote variatie vermindert de gevoeligheid van de metriek.
Met andere woorden, de bevolking kan worden verdeeld in drie lagen, die als volgt worden beschreven:
Laten we zeggen dat elk onderdeel een normale verdeling heeft. Dan heeft de belangrijkste metriek voor de populatie ook een normale verdeling.
We verdelen willekeurig alle gebruikers uit de populatie in een klassiek experimenteel ontwerp zonder rekening te houden met de verschillen tussen onze gebruikers. Daarom beschouwen we de steekproef met de volgende verwachte waarde en variantie.
Een andere manier is om binnen elke strat willekeurig te verdelen op basis van het gewicht van de strat in de algemene populatie.
In dit geval zijn de verwachte waarde en variantie als volgt.
De verwachte waarde is hetzelfde als in de eerste selectie. De variantie is echter minder, wat een hogere metrische gevoeligheid garandeert.
Laten we nu eens kijken naar Neyman's methode . Zij stellen voor om gebruikers willekeurig te verdelen binnen elke strat met specifieke gewichten.
In dit geval zijn de verwachte waarde en variantie dus gelijk aan het volgende.
De verwachte waarde is gelijk aan de verwachte waarde in het eerste geval asymptotisch. De variantie is echter veel minder.
We hebben de efficiëntie van deze methode theoretisch bewezen. Laten we samples simuleren en de stratificatiemethode empirisch testen.
Laten we drie gevallen bekijken:
We passen alle drie de methoden in alle gevallen toe en maken een histogram en boxplot om ze te vergelijken.
Laten we eerst een klasse in Python maken die onze algemene populatie simuleert, bestaande uit drie strategieën.
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]
Vervolgens voegen we functies toe voor de drie bemonsteringsmethoden die in het theoretische gedeelte zijn beschreven.
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
Ook voor het empirische deel hebben we altijd een functie nodig om het experimentele proces te simuleren.
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
Als we naar de algemene populatie kijken, waarbij al onze strategieën dezelfde waarden en varianties hebben, dan verwachten we dat de resultaten van alle drie de methoden min of meer gelijk zijn.
Verschillende middelen en gelijke varianties leverden spannendere resultaten op. Stratificatie gebruiken vermindert variantie drastisch.
In gevallen met gelijke middelen en verschillende variantie zien we een variantiereductie in de methode van Neyman.
Nu kunt u de stratificatiemethode toepassen om de metrische variantie te verminderen en het experiment te verbeteren door uw publiek te clusteren en ze technisch gezien willekeurig binnen elke cluster te verdelen met specifieke gewichten!