|
1 | 1 | import jstat from 'jstat';
|
2 | 2 |
|
3 |
| -// SOLVING FOR POWER |
4 |
| -function solveforpower_Gtest ({total_sample_size, base_rate, effect_size, alpha, alternative, mu}) { |
5 |
| - var sample_size = total_sample_size/2; |
| 3 | +function get_alpha_sidaks_correction(alpha, variants) { |
| 4 | + if (variants == 1) { |
| 5 | + return alpha; |
| 6 | + } |
6 | 7 |
|
7 |
| - var mean_base = base_rate; |
8 |
| - var mean_var = base_rate * (1+effect_size); |
| 8 | + return 1 - (Math.pow(1-alpha, 1/variants)); |
| 9 | +} |
9 | 10 |
|
10 |
| - var mean_diff = mean_var - mean_base; |
11 |
| - var delta = mean_diff - mu |
| 11 | +// SOLVING FOR POWER |
| 12 | +function solveforpower_Gtest(data) { |
| 13 | + var { base_rate, effect_size } = data; |
| 14 | + var mean_var = base_rate*(1+effect_size); |
| 15 | + data.variance = base_rate*(1-base_rate) + mean_var*(1-mean_var); |
12 | 16 |
|
13 |
| - var variance = mean_base * (1-mean_base) + mean_var * (1-mean_var); |
14 |
| - var z = jstat.normal.inv(1-alpha/2, 0, 1); |
15 |
| - var mean = delta*Math.sqrt(sample_size/variance); |
| 17 | + return solve_for_power(data); |
| 18 | +} |
16 | 19 |
|
17 |
| - var power; |
18 |
| - if (alternative == 'lower') { |
19 |
| - power = jstat.normal.cdf(jstat.normal.inv(alpha, 0, 1), mean, 1) |
20 |
| - } else if (alternative == 'greater') { |
21 |
| - power = 1-jstat.normal.cdf(jstat.normal.inv(1-alpha, 0, 1), mean, 1) |
22 |
| - } else { |
23 |
| - power = 1 - (jstat.normal.cdf(z, mean, 1) - |
24 |
| - jstat.normal.cdf(-z, mean, 1)) |
25 |
| - } |
| 20 | +function solveforpower_Ttest(data) { |
| 21 | + var { sd_rate } = data; |
| 22 | + data.variance = 2*sd_rate**2; |
26 | 23 |
|
27 |
| - return power |
| 24 | + return solve_for_power(data); |
28 | 25 | }
|
29 | 26 |
|
30 |
| -function solveforpower_Ttest({total_sample_size, base_rate, sd_rate, effect_size, alpha, alternative, mu}) { |
31 |
| - var sample_size = total_sample_size/2; |
| 27 | +function solve_for_power(data) { |
| 28 | + var {total_sample_size, base_rate, variance, effect_size, alpha, variants, alternative, mu} = data; |
| 29 | + var sample_size = total_sample_size / (1 + variants); |
32 | 30 |
|
33 | 31 | var mean_base = base_rate;
|
34 | 32 | var mean_var = base_rate * (1+effect_size);
|
35 | 33 |
|
36 | 34 | var mean_diff = mean_var - mean_base;
|
37 |
| - var delta = mean_diff - mu |
| 35 | + var delta = mean_diff - mu; |
38 | 36 |
|
39 |
| - var variance = 2*sd_rate**2; |
40 |
| - var z = jstat.normal.inv(1-alpha/2, 0, 1) |
| 37 | + var z = jstat.normal.inv(1-alpha/2, 0, 1); |
41 | 38 | var mean = delta*Math.sqrt(sample_size/variance);
|
42 | 39 |
|
43 | 40 | var power;
|
44 | 41 | if (alternative == 'lower') {
|
45 |
| - power = jstat.normal.cdf(jstat.normal.inv(alpha, 0, 1), mean, 1) |
| 42 | + power = jstat.normal.cdf(jstat.normal.inv(alpha, 0, 1), mean, 1); |
46 | 43 | } else if (alternative == 'greater') {
|
47 |
| - power = 1-jstat.normal.cdf(jstat.normal.inv(1-alpha, 0, 1), mean, 1) |
| 44 | + power = 1-jstat.normal.cdf(jstat.normal.inv(1-alpha, 0, 1), mean, 1); |
48 | 45 | } else {
|
49 |
| - power = 1 - (jstat.normal.cdf(z, mean, 1) - |
50 |
| - jstat.normal.cdf(-z, mean, 1)) |
| 46 | + power = 1 - (jstat.normal.cdf(z, mean, 1) - jstat.normal.cdf(-z, mean, 1)); |
51 | 47 | }
|
52 | 48 |
|
53 |
| - return power |
| 49 | + return power; |
54 | 50 | }
|
55 | 51 |
|
56 | 52 |
|
@@ -109,64 +105,28 @@ function solve_quadratic_for_sample({mean_diff, Z, days, threshold, variance}) {
|
109 | 105 | }
|
110 | 106 |
|
111 | 107 | function solveforsample_Ttest(data){
|
112 |
| - var { base_rate, sd_rate, effect_size, alpha, beta, alternative, mu, opts } = data; |
113 |
| - if (!is_valid_input(data)) { |
114 |
| - return NaN; |
115 |
| - } |
116 |
| - var mean_base = base_rate; |
117 |
| - var mean_var = base_rate * (1+effect_size); |
118 |
| - |
119 |
| - var variance = 2*sd_rate**2; |
120 |
| - var mean_diff = mean_var - mean_base; |
121 |
| - |
122 |
| - var multiplier; |
123 |
| - var sample_one_group; |
124 |
| - if (opts && opts.type == 'absolutePerDay') { |
125 |
| - if (opts.calculating == 'visitorsPerDay') { |
126 |
| - var Z; |
127 |
| - if (alternative == "greater") { |
128 |
| - Z = jstat.normal.inv(beta, 0, 1) - jstat.normal.inv(1-alpha, 0, 1); |
129 |
| - } else if (alternative == "lower") { |
130 |
| - Z = jstat.normal.inv(1-beta, 0, 1) - jstat.normal.inv(alpha, 0, 1); |
131 |
| - } else { |
132 |
| - Z = jstat.normal.inv(1-beta, 0, 1) + jstat.normal.inv(1-alpha/2, 0, 1); |
133 |
| - } |
134 |
| - var sqrt_visitors_per_day = solve_quadratic_for_sample({mean_diff: mean_diff, Z: Z, |
135 |
| - days: opts.days, threshold: opts.threshold, variance: variance}); |
136 |
| - sample_one_group = opts.days*sqrt_visitors_per_day**2; |
137 |
| - } else { |
138 |
| - multiplier = variance/(mean_diff*Math.sqrt(opts.visitors_per_day/2) - opts.threshold/(Math.sqrt(2*opts.visitors_per_day)))**2; |
139 |
| - var days; |
140 |
| - if (alternative == "greater" || alternative == "lower") { |
141 |
| - days = multiplier * (jstat.normal.inv(beta, 0, 1) - jstat.normal.inv(1-alpha, 0, 1))**2 |
142 |
| - } else { |
143 |
| - days = multiplier * (jstat.normal.inv(1-beta, 0, 1) + jstat.normal.inv(1-alpha/2, 0, 1))**2 |
144 |
| - } |
145 |
| - sample_one_group = days*opts.visitors_per_day/2; |
146 |
| - } |
147 |
| - } else { |
148 |
| - multiplier = variance/(mu - mean_diff)**2 |
| 108 | + var { sd_rate } = data; |
| 109 | + data.variance = 2*sd_rate**2; |
| 110 | + return sample_size_calculation(data); |
| 111 | +} |
149 | 112 |
|
150 |
| - if (alternative == "greater" || alternative == "lower") { |
151 |
| - sample_one_group = multiplier * (jstat.normal.inv(beta, 0, 1) - jstat.normal.inv(1-alpha, 0, 1))**2 |
152 |
| - } else { |
153 |
| - sample_one_group = multiplier * (jstat.normal.inv(1-beta, 0, 1) + jstat.normal.inv(1-alpha/2, 0, 1))**2 |
154 |
| - } |
155 |
| - } |
| 113 | +function solveforsample_Gtest(data){ |
| 114 | + var { base_rate, effect_size } = data; |
| 115 | + var mean_var = base_rate*(1+effect_size); |
| 116 | + data.variance = base_rate*(1-base_rate) + mean_var*(1-mean_var); |
156 | 117 |
|
157 |
| - return 2*Math.ceil(sample_one_group); |
| 118 | + return sample_size_calculation(data); |
158 | 119 | }
|
159 | 120 |
|
160 |
| -function solveforsample_Gtest(data){ |
161 |
| - var { base_rate, effect_size, alpha, beta, alternative, mu, opts } = data; |
| 121 | +function sample_size_calculation(data) { |
| 122 | + var { base_rate, variance, effect_size, alpha, beta, variants, alternative, mu, opts } = data; |
| 123 | + |
162 | 124 | if (!is_valid_input(data)) {
|
163 |
| - return NaN; |
| 125 | + return NaN; |
164 | 126 | }
|
| 127 | + |
165 | 128 | var mean_base = base_rate;
|
166 | 129 | var mean_var = base_rate*(1+effect_size);
|
167 |
| - |
168 |
| - var variance = mean_base*(1-mean_base) + mean_var*(1-mean_var); |
169 |
| - |
170 | 130 | var mean_diff = mean_var - mean_base;
|
171 | 131 |
|
172 | 132 | var multiplier;
|
@@ -204,14 +164,14 @@ function solveforsample_Gtest(data){
|
204 | 164 | }
|
205 | 165 | }
|
206 | 166 |
|
207 |
| - return 2*Math.ceil(sample_one_group); |
| 167 | + return (1+variants)*Math.ceil(sample_one_group); |
208 | 168 | }
|
209 | 169 |
|
210 | 170 |
|
211 | 171 |
|
212 | 172 | // SOLVING FOR EFFECT SIZE
|
213 |
| -function solveforeffectsize_Ttest({total_sample_size, base_rate, sd_rate, alpha, beta, alternative, mu}){ |
214 |
| - var sample_size = total_sample_size/2; |
| 173 | +function solveforeffectsize_Ttest({total_sample_size, base_rate, sd_rate, alpha, beta, variants, alternative, mu}){ |
| 174 | + var sample_size = total_sample_size / (1 + variants); |
215 | 175 | var variance = 2*sd_rate**2;
|
216 | 176 |
|
217 | 177 | var z = jstat.normal.inv(1-beta, 0, 1);
|
@@ -245,8 +205,8 @@ function solve_quadratic(Z, sample_size, control_rate, mu) {
|
245 | 205 | return [sol_h, sol_l];
|
246 | 206 | }
|
247 | 207 |
|
248 |
| -function solveforeffectsize_Gtest({total_sample_size, base_rate, alpha, beta, alternative, mu}){ |
249 |
| - var sample_size = total_sample_size / 2; |
| 208 | +function solveforeffectsize_Gtest({total_sample_size, base_rate, alpha, beta, variants, alternative, mu}){ |
| 209 | + var sample_size = total_sample_size / (1 + variants); |
250 | 210 |
|
251 | 211 | var rel_effect_size;
|
252 | 212 | var Z;
|
@@ -340,4 +300,5 @@ export default {
|
340 | 300 | getMuFromRelativeDifference: get_mu_from_relative_difference,
|
341 | 301 | getMuFromAbsolutePerDay: get_mu_from_absolute_per_day,
|
342 | 302 | getAlternative: get_alternative,
|
| 303 | + getCorrectedAlpha: get_alpha_sidaks_correction, |
343 | 304 | }
|
0 commit comments