2
* This program is free software; you can redistribute it and/or modify
3
* it under the terms of the GNU General Public License as published by
4
* the Free Software Foundation; either version 2 of the License, or
5
* (at your option) any later version.
7
* This program is distributed in the hope that it will be useful,
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
* GNU General Public License for more details.
12
* You should have received a copy of the GNU General Public License
13
* along with this program; if not, write to the Free Software
14
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
* Copyright (C) 1999 University of Waikato, Hamilton, New Zealand
24
package weka.experiment;
26
import weka.core.Utils;
27
import weka.core.Statistics;
30
* A class for storing stats on a paired comparison (t-test and correlation)
32
* @author Len Trigg (trigg@cs.waikato.ac.nz)
33
* @version $Revision: 1.9 $
35
public class PairedStats {
37
/** The stats associated with the data in column 1 */
40
/** The stats associated with the data in column 2 */
43
/** The stats associated with the paired differences */
44
public Stats differencesStats;
46
/** The probability of obtaining the observed differences */
47
public double differencesProbability;
49
/** The correlation coefficient */
50
public double correlation;
52
/** The sum of the products */
55
/** The number of data points seen */
59
* A significance indicator:
60
* 0 if the differences are not significant
61
* > 0 if x significantly greater than y
62
* < 0 if x significantly less than y
64
public int differencesSignificance;
66
/** The significance level for comparisons */
67
public double sigLevel;
69
/** The degrees of freedom (if set programmatically) */
70
protected int m_degreesOfFreedom = 0;
73
* Creates a new PairedStats object with the supplied significance level.
75
* @param sig the significance level for comparisons
77
public PairedStats(double sig) {
81
differencesStats = new Stats();
86
* Sets the degrees of freedom (if calibration is required).
88
public void setDegreesOfFreedom(int d) {
91
throw new IllegalArgumentException("PairedStats: degrees of freedom must be >= 1");
93
m_degreesOfFreedom = d;
97
* Gets the degrees of freedom.
99
public int getDegreesOfFreedom() {
101
return m_degreesOfFreedom;
105
* Add an observed pair of values.
107
* @param value1 the value from column 1
108
* @param value2 the value from column 2
110
public void add(double value1, double value2) {
114
differencesStats.add(value1 - value2);
115
xySum += value1 * value2;
120
* Removes an observed pair of values.
122
* @param value1 the value from column 1
123
* @param value2 the value from column 2
125
public void subtract(double value1, double value2) {
127
xStats.subtract(value1);
128
yStats.subtract(value2);
129
differencesStats.subtract(value1 - value2);
130
xySum -= value1 * value2;
136
* Adds an array of observed pair of values.
138
* @param value1 the array containing values from column 1
139
* @param value2 the array containing values from column 2
141
public void add(double value1[], double value2[]) {
142
if ((value1 == null) || (value2 == null)) {
143
throw new NullPointerException();
145
if (value1.length != value2.length) {
146
throw new IllegalArgumentException("Arrays must be of the same length");
148
for (int i = 0; i < value1.length; i++) {
149
add(value1[i], value2[i]);
155
* Removes an array of observed pair of values.
157
* @param value1 the array containing values from column 1
158
* @param value2 the array containing values from column 2
160
public void subtract(double value1[], double value2[]) {
161
if ((value1 == null) || (value2 == null)) {
162
throw new NullPointerException();
164
if (value1.length != value2.length) {
165
throw new IllegalArgumentException("Arrays must be of the same length");
167
for (int i = 0; i < value1.length; i++) {
168
subtract(value1[i], value2[i]);
174
* Calculates the derived statistics (significance etc).
176
public void calculateDerived() {
178
xStats.calculateDerived();
179
yStats.calculateDerived();
180
differencesStats.calculateDerived();
182
correlation = Double.NaN;
183
if (!Double.isNaN(xStats.stdDev) && !Double.isNaN(yStats.stdDev)
184
&& !Utils.eq(xStats.stdDev, 0)) {
185
double slope = (xySum - xStats.sum * yStats.sum / count)
186
/ (xStats.sumSq - xStats.sum * xStats.mean);
187
if (!Utils.eq(yStats.stdDev, 0)) {
188
correlation = slope * xStats.stdDev / yStats.stdDev;
194
if (Utils.gr(differencesStats.stdDev, 0)) {
195
double tval = differencesStats.mean
197
/ differencesStats.stdDev;
199
if (m_degreesOfFreedom >= 1){
200
differencesProbability = Statistics.FProbability(tval * tval, 1,
204
differencesProbability = Statistics.FProbability(tval * tval, 1,
207
differencesProbability = 1;
211
if (differencesStats.sumSq == 0) {
212
differencesProbability = 1.0;
214
differencesProbability = 0.0;
217
differencesSignificance = 0;
218
if (differencesProbability <= sigLevel) {
219
if (xStats.mean > yStats.mean) {
220
differencesSignificance = 1;
222
differencesSignificance = -1;
228
* Returns statistics on the paired comparison.
230
* @return the t-test statistics as a string
232
public String toString() {
234
return "Analysis for " + Utils.doubleToString(count, 0)
241
+ Utils.doubleToString(xStats.min, 17, 4)
242
+ Utils.doubleToString(yStats.min, 17, 4)
243
+ Utils.doubleToString(differencesStats.min, 17, 4) + '\n'
245
+ Utils.doubleToString(xStats.max, 17, 4)
246
+ Utils.doubleToString(yStats.max, 17, 4)
247
+ Utils.doubleToString(differencesStats.max, 17, 4) + '\n'
249
+ Utils.doubleToString(xStats.sum, 17, 4)
250
+ Utils.doubleToString(yStats.sum, 17, 4)
251
+ Utils.doubleToString(differencesStats.sum, 17, 4) + '\n'
253
+ Utils.doubleToString(xStats.sumSq, 17, 4)
254
+ Utils.doubleToString(yStats.sumSq, 17, 4)
255
+ Utils.doubleToString(differencesStats.sumSq, 17, 4) + '\n'
257
+ Utils.doubleToString(xStats.mean, 17, 4)
258
+ Utils.doubleToString(yStats.mean, 17, 4)
259
+ Utils.doubleToString(differencesStats.mean, 17, 4) + '\n'
261
+ Utils.doubleToString(xStats.stdDev, 17, 4)
262
+ Utils.doubleToString(yStats.stdDev, 17, 4)
263
+ Utils.doubleToString(differencesStats.stdDev, 17, 4) + '\n'
264
+ "Prob(differences) "
265
+ Utils.doubleToString(differencesProbability, 4)
266
+ " (sigflag " + differencesSignificance + ")\n"
268
+ Utils.doubleToString(correlation,4) + "\n";
272
* Tests the paired stats object from the command line.
273
* reads line from stdin, expecting two values per line.
275
* @param args ignored.
277
public static void main(String [] args) {
280
PairedStats ps = new PairedStats(0.05);
281
java.io.LineNumberReader r = new java.io.LineNumberReader(
282
new java.io.InputStreamReader(System.in));
284
while ((line = r.readLine()) != null) {
286
if (line.equals("") || line.startsWith("@") || line.startsWith("%")) {
289
java.util.StringTokenizer s
290
= new java.util.StringTokenizer(line, " ,\t\n\r\f");
292
double v1 = 0, v2 = 0;
293
while (s.hasMoreTokens()) {
294
double val = (new Double(s.nextToken())).doubleValue();
297
} else if (count == 1) {
300
System.err.println("MSG: Too many values in line \""
301
+ line + "\", skipped.");
310
ps.calculateDerived();
311
System.err.println(ps);
312
} catch (Exception ex) {
313
ex.printStackTrace();
314
System.err.println(ex.getMessage());