Added Product and Mean to Univariate and all implementations, this patch

contains contributions from Mark Diggory.

* This patch introduces Product and GeometricMean into the Univariate
implementation.

* Discarding the contribution of a discarded element in a rolling
UnivariateImpl requires that the product be calculated explicitly each
time a value is discarded.  This is necessary because not all values will
have non-zero values.

* Errors in rolling logic for ListUimpl, and UnivariateImpl were corrected,
and more test cases were added to the JUnit tests for the Univariate
implementations.  More rigorous test cases are needed for the entire
suite of Univariate implementations


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/math/trunk@140851 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Tim O'Brien 2003-05-21 17:59:20 +00:00
parent a3e8ae46e0
commit 8ed6e84dc6
9 changed files with 189 additions and 27 deletions

View File

@ -57,6 +57,7 @@ package org.apache.commons.math;
* Provides univariate measures for an array of doubles.
*
* @author <a href="mailto:tobrien@apache.org">Tim O'Brien</a>
* @author Mark Diggory
*/
public abstract class AbstractStoreUnivariate implements StoreUnivariate {
@ -158,6 +159,31 @@ public abstract class AbstractStoreUnivariate implements StoreUnivariate {
return arithMean;
}
/**
* Returns the geometric mean for this collection of values
* @see org.apache.commons.math.Univariate#getGeometricMean()
*/
public double getGeometricMean() {
double gMean = Math.pow(getProduct(),(1.0/getN()));
return gMean;
}
/**
* Returns the product for this collection of values
* @see org.apache.commons.math.Univariate#getProduct()
*/
public double getProduct() {
double product = Double.NaN;
if( getN() > 0 ) {
product = 1.0;
for( int i = 0; i < getN(); i++) {
product *= getElement(i);
}
}
return product;
}
/**
* Returns the variance for this collection of values
* @see org.apache.commons.math.Univariate#getVariance()

View File

@ -113,21 +113,24 @@ public class ListUnivariateImpl extends AbstractStoreUnivariate {
double value = Double.NaN;
if (windowSize != Univariate.INIFINTE_WINDOW &&
windowSize < list.size()) {
Number n = (Number) list.get(((list.size() - 1) - windowSize) +
index) ;
int calcIndex = (list.size() - windowSize) + index;
Number n = (Number) list.get(calcIndex);
value = n.doubleValue();
} else {
Number n = (Number) list.get(index);
value = n.doubleValue();
}
System.out.println( "Returning value: " + value );
return value;
}
/* (non-Javadoc)
* @see org.apache.commons.math.Univariate#getN()
*/
public double getN() {
double N = 0.0;
public int getN() {
int N = 0;
if (windowSize != Univariate.INIFINTE_WINDOW) {
if (list.size() > windowSize) {

View File

@ -91,7 +91,7 @@ public class StoreUnivariateImpl extends AbstractStoreUnivariate {
/* (non-Javadoc)
* @see org.apache.commons.math.Univariate#getN()
*/
public double getN() {
public int getN() {
return eDA.getNumElements();
}

View File

@ -61,7 +61,8 @@
*
* @author Phil Steitz
* @author <a href="mailto:tobrien@apache.org">Tim O'Brien</a>
* @version $Revision: 1.4 $ $Date: 2003/05/20 18:15:29 $
* @author Mark Diggory
* @version $Revision: 1.5 $ $Date: 2003/05/21 17:59:19 $
*
*/
public interface Univariate {
@ -78,6 +79,18 @@ public interface Univariate {
*/
public abstract double getMean();
/**
* Returns the geometric mean of the values that have been added
* @return mean value
*/
public abstract double getGeometricMean();
/**
* Returns the product of all values that have been added
* @return product of all values
*/
public abstract double getProduct();
/**
* Returns the variance of the values that have been added
* @return variance value
@ -103,7 +116,7 @@ public interface Univariate {
/** Getter for property n.
* @return Value of property n.
*/
public abstract double getN();
public abstract int getN();
/** Getter for property sum.
* @return Value of property sum.

View File

@ -64,7 +64,9 @@ import java.io.Serializable;
* to doubles by addValue().
*
* @author Phil Steitz
* @version $Revision: 1.5 $ $Date: 2003/05/20 18:15:29 $
* @author Mark Diggory
* @author <a href="mailto:tobrien@apache.org">Tim O'Brien</a>
* @version $Revision: 1.6 $ $Date: 2003/05/21 17:59:19 $
*
*/
public class UnivariateImpl implements Univariate, Serializable {
@ -84,7 +86,7 @@ public class UnivariateImpl implements Univariate, Serializable {
private double sumsq = 0.0;
/** count of values that have been added */
private double n = 0.0;
private int n = 0;
/** min of values that have been added */
private double min = Double.MAX_VALUE;
@ -92,6 +94,9 @@ public class UnivariateImpl implements Univariate, Serializable {
/** max of values that have been added */
private double max = Double.MIN_VALUE;
/** produce of values that have been added */
private double product = Double.NaN;
/** Creates new univariate */
public UnivariateImpl() {
clear();
@ -118,7 +123,23 @@ public class UnivariateImpl implements Univariate, Serializable {
*/
public double getMean() {
// FIXME: throw something meaningful if n = 0
return sum/n;
return (sum / (double) n );
}
/**
* Returns the geometric mean of the values that have been added
* @return geometric mean value
*/
public double getGeometricMean() {
return Math.pow(product,( 1.0/n ) );
}
/**
* Returns the product of all values add to this Univariate
* @return product value
*/
public double getProduct() {
return product;
}
/**
@ -133,7 +154,7 @@ public class UnivariateImpl implements Univariate, Serializable {
variance = 0.0;
} else if( n > 1 ) {
double xbar = getMean();
variance = (sumsq - xbar*xbar*n)/(n-1);
variance = (sumsq - xbar*xbar*((double) n))/(((double) n)-1);
}
return variance;
@ -156,18 +177,25 @@ public class UnivariateImpl implements Univariate, Serializable {
*/
private void insertValue(double v) {
// The default value of product is NaN, if you
// try to retrieve the product for a univariate with
// no values, we return NaN.
//
// If this is the first call to insertValue, we want
// to set product to 1.0, so that our first element
// is not "cancelled" out by the NaN.
if( n == 0 ) {
product = 1.0;
}
if( windowSize != Univariate.INIFINTE_WINDOW ) {
if( windowSize == n ) {
double discarded = doubleArray.addElementRolling( v );
// Remove the influence of discarded value ONLY
// if the discard value has any meaning. In other words
// don't discount until we "roll".
if( windowSize > doubleArray.getNumElements() ) {
// Remove the influence of the discarded
sum -= discarded;
sumsq -= discarded * discarded;
}
// Remove the influence of the discarded
sum -= discarded;
sumsq -= discarded * discarded;
// Include the influence of the new
// TODO: The next two lines seems rather expensive, but
@ -176,6 +204,19 @@ public class UnivariateImpl implements Univariate, Serializable {
max = doubleArray.getMax();
sum += v;
sumsq += v*v;
// Note that the product CANNOT be discarded
// properly because one cannot discount the effect
// of a zero value. For this reason, the product
// of the altered array must be calculated from the
// current array elements. Product must be recalculated
// everytime the array is "rolled"
product = 1.0;
double[] elements = doubleArray.getElements();
for( int i = 0; i < elements.length; i++ ) {
product *= elements[i];
}
} else {
doubleArray.addElement( v );
n += 1.0;
@ -183,6 +224,7 @@ public class UnivariateImpl implements Univariate, Serializable {
if (v > max) max = v;
sum += v;
sumsq += v*v;
product *= v;
}
} else {
// If the windowSize is inifinite please don't take the time to
@ -193,6 +235,7 @@ public class UnivariateImpl implements Univariate, Serializable {
if (v > max) max = v;
sum += v;
sumsq += v*v;
product *= v;
}
}
@ -220,7 +263,7 @@ public class UnivariateImpl implements Univariate, Serializable {
/** Getter for property n.
* @return Value of property n.
*/
public double getN() {
public int getN() {
return n;
}
@ -259,7 +302,7 @@ public class UnivariateImpl implements Univariate, Serializable {
public void clear() {
this.sum = 0.0;
this.sumsq = 0.0;
this.n = 0.0;
this.n = 0;
this.min = Double.MAX_VALUE;
this.max = Double.MIN_VALUE;
}

View File

@ -64,7 +64,7 @@ import junit.framework.TestSuite;
* Test cases for the {@link Univariate} class.
*
* @author <a href="mailto:phil@steitz.com">Phil Steitz</a>
* @version $Revision: 1.2 $ $Date: 2003/05/15 15:38:48 $
* @version $Revision: 1.3 $ $Date: 2003/05/21 17:59:20 $
*/
public final class ListUnivariateImplTest extends TestCase {
@ -151,5 +151,31 @@ public final class ListUnivariateImplTest extends TestCase {
assertEquals("skewness", 1.437424, u.getSkewness(), 0.0001);
assertEquals("kurtosis", 2.37719, u.getKurtosis(), 0.0001);
}
public void testProductAndGeometricMean() throws Exception {
ListUnivariateImpl u = new ListUnivariateImpl(new ArrayList());
u.setWindowSize(10);
u.addValue( 1.0 );
u.addValue( 2.0 );
u.addValue( 3.0 );
u.addValue( 4.0 );
assertEquals( "Product not expected", 24.0, u.getProduct(), Double.MIN_VALUE );
assertEquals( "Geometric mean not expected", 2.213364, u.getGeometricMean(), 0.00001 );
// Now test rolling - UnivariateImpl should discount the contribution
// of a discarded element
for( int i = 0; i < 10; i++ ) {
u.addValue( i + 2 );
}
// Values should be (2,3,4,5,6,7,8,9,10,11)
assertEquals( "Product not expected", 39916800.0, u.getProduct(), 0.00001 );
assertEquals( "Geometric mean not expected", 5.755931, u.getGeometricMean(), 0.00001 );
}
}

View File

@ -61,7 +61,7 @@ import junit.framework.TestSuite;
* Test cases for the {@link Univariate} class.
*
* @author <a href="mailto:phil@steitz.com">Phil Steitz</a>
* @version $Revision: 1.1 $ $Date: 2003/05/15 05:39:01 $
* @version $Revision: 1.2 $ $Date: 2003/05/21 17:59:20 $
*/
public final class StoreUnivariateImplTest extends TestCase {
@ -142,5 +142,31 @@ public final class StoreUnivariateImplTest extends TestCase {
assertEquals("skewness", 1.437424, u.getSkewness(), 0.0001);
assertEquals("kurtosis", 2.37719, u.getKurtosis(), 0.0001);
}
public void testProductAndGeometricMean() throws Exception {
StoreUnivariateImpl u = new StoreUnivariateImpl();
u.setWindowSize(10);
u.addValue( 1.0 );
u.addValue( 2.0 );
u.addValue( 3.0 );
u.addValue( 4.0 );
assertEquals( "Product not expected", 24.0, u.getProduct(), Double.MIN_VALUE );
assertEquals( "Geometric mean not expected", 2.213364, u.getGeometricMean(), 0.00001 );
// Now test rolling - UnivariateImpl should discount the contribution
// of a discarded element
for( int i = 0; i < 10; i++ ) {
u.addValue( i + 2 );
}
// Values should be (2,3,4,5,6,7,8,9,10,11)
assertEquals( "Product not expected", 39916800.0, u.getProduct(), 0.00001 );
assertEquals( "Geometric mean not expected", 5.755931, u.getGeometricMean(), 0.00001 );
}
}

View File

@ -61,7 +61,7 @@ import junit.framework.TestSuite;
* Test cases for the {@link Univariate} class.
*
* @author <a href="mailto:phil@steitz.com">Phil Steitz</a>
* @version $Revision: 1.1 $ $Date: 2003/05/15 05:39:01 $
* @version $Revision: 1.2 $ $Date: 2003/05/21 17:59:20 $
*/
public final class UnivariateImplTest extends TestCase {
@ -125,5 +125,30 @@ public final class UnivariateImplTest extends TestCase {
assertTrue( "Mean of n = 1 set should be zero", u.getStandardDeviation() == 0);
assertTrue( "Variance of n = 1 set should be zero", u.getVariance() == 0);
}
public void testProductAndGeometricMean() throws Exception {
UnivariateImpl u = new UnivariateImpl(10);
u.addValue( 1.0 );
u.addValue( 2.0 );
u.addValue( 3.0 );
u.addValue( 4.0 );
assertEquals( "Product not expected", 24.0, u.getProduct(), Double.MIN_VALUE );
assertEquals( "Geometric mean not expected", 2.213364, u.getGeometricMean(), 0.00001 );
// Now test rolling - UnivariateImpl should discount the contribution
// of a discarded element
for( int i = 0; i < 10; i++ ) {
u.addValue( i + 2 );
}
// Values should be (2,3,4,5,6,7,8,9,10,11)
assertEquals( "Product not expected", 39916800.0, u.getProduct(), 0.00001 );
assertEquals( "Geometric mean not expected", 5.755931, u.getGeometricMean(), 0.00001 );
}
}

View File

@ -63,7 +63,7 @@ import java.net.URL;
* Test cases for the ValueServer class.
*
* @author Phil Steitz
* @version $Revision: 1.1 $
* @version $Revision: 1.2 $
*/
public final class ValueServerTest extends TestCase {
@ -105,9 +105,9 @@ public final class ValueServerTest extends TestCase {
next = vs.getNext();
stats.addValue(next);
}
assertEquals("mean", stats.getMean(),5.069831575018909,tolerance);
assertEquals("mean", 5.069831575018909, stats.getMean(), tolerance);
assertEquals
("std dev", stats.getStandardDeviation(),1.0173699343977738,tolerance);
("std dev", 1.0173699343977738, stats.getStandardDeviation(), tolerance);
}
/**