1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 package ffx.numerics.math;
40
41
42 import org.apache.commons.math3.distribution.TDistribution;
43
44 import javax.annotation.Nullable;
45 import java.util.Random;
46
47 import static java.lang.String.format;
48 import static java.util.Arrays.fill;
49 import static org.apache.commons.math3.util.FastMath.sqrt;
50
51
52
53
54
55
56
57
58
59 public class BootStrapStatistics {
60
61
62
63
64
65 public final double mean;
66
67
68
69 public final double var;
70
71
72
73 public final double varPopulation;
74
75
76
77 public final double sd;
78
79
80
81 public final double sdPopulation;
82
83
84
85 public final double sumWeights;
86
87
88
89
90
91 public final double min;
92
93
94
95 public final double max;
96
97
98
99 public final long count;
100
101
102
103 public final double sum;
104
105
106
107 public final long dof;
108 private final TDistribution tDist;
109 private final String descString;
110
111
112
113
114
115
116
117 public BootStrapStatistics(double[] values) {
118 this(values, null, 0, values.length, 1);
119 }
120
121
122
123
124
125
126
127
128 public BootStrapStatistics(double[] values, int first) {
129 this(values, null, first, values.length, 1);
130 }
131
132
133
134
135
136
137
138
139
140 public BootStrapStatistics(double[] values, int first, int last) {
141 this(values, null, first, last, 1);
142 }
143
144
145
146
147
148
149
150
151
152
153 public BootStrapStatistics(double[] values, int first, int last, int stride) {
154 this(values, null, first, last, stride);
155 }
156
157
158
159
160
161
162
163
164
165
166 public BootStrapStatistics(double[] values, @Nullable double[] weights, int first, int last, int stride) {
167 if (values == null) {
168 throw new IllegalArgumentException(" Cannot have null values!");
169 }
170 int nValues = getNumberOfValues(values, first, last);
171
172 if (weights == null) {
173 weights = new double[nValues];
174 fill(weights, 1.0);
175 }
176
177 int tempCount = (last - first);
178 if (tempCount % stride == 0) {
179 count = tempCount / stride;
180 } else {
181 count = (tempCount / stride) + 1;
182 }
183 assert count > 0;
184
185 if (count == 1) {
186 mean = values[first];
187 var = Double.NaN;
188 varPopulation = 0;
189 sd = Double.NaN;
190 sdPopulation = 0;
191 min = mean;
192 max = mean;
193 sum = mean;
194 sumWeights = weights[first];
195 dof = 0;
196 tDist = null;
197 descString = format(" Summary of single observation: value is %17.14g", mean);
198 } else {
199
200 RunningStatistics runningStatistics = getRunningStatistics(values, weights);
201 min = runningStatistics.getMin();
202 max = runningStatistics.getMax();
203 mean = runningStatistics.getMean();
204 sum = runningStatistics.getSum();
205 sumWeights = runningStatistics.getWeight();
206 varPopulation = runningStatistics.getPopulationVariance();
207 sdPopulation = runningStatistics.getPopulationStandardDeviation();
208 dof = runningStatistics.getDOF();
209 var = runningStatistics.getVariance();
210 sd = runningStatistics.getStandardDeviation();
211 tDist = new TDistribution(dof);
212 descString = format(
213 " Summary of %d observations: sum is %17.14g, mean is %17.14g, min is %17.14g, "
214 + "max is %17.14g, and the sum of weights is %17.14g"
215 + "\nSample standard deviation: %17.14g (dof = %d)"
216 + "\nPopulation standard deviation: %17.14g (dof = %d)",
217 count, sum, mean, min, max, sumWeights, sd, dof, sdPopulation, count);
218 }
219 }
220
221 private RunningStatistics getRunningStatistics(double[] values, double[] weights) {
222 RunningStatistics bootstrapRunningStatistics = new RunningStatistics();
223 Random random = new Random();
224
225 for (int bs = 0; bs < count; bs++) {
226
227 RunningStatistics bootstrapRound = new RunningStatistics();
228 for (int i = 0; i < count; i++) {
229 int j = random.nextInt((int) count);
230 bootstrapRound.addValue(values[j], weights[j]);
231 }
232
233 bootstrapRunningStatistics.addValue(bootstrapRound.getMean());
234 }
235 return bootstrapRunningStatistics;
236 }
237
238 private static int getNumberOfValues(double[] values, int first, int last) {
239 int nValues = values.length;
240
241 if (first < 0 || first > (nValues - 1)) {
242 throw new IllegalArgumentException(
243 format(" First entry %d was not in valid range 0-%d (0 to length of values - 1)",
244 first, nValues - 1));
245 }
246 if (last <= first || last > nValues) {
247 throw new IllegalArgumentException(
248 format(" Last entry %d was not in valid range %d-%d (first+1 to length of values",
249 last, (first + 1), nValues));
250 }
251 return nValues;
252 }
253
254
255
256
257
258
259 public double confidenceInterval() {
260 return confidenceInterval(0.05);
261 }
262
263
264
265
266
267
268
269 public double confidenceInterval(double alpha) {
270 if (dof == 0) {
271 throw new IllegalArgumentException(
272 " Cannot calculate confidence intervals when there are no degrees of freedom!");
273 }
274 double critVal = tDist.inverseCumulativeProbability(0.5 * (1.0 - alpha));
275 return critVal * sd / sqrt(count);
276 }
277
278
279
280
281
282
283 public double getMean() {
284 return mean;
285 }
286
287
288
289
290
291
292 public double getSd() {
293 return sd;
294 }
295
296
297
298
299
300
301 public double getVar() {
302 return var;
303 }
304
305
306
307
308 @Override
309 public String toString() {
310 return descString;
311 }
312
313
314
315
316
317
318 public String describe() {
319 return format(" Mean: %12.6f +/-%12.6f, Min/Max: %12.6f/%12.6f", mean, sd, min, max);
320 }
321
322 }