repicea.stats.estimates.Estimate Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of repicea-mathstats Show documentation
Show all versions of repicea-mathstats Show documentation
Mathematical and statistical methods
/*
* This file is part of the repicea-statistics library.
*
* Copyright (C) 2009-2012 Mathieu Fortin for Rouge-Epicea
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed with 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 Lesser General Public
* License for more details.
*
* Please see the license at http://www.gnu.org/copyleft/lesser.html.
*/
package repicea.stats.estimates;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import repicea.math.AbstractMatrix;
import repicea.math.ComplexMatrix;
import repicea.math.Matrix;
import repicea.math.SymmetricMatrix;
import repicea.serial.SerializerChangeMonitor;
import repicea.stats.Distribution;
import repicea.stats.RandomVariable;
/**
* The Estimate class is the basic class for all estimates.
* @author Mathieu Fortin - March 2012
* @param an AbstractMatrix-derived class that stands for the mean
* @param an AbstractMatrix-derived class that stands for the variance
* @param a Distribution derived instance which represents the assumed distribution for the estimate
*/
@SuppressWarnings("rawtypes")
public abstract class Estimate> extends RandomVariable {
static {
SerializerChangeMonitor.registerEnumNameChange("repicea.stats.estimates.Estimate$EstimatorType", "MonteCarlo", "Resampling");
}
private static final long serialVersionUID = 20120825L;
protected EstimatorType estimatorType;
protected final List rowIndex;
/**
* The type of estimator.
* @author Mathieu Fortin - March 2012
s */
public static enum EstimatorType {
Resampling,
LeastSquares,
LikelihoodBased,
MomentBased,
Unknown}
protected Estimate(D distribution) {
super(distribution);
rowIndex = new ArrayList();
}
/**
* This method returns the type of the estimator.
* @return an EstimatorType instance
*/
public EstimatorType getEstimatorType() {return estimatorType;}
/**
* This method makes it possible to set an optional row index. This is useful when the
* response is a vector.
* @param newRowIndex a List of String instance. A null value reset the
*/
public void setRowIndex(List newRowIndex) {
this.rowIndex.clear();
if (newRowIndex != null && !newRowIndex.isEmpty()) {
if (newRowIndex.size() != getMean().m_iRows) {
throw new InvalidParameterException("The size of the list is incompatible with tne dimension of the estimate!");
}
this.rowIndex.addAll(newRowIndex);
}
}
/**
* This method returns a copy of the row index.
* @return a List of String instance or null if the row index has not been set.
*/
public List getRowIndex() {
List rowIndexCopy = new ArrayList();
rowIndexCopy.addAll(rowIndex);
return rowIndexCopy;
}
/**
* This method returns a random deviate from this estimate. This method
* is useful for Monte Carlo simulations.
* @return a deviate from the underlying distribution as a Matrix instance
*/
public M getRandomDeviate() {
return getDistribution().getRandomRealization();
}
/**
* This method returns an difference estimate.
* @param estimate2 an Estimate to be subtracted from this estimate.
* @return an Estimate
*/
@SuppressWarnings("unchecked")
public Estimate getDifferenceEstimate(Estimate estimate2) {
M diff = (M) getMean().subtract(estimate2.getMean());
if (diff instanceof ComplexMatrix) {
throw new UnsupportedOperationException("The method getDifferenceEstimate has not been implemented for ComplexMatrix yet!");
}
Matrix variance = (Matrix) getVariance().add(estimate2.getVariance());
if (variance instanceof SymmetricMatrix) {
return (Estimate) new GaussianEstimate((Matrix) diff, (SymmetricMatrix) variance);
} else {
throw new UnsupportedOperationException("The variance object is not a SymmetricMatrix instance!");
}
}
/**
* This method returns a sum of two estimates.
* @param estimate2 an Estimate to be added to this estimate.
* @return an Estimate
*/
@SuppressWarnings("unchecked")
public Estimate getSumEstimate(Estimate estimate2) {
M diff = (M) getMean().add(estimate2.getMean());
if (diff instanceof ComplexMatrix) {
throw new UnsupportedOperationException("The method getSumEstimate has not been implemented for ComplexMatrix yet!");
}
Matrix variance = (Matrix) getVariance().add(estimate2.getVariance());
if (variance instanceof SymmetricMatrix) {
return (Estimate) new GaussianEstimate((Matrix) diff, (SymmetricMatrix) variance);
} else {
throw new UnsupportedOperationException("The variance object is not a SymmetricMatrix instance!");
}
}
/**
* This method returns an difference estimate.
* @param scalar a double to be multiplied by this estimate
* @return an Estimate
*/
@SuppressWarnings("unchecked")
public Estimate getProductEstimate(double scalar) {
M diff = (M) getMean().scalarMultiply(scalar);
if (diff instanceof ComplexMatrix) {
throw new UnsupportedOperationException("The method getProductEstimate has not been implemented for ComplexMatrix yet!");
}
SymmetricMatrix variance = (SymmetricMatrix) getVariance().scalarMultiply(scalar * scalar);
return (Estimate) new GaussianEstimate((Matrix) diff, variance);
}
/**
* This method returns the probability of getting a lower valueand upper bound of a confidence intervals at probability
* level 1 - alpha
* @param oneMinusAlpha is 1 minus the probability of Type I error
* @return a ConfidenceInterval instance
*/
public abstract ConfidenceInterval getConfidenceIntervalBounds(double oneMinusAlpha);
/**
* This method checks if the two point estimates are compatible. The basic
* check consists of comparing the classes. Then, the matrix data is checked
* for consistency with previous data.
* @param estimate an Estimate instance
* @return a boolean
*/
protected boolean isMergeableEstimate(Estimate,?,?> estimate) {
return false;
}
/**
* Returns an estimate of the product of two parametric univariate estimate. The variance
* estimator is based on Goodman's estimator.
* @param estimate an Estimate instance
* @return a SimpleEstimate instance
*/
public SimpleEstimate getProductEstimate(Estimate estimate) {
if (estimate.getDistribution().isUnivariate() && getDistribution().isUnivariate()) {
M alphaMu = getMean();
M betaMu = estimate.getMean();
if (alphaMu instanceof ComplexMatrix || betaMu instanceof ComplexMatrix) {
throw new UnsupportedOperationException("The method getProductEstimate has not been implemented for ComplexMatrix yet!");
}
Matrix alphaMean = (Matrix) alphaMu;
Matrix betaMean = (Matrix) betaMu;
Matrix alphaVariance = (Matrix) getVariance();
Matrix betaVariance = (Matrix) estimate.getVariance();
Matrix newMean = alphaMean.multiply(betaMean);
Matrix newVariance = alphaMean.elementWisePower(2d).multiply(betaVariance).
add(betaMean.elementWisePower(2d).multiply(alphaVariance)).
subtract(alphaVariance.multiply(betaVariance));
return new SimpleEstimate(newMean, SymmetricMatrix.convertToSymmetricIfPossible(newVariance));
}
throw new InvalidParameterException("The getProductEstimate is only implemented for parametric univariate distribution ");
}
public static SimpleEstimate getProductOfManyEstimates(List> estimates) {
Estimate currentEstimate = null;
for (int i = 1; i < estimates.size(); i++) {
if (i == 1) {
currentEstimate = estimates.get(i-1);
}
currentEstimate = currentEstimate.getProductEstimate(estimates.get(i));
}
return (SimpleEstimate) currentEstimate;
}
/**
* Collapse the estimate following a map that contains the indices for each group.
*
* The collapsing ensures the consistency, that is all the row indices must be found in the
* list instances contained in the map argument. If there is a mismatch, the method will throw an
* exception. IMPORTANT: the new indices, that is the keys of the map argument are sorted in the
* new Estimate instance.
* @param desiredIndicesForCollapsing a LinkedHashMap with the keys being the new indices and
* the values being lists of indices to be collapsed.
* @return an Estimate instance
*/
public Estimate collapseEstimate(LinkedHashMap> desiredIndicesForCollapsing) {
return collapseMeanAndVariance(desiredIndicesForCollapsing);
}
protected final Estimate collapseMeanAndVariance(LinkedHashMap> desiredIndicesForCollapsing) {
M m = getMean();
if (!(m instanceof Matrix)) {
throw new UnsupportedOperationException("The collapseEstimate method is meant for Estimate based on Matrix instance!");
}
Matrix mean = (Matrix) m;
if (rowIndex.isEmpty()) {
throw new InvalidParameterException("The row indices have not been set yet!");
}
if (rowIndex.size() != mean.m_iRows) {
throw new InvalidParameterException("The size of the list is incompatible with tne dimension of the estimate!");
}
List copyOfIndex = new ArrayList();
copyOfIndex.addAll(getRowIndex());
Collections.sort(copyOfIndex);
List completeList = new ArrayList();
for (List l : desiredIndicesForCollapsing.values()) {
completeList.addAll(l);
}
Collections.sort(completeList);
if (!completeList.equals(copyOfIndex)) {
throw new InvalidParameterException("Some indices are missing in the desiredIndicesForCollapsing or cannot be found in the row indices!");
}
// P oldMean = getMean();
Matrix newMean = collapseRowVector(mean, desiredIndicesForCollapsing);
Matrix oldVariance = (Matrix) getVariance();
Matrix newVariance = collapseSquareMatrix(oldVariance, desiredIndicesForCollapsing);
Estimate outputEstimate = new SimpleEstimate(newMean, SymmetricMatrix.convertToSymmetricIfPossible(newVariance));
List newIndexRow = new ArrayList(desiredIndicesForCollapsing.keySet());
Collections.sort(newIndexRow);
outputEstimate.setRowIndex(newIndexRow);
return outputEstimate;
}
protected final Matrix collapseRowVector(Matrix originalMatrix, LinkedHashMap> desiredIndicesForCollapsing) {
List newIndexRow = new ArrayList(desiredIndicesForCollapsing.keySet());
Collections.sort(newIndexRow);
Matrix collapsedMatrix = new Matrix(desiredIndicesForCollapsing.size(), 1);
for (int i = 0; i < collapsedMatrix.m_iRows; i++) {
List requestedIndices = desiredIndicesForCollapsing.get(newIndexRow.get(i));
collapsedMatrix.setValueAt(i, 0, originalMatrix.getSubMatrix(convertIndexIntoInteger(requestedIndices), null).getSumOfElements());
}
return collapsedMatrix;
}
protected final Matrix collapseSquareMatrix(Matrix originalMatrix, LinkedHashMap> desiredIndicesForCollapsing) {
if (originalMatrix == null) { // means the variance cannot be calculated as in the MonteCarloEstimate class if the nb realizations is smaller than 2.
return null;
} else {
List newIndexRow = new ArrayList(desiredIndicesForCollapsing.keySet());
Collections.sort(newIndexRow);
Matrix collapsedMatrix = new Matrix(desiredIndicesForCollapsing.size(), desiredIndicesForCollapsing.size());
for (int i = 0; i < collapsedMatrix.m_iRows; i++) {
List requestedIndices_i = desiredIndicesForCollapsing.get(newIndexRow.get(i));
for (int j = 0; j < collapsedMatrix.m_iRows; j++) {
List requestedIndices_j = desiredIndicesForCollapsing.get(newIndexRow.get(j));
Matrix tmpMatrix = originalMatrix.getSubMatrix(convertIndexIntoInteger(requestedIndices_i),
convertIndexIntoInteger(requestedIndices_j));
collapsedMatrix.setValueAt(i, j, tmpMatrix.getSumOfElements());
}
}
return collapsedMatrix;
}
}
private List convertIndexIntoInteger(List selectedIndices) {
List outputList = new ArrayList();
for (String s : selectedIndices) {
outputList.add(getRowIndex().indexOf(s));
}
return outputList;
}
@Override
public final M getMean() {
return super.getMean();
}
@Override
public final V getVariance() {
return super.getVariance();
}
}