paint-brush
Wykorzystanie metody stratyfikacji do analizy eksperymentuprzez@nataliaogneva
33,172 odczyty
33,172 odczyty

Wykorzystanie metody stratyfikacji do analizy eksperymentu

przez Natalia Ogneva8m2024/04/19
Read on Terminal Reader
Read this story w/o Javascript

Za długo; Czytać

Próbkowanie warstwowe to potężna technika zwiększająca wydajność eksperymentów i wrażliwość metryczną w analizie danych. Grupując odbiorców i dzieląc ich według określonych wag, możesz optymalizować eksperymenty, zmniejszać wariancję i zwiększać niezawodność wyników.

Company Mentioned

Mention Thumbnail
featured image - Wykorzystanie metody stratyfikacji do analizy eksperymentu
Natalia Ogneva HackerNoon profile picture
0-item


Każdy eksperyment wiąże się z kompromisem między szybkimi wynikami a wrażliwością metryki. Jeśli wybrana metryka jest szeroka pod względem wariancji, musimy długo czekać, aby upewnić się, że wyniki eksperymentu są dokładne. Rozważmy jedną metodę, która pomoże analitykom zwiększyć ich eksperymenty bez tracenia zbyt wiele czasu lub wrażliwości metryki.


Formułowanie problemu

Załóżmy, że przeprowadzamy standardowy eksperyment, aby przetestować nowy algorytm rankingowy, w którym długość sesji jest głównym wskaźnikiem. Ponadto weź pod uwagę, że naszą publiczność można podzielić na trzy grupy: 1 milion nastolatków, 2 miliony użytkowników w wieku 18-45 lat i 3 miliony użytkowników w wieku 45 lat i więcej. Reakcja na nowy algorytm rankingowy będzie się znacznie różnić w tych grupach odbiorców. Ta duża zmienność zmniejsza wrażliwość wskaźnika.


Innymi słowy, populację można podzielić na trzy warstwy, opisane poniżej:


Załóżmy, że każdy składnik ma rozkład normalny. Wtedy główna metryka populacji również ma rozkład normalny.

Metoda stratyfikacji

Losowo dzielimy wszystkich użytkowników z populacji w klasycznym projekcie eksperymentu, nie biorąc pod uwagę różnic między naszymi użytkownikami. Dlatego rozważamy próbkę z następującą wartością oczekiwaną i wariancją.


Innym sposobem jest losowy podział wewnątrz każdej warstwy według jej wagi w populacji ogólnej.

W tym przypadku wartość oczekiwana i wariancja są następujące.


Wartość oczekiwana jest taka sama jak w pierwszym wyborze. Jednak wariancja jest mniejsza, co gwarantuje wyższą czułość metryki.

Teraz rozważmy metodę Neymana . Sugerują oni losowe dzielenie użytkowników w każdej strategii z określonymi wagami.

Tak więc w tym przypadku wartość oczekiwana i wariancja są równe poniższemu.

Wartość oczekiwana jest równa wartości oczekiwanej w pierwszym przypadku asymptotycznie. Jednak wariancja jest znacznie mniejsza.

Testowanie empiryczne

Teoretycznie udowodniliśmy skuteczność tej metody. Symulujmy próbki i przetestujmy metodę stratyfikacji empirycznie.

Rozważmy trzy przypadki:

  • wszystkie strategie z równymi średnimi i wariancjami,
  • wszystkie strategie z różnymi średnimi i równymi wariancjami,
  • wszystkie strategie o równych średnich i różnych wariancjach.

Zastosujemy wszystkie trzy metody we wszystkich przypadkach i stworzymy histogram oraz wykres pudełkowy w celu ich porównania.

Przygotowanie kodu

Najpierw utwórzmy klasę w Pythonie, która symuluje naszą ogólną populację składającą się z trzech strategii.

 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]


Następnie dodajmy funkcje dla trzech metod próbkowania opisanych w części teoretycznej.

 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


Ponadto w części empirycznej zawsze potrzebujemy funkcji symulującej proces eksperymentu.

 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


Wyniki symulacji

Jeśli przyjrzymy się populacji ogólnej, gdzie wszystkie nasze strategie mają te same wartości i wariancje, można się spodziewać, że wyniki wszystkich trzech metod będą mniej więcej równe.

Różne średnie i równe wariancje dały bardziej ekscytujące wyniki. Użycie stratyfikacji drastycznie zmniejsza wariancję.

W przypadkach równych średnich i różnych wariancji obserwujemy redukcję wariancji w metodzie Neymana.

Wniosek

Teraz możesz zastosować metodę stratyfikacji, aby zmniejszyć wariancję metryczną i udoskonalić eksperyment, grupując odbiorców i technicznie dzieląc ich losowo w obrębie każdego klastra z określonymi wagami!