BinningResult.java
/**
* VStar: a statistical analysis tool for variable star data.
* Copyright (C) 2010 AAVSO (http://www.aavso.org/)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.aavso.tools.vstar.util.stats;
import java.util.List;
import org.aavso.tools.vstar.data.SeriesType;
import org.aavso.tools.vstar.data.ValidObservation;
import org.aavso.tools.vstar.util.prefs.NumericPrecisionPrefs;
import org.apache.commons.math.stat.inference.OneWayAnova;
import org.apache.commons.math.stat.inference.OneWayAnovaImpl;
/**
* The result of a binning operation including mean observations (with averages
* and confidence intervals per bin), magnitude bins, and analysis of variance
* results (F-test, p-value).
*/
public class BinningResult {
private SeriesType series;
private int sourceObsCount;
private List<ValidObservation> meanObservations;
private List<double[]> magnitudeBins;
private double fValue;
private double pValue;
private boolean error;
/**
* Constructor
*
* @param series
* The series type of the observations.
* @param sourceObsCount
* The number of source observations.
* @param meanObservations
* A list of mean observations.
* @param magnitudeBins
* The corresponding magnitude bins that gave rise to the binned
* mean observations.
*/
public BinningResult(SeriesType series, int sourceObsCount,
List<ValidObservation> meanObservations,
List<double[]> magnitudeBins) {
this.series = series;
this.sourceObsCount = sourceObsCount;
this.meanObservations = meanObservations;
this.magnitudeBins = magnitudeBins;
this.error = false;
OneWayAnova anova = new OneWayAnovaImpl();
try {
fValue = anova.anovaFValue(this.magnitudeBins);
pValue = anova.anovaPValue(this.magnitudeBins);
} catch (Exception e) {
error = true;
fValue = Double.NaN;
pValue = Double.NaN;
}
}
/**
* @return the series
*/
public SeriesType getSeries() {
return series;
}
/**
* @return the meanObservations
*/
public List<ValidObservation> getMeanObservations() {
return meanObservations;
}
/**
* @return the magnitudeBins
*/
public List<double[]> getMagnitudeBins() {
return magnitudeBins;
}
/**
* @return the fValue
*/
public double getFValue() {
return fValue;
}
/**
* @return the pValue
*/
public double getPValue() {
return pValue;
}
/**
* Returns the between-group degrees of freedom for the F-test result. This
* is defined as: df(b) = K-1 where K is the number of groups.
*
* @return The degrees of freedom.
*/
public int getBetweenGroupDF() {
return magnitudeBins.size() - 1;
}
/**
* Returns the within-group degrees of freedom for the F-test result. This
* is defined as: df(w) = (N1-1)+(N2-1)+...+(Nm-1) where N1..Nm are the
* number of values within each group. This should be k (the number of
* groups, i.e. bins) less than N, the total number of data-points
* (observations) used for binning.
*
* @return The degrees of freedom.
*/
public int getWithinGroupDF() {
// int sum = 0;
//
// for (double[] binData : magnitudeBins) {
// sum += (binData.length - 1);
// }
// N-k
int N_minus_k = sourceObsCount - magnitudeBins.size();
// assert N_minus_k == sum;
return N_minus_k;
}
/**
* Does this binning result have a sane F-test and p-values? Insufficient
* data is one reason why the values may not be valid.
*
* @return Whether or not the ANOVA values are valid.
*/
public boolean hasValidAnovaValues() {
return !error;
}
// Returns ANOVA result text suitable for display.
public String createAnovaText() {
String msg = null;
// Example: F-value: 18.22 on 12 and 346 degrees of freedom p-value: <
// 0.000001.
if (hasValidAnovaValues()) {
String pValueStr;
if (getPValue() < 0.000001) {
pValueStr = "p-value: < 0.000001";
} else {
pValueStr = "p-value: "
+ NumericPrecisionPrefs.formatOther(getPValue());
}
msg = String.format(
"%s, F-value: %s on %d and %d degrees of freedom, %s", getSeries(),
NumericPrecisionPrefs.formatOther(getFValue()),
getBetweenGroupDF(), getWithinGroupDF(), pValueStr);
} else {
msg = "anova: insufficient data";
}
return msg;
}
}