field_test 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/README.md +2 -2
- data/ext/field_test/bayestest.hpp +49 -33
- data/lib/field_test/version.rb +1 -1
- metadata +8 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70d3fdf1a39390631baa12589f108d99852f02009daaaf9ca0d50756630bb3c9
|
4
|
+
data.tar.gz: ba0700b9b9eaed0610d7343e7dff096e6e0e3572919832e8deae189fe5833df8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f6c1c6c82b05b4373ef899c1c53ee4d788eb5d9eabc90d827db7e04ee66ec8bc398047f2d080be14af031fd461632078cfa88dcbe9a776ef64d0647f7854cbe
|
7
|
+
data.tar.gz: 768f3018bbb87d22f4d39b41b09ec02914f2a7c4de679236675a2280fbee7bf90c64f09e4645f8966dbc79204ed267a2dcf03df6cfecc432b3103e15eeb5a4cd
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -189,8 +189,8 @@ Keep track of when experiments started and ended. Use any format `Time.parse` ac
|
|
189
189
|
```yml
|
190
190
|
experiments:
|
191
191
|
button_color:
|
192
|
-
started_at: Dec 1,
|
193
|
-
ended_at: Dec 8,
|
192
|
+
started_at: Dec 1, 2024 8 am PST
|
193
|
+
ended_at: Dec 8, 2024 2 pm PST
|
194
194
|
```
|
195
195
|
|
196
196
|
Add a friendlier name and description with:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*!
|
2
|
-
* BayesTest C++ v0.1.
|
2
|
+
* BayesTest C++ v0.1.2
|
3
3
|
* https://github.com/ankane/bayestest-cpp
|
4
4
|
* MIT License
|
5
5
|
*/
|
@@ -11,6 +11,8 @@
|
|
11
11
|
|
12
12
|
namespace bayestest {
|
13
13
|
|
14
|
+
namespace {
|
15
|
+
|
14
16
|
double logbeta(double a, double b) {
|
15
17
|
return std::lgamma(a) + std::lgamma(b) - std::lgamma(a + b);
|
16
18
|
}
|
@@ -21,7 +23,7 @@ double prob_b_beats_a(int alpha_a, int beta_a, int alpha_b, int beta_b) {
|
|
21
23
|
double beta_ba = beta_b + beta_a;
|
22
24
|
|
23
25
|
for (auto i = 0; i < alpha_b; i++) {
|
24
|
-
total += exp(logbeta(alpha_a + i, beta_ba) - log(beta_b + i) - logbeta(1 + i, beta_b) - logbeta_aa_ba);
|
26
|
+
total += std::exp(logbeta(alpha_a + i, beta_ba) - std::log(beta_b + i) - logbeta(1 + i, beta_b) - logbeta_aa_ba);
|
25
27
|
}
|
26
28
|
|
27
29
|
return total;
|
@@ -36,7 +38,7 @@ double prob_c_beats_ab(int alpha_a, int beta_a, int alpha_b, int beta_b, int alp
|
|
36
38
|
log_bb_j_logbeta_j_bb.reserve(alpha_b);
|
37
39
|
|
38
40
|
for (auto j = 0; j < alpha_b; j++) {
|
39
|
-
log_bb_j_logbeta_j_bb.push_back(log(beta_b + j) + logbeta(1 + j, beta_b));
|
41
|
+
log_bb_j_logbeta_j_bb.push_back(std::log(beta_b + j) + logbeta(1 + j, beta_b));
|
40
42
|
}
|
41
43
|
|
42
44
|
double abc = beta_a + beta_b + beta_c;
|
@@ -48,15 +50,17 @@ double prob_c_beats_ab(int alpha_a, int beta_a, int alpha_b, int beta_b, int alp
|
|
48
50
|
}
|
49
51
|
|
50
52
|
for (auto i = 0; i < alpha_a; i++) {
|
51
|
-
double sum_i = -log(beta_a + i) - logbeta(1 + i, beta_a) - logbeta_ac_bc;
|
53
|
+
double sum_i = -std::log(beta_a + i) - logbeta(1 + i, beta_a) - logbeta_ac_bc;
|
52
54
|
|
53
55
|
for (auto j = 0; j < alpha_b; j++) {
|
54
|
-
total += exp(sum_i + logbeta_ac_i_j[i + j] - log_bb_j_logbeta_j_bb[j]);
|
56
|
+
total += std::exp(sum_i + logbeta_ac_i_j[i + j] - log_bb_j_logbeta_j_bb[j]);
|
55
57
|
}
|
56
58
|
}
|
57
59
|
|
58
|
-
return 1
|
59
|
-
prob_b_beats_a(alpha_c, beta_c,
|
60
|
+
return 1
|
61
|
+
- prob_b_beats_a(alpha_c, beta_c, alpha_a, beta_a)
|
62
|
+
- prob_b_beats_a(alpha_c, beta_c, alpha_b, beta_b)
|
63
|
+
+ total;
|
60
64
|
}
|
61
65
|
|
62
66
|
double prob_d_beats_abc(int alpha_a, int beta_a, int alpha_b, int beta_b, int alpha_c, int beta_c, int alpha_d, int beta_d) {
|
@@ -68,14 +72,14 @@ double prob_d_beats_abc(int alpha_a, int beta_a, int alpha_b, int beta_b, int al
|
|
68
72
|
log_bb_j_logbeta_j_bb.reserve(alpha_b);
|
69
73
|
|
70
74
|
for (auto j = 0; j < alpha_b; j++) {
|
71
|
-
log_bb_j_logbeta_j_bb.push_back(log(beta_b + j) + logbeta(1 + j, beta_b));
|
75
|
+
log_bb_j_logbeta_j_bb.push_back(std::log(beta_b + j) + logbeta(1 + j, beta_b));
|
72
76
|
}
|
73
77
|
|
74
78
|
std::vector<double> log_bc_k_logbeta_k_bc;
|
75
79
|
log_bc_k_logbeta_k_bc.reserve(alpha_c);
|
76
80
|
|
77
81
|
for (auto k = 0; k < alpha_c; k++) {
|
78
|
-
log_bc_k_logbeta_k_bc.push_back(log(beta_c + k) + logbeta(1 + k, beta_c));
|
82
|
+
log_bc_k_logbeta_k_bc.push_back(std::log(beta_c + k) + logbeta(1 + k, beta_c));
|
79
83
|
}
|
80
84
|
|
81
85
|
double abcd = beta_a + beta_b + beta_c + beta_d;
|
@@ -87,36 +91,38 @@ double prob_d_beats_abc(int alpha_a, int beta_a, int alpha_b, int beta_b, int al
|
|
87
91
|
}
|
88
92
|
|
89
93
|
for (auto i = 0; i < alpha_a; i++) {
|
90
|
-
double sum_i = -log(beta_a + i) - logbeta(1 + i, beta_a) - logbeta_ad_bd;
|
94
|
+
double sum_i = -std::log(beta_a + i) - logbeta(1 + i, beta_a) - logbeta_ad_bd;
|
91
95
|
|
92
96
|
for (auto j = 0; j < alpha_b; j++) {
|
93
97
|
double sum_j = sum_i - log_bb_j_logbeta_j_bb[j];
|
94
98
|
|
95
99
|
for (auto k = 0; k < alpha_c; k++) {
|
96
|
-
total += exp(sum_j + logbeta_bd_i_j_k[i + j + k] - log_bc_k_logbeta_k_bc[k]);
|
100
|
+
total += std::exp(sum_j + logbeta_bd_i_j_k[i + j + k] - log_bc_k_logbeta_k_bc[k]);
|
97
101
|
}
|
98
102
|
}
|
99
103
|
}
|
100
104
|
|
101
|
-
return 1
|
102
|
-
prob_b_beats_a(
|
103
|
-
prob_b_beats_a(
|
104
|
-
|
105
|
-
prob_c_beats_ab(alpha_a, beta_a,
|
106
|
-
prob_c_beats_ab(
|
105
|
+
return 1
|
106
|
+
- prob_b_beats_a(alpha_a, beta_a, alpha_d, beta_d)
|
107
|
+
- prob_b_beats_a(alpha_b, beta_b, alpha_d, beta_d)
|
108
|
+
- prob_b_beats_a(alpha_c, beta_c, alpha_d, beta_d)
|
109
|
+
+ prob_c_beats_ab(alpha_a, beta_a, alpha_b, beta_b, alpha_d, beta_d)
|
110
|
+
+ prob_c_beats_ab(alpha_a, beta_a, alpha_c, beta_c, alpha_d, beta_d)
|
111
|
+
+ prob_c_beats_ab(alpha_b, beta_b, alpha_c, beta_c, alpha_d, beta_d)
|
112
|
+
- total;
|
107
113
|
}
|
108
114
|
|
109
115
|
double prob_1_beats_2(int alpha_1, int beta_1, int alpha_2, int beta_2) {
|
110
116
|
double total = 0.0;
|
111
|
-
double log_b1 = log(beta_1);
|
112
|
-
double a2_log_b2 = alpha_2 * log(beta_2);
|
113
|
-
double log_b1_b2 = log(beta_1 + beta_2);
|
117
|
+
double log_b1 = std::log(beta_1);
|
118
|
+
double a2_log_b2 = alpha_2 * std::log(beta_2);
|
119
|
+
double log_b1_b2 = std::log(beta_1 + beta_2);
|
114
120
|
|
115
121
|
for (auto k = 0; k < alpha_1; k++) {
|
116
|
-
total += exp(k * log_b1 +
|
122
|
+
total += std::exp(k * log_b1 +
|
117
123
|
a2_log_b2 -
|
118
124
|
(k + alpha_2) * log_b1_b2 -
|
119
|
-
log(k + alpha_2) -
|
125
|
+
std::log(k + alpha_2) -
|
120
126
|
logbeta(k + 1, alpha_2));
|
121
127
|
}
|
122
128
|
|
@@ -126,33 +132,40 @@ double prob_1_beats_2(int alpha_1, int beta_1, int alpha_2, int beta_2) {
|
|
126
132
|
double prob_1_beats_23(int alpha_1, int beta_1, int alpha_2, int beta_2, int alpha_3, int beta_3) {
|
127
133
|
double total = 0.0;
|
128
134
|
|
129
|
-
double log_b1_b2_b3 = log(beta_1 + beta_2 + beta_3);
|
130
|
-
double a1_log_b1 = alpha_1 * log(beta_1);
|
131
|
-
double log_b2 = log(beta_2);
|
132
|
-
double log_b3 = log(beta_3);
|
135
|
+
double log_b1_b2_b3 = std::log(beta_1 + beta_2 + beta_3);
|
136
|
+
double a1_log_b1 = alpha_1 * std::log(beta_1);
|
137
|
+
double log_b2 = std::log(beta_2);
|
138
|
+
double log_b3 = std::log(beta_3);
|
133
139
|
double loggamma_a1 = std::lgamma(alpha_1);
|
134
140
|
|
135
141
|
for (auto k = 0; k < alpha_2; k++) {
|
136
142
|
double sum_k = a1_log_b1 + k * log_b2 - std::lgamma(k + 1);
|
137
143
|
|
138
144
|
for (auto l = 0; l < alpha_3; l++) {
|
139
|
-
total += exp(sum_k + l * log_b3
|
145
|
+
total += std::exp(sum_k + l * log_b3
|
140
146
|
- (k + l + alpha_1) * log_b1_b2_b3
|
141
147
|
+ std::lgamma(k + l + alpha_1) - std::lgamma(l + 1) - loggamma_a1);
|
142
148
|
}
|
143
149
|
}
|
144
150
|
|
145
|
-
return 1
|
146
|
-
- prob_1_beats_2(
|
151
|
+
return 1
|
152
|
+
- prob_1_beats_2(alpha_2, beta_2, alpha_1, beta_1)
|
153
|
+
- prob_1_beats_2(alpha_3, beta_3, alpha_1, beta_1)
|
154
|
+
+ total;
|
155
|
+
}
|
156
|
+
|
147
157
|
}
|
148
158
|
|
159
|
+
/// A test for binary outcomes.
|
149
160
|
class BinaryTest {
|
150
161
|
public:
|
162
|
+
/// Adds a new variant.
|
151
163
|
void add(int participants, int conversions) {
|
152
164
|
variants.emplace_back(participants, conversions);
|
153
165
|
}
|
154
166
|
|
155
|
-
|
167
|
+
/// Returns the winning probability of each variant.
|
168
|
+
std::vector<double> probabilities() const {
|
156
169
|
std::vector<double> probs;
|
157
170
|
probs.reserve(variants.size());
|
158
171
|
|
@@ -233,7 +246,7 @@ public:
|
|
233
246
|
|
234
247
|
private:
|
235
248
|
struct Variant {
|
236
|
-
Variant(int participants, int conversions) : participants(participants), conversions(conversions) {}
|
249
|
+
Variant(int participants, int conversions) : participants(participants), conversions(conversions) {}
|
237
250
|
int participants;
|
238
251
|
int conversions;
|
239
252
|
};
|
@@ -241,13 +254,16 @@ private:
|
|
241
254
|
std::vector<Variant> variants;
|
242
255
|
};
|
243
256
|
|
257
|
+
/// A test for count data.
|
244
258
|
class CountTest {
|
245
259
|
public:
|
260
|
+
/// Adds a new variant.
|
246
261
|
void add(int events, int exposure) {
|
247
262
|
variants.emplace_back(events, exposure);
|
248
263
|
}
|
249
264
|
|
250
|
-
|
265
|
+
/// Returns the winning probability of each variant.
|
266
|
+
std::vector<double> probabilities() const {
|
251
267
|
std::vector<double> probs;
|
252
268
|
probs.reserve(variants.size());
|
253
269
|
|
@@ -302,7 +318,7 @@ public:
|
|
302
318
|
|
303
319
|
private:
|
304
320
|
struct Variant {
|
305
|
-
Variant(int events, int exposure) : events(events), exposure(exposure) {}
|
321
|
+
Variant(int events, int exposure) : events(events), exposure(exposure) {}
|
306
322
|
int events;
|
307
323
|
int exposure;
|
308
324
|
};
|
data/lib/field_test/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: field_test
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kane
|
8
|
-
autorequire:
|
9
8
|
bindir: bin
|
10
9
|
cert_chain: []
|
11
|
-
date:
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
12
11
|
dependencies:
|
13
12
|
- !ruby/object:Gem::Dependency
|
14
13
|
name: railties
|
@@ -16,28 +15,28 @@ dependencies:
|
|
16
15
|
requirements:
|
17
16
|
- - ">="
|
18
17
|
- !ruby/object:Gem::Version
|
19
|
-
version: '7'
|
18
|
+
version: '7.1'
|
20
19
|
type: :runtime
|
21
20
|
prerelease: false
|
22
21
|
version_requirements: !ruby/object:Gem::Requirement
|
23
22
|
requirements:
|
24
23
|
- - ">="
|
25
24
|
- !ruby/object:Gem::Version
|
26
|
-
version: '7'
|
25
|
+
version: '7.1'
|
27
26
|
- !ruby/object:Gem::Dependency
|
28
27
|
name: activerecord
|
29
28
|
requirement: !ruby/object:Gem::Requirement
|
30
29
|
requirements:
|
31
30
|
- - ">="
|
32
31
|
- !ruby/object:Gem::Version
|
33
|
-
version: '7'
|
32
|
+
version: '7.1'
|
34
33
|
type: :runtime
|
35
34
|
prerelease: false
|
36
35
|
version_requirements: !ruby/object:Gem::Requirement
|
37
36
|
requirements:
|
38
37
|
- - ">="
|
39
38
|
- !ruby/object:Gem::Version
|
40
|
-
version: '7'
|
39
|
+
version: '7.1'
|
41
40
|
- !ruby/object:Gem::Dependency
|
42
41
|
name: browser
|
43
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,7 +65,6 @@ dependencies:
|
|
66
65
|
- - ">="
|
67
66
|
- !ruby/object:Gem::Version
|
68
67
|
version: 4.3.3
|
69
|
-
description:
|
70
68
|
email: andrew@ankane.org
|
71
69
|
executables: []
|
72
70
|
extensions:
|
@@ -109,7 +107,6 @@ homepage: https://github.com/ankane/field_test
|
|
109
107
|
licenses:
|
110
108
|
- MIT
|
111
109
|
metadata: {}
|
112
|
-
post_install_message:
|
113
110
|
rdoc_options: []
|
114
111
|
require_paths:
|
115
112
|
- lib
|
@@ -117,15 +114,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
114
|
requirements:
|
118
115
|
- - ">="
|
119
116
|
- !ruby/object:Gem::Version
|
120
|
-
version: '3.
|
117
|
+
version: '3.2'
|
121
118
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
119
|
requirements:
|
123
120
|
- - ">="
|
124
121
|
- !ruby/object:Gem::Version
|
125
122
|
version: '0'
|
126
123
|
requirements: []
|
127
|
-
rubygems_version: 3.
|
128
|
-
signing_key:
|
124
|
+
rubygems_version: 3.6.7
|
129
125
|
specification_version: 4
|
130
126
|
summary: A/B testing for Rails
|
131
127
|
test_files: []
|