| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.commons.math.stat.descriptive.moment; |
| |
| import java.io.Serializable; |
| import org.apache.commons.math.exception.NullArgumentException; |
| import org.apache.commons.math.exception.util.LocalizedFormats; |
| import org.apache.commons.math.stat.descriptive.AbstractUnivariateStatistic; |
| |
| /** |
| * <p>Computes the semivariance of a set of values with respect to a given cutoff value. |
| * We define the <i>downside semivariance</i> of a set of values <code>x</code> |
| * against the <i>cutoff value</i> <code>cutoff</code> to be <br/> |
| * <code>Σ (x[i] - target)<sup>2</sup> / df</code> <br/> |
| * where the sum is taken over all <code>i</code> such that <code>x[i] < cutoff</code> |
| * and <code>df</code> is the length of <code>x</code> (non-bias-corrected) or |
| * one less than this number (bias corrected). The <i>upside semivariance</i> |
| * is defined similarly, with the sum taken over values of <code>x</code> that |
| * exceed the cutoff value.</p> |
| * |
| * <p>The cutoff value defaults to the mean, bias correction defaults to <code>true</code> |
| * and the "variance direction" (upside or downside) defaults to downside. The variance direction |
| * and bias correction may be set using property setters or their values can provided as |
| * parameters to {@link #evaluate(double[], double, Direction, boolean, int, int)}.</p> |
| * |
| * <p>If the input array is null, <code>evaluate</code> methods throw |
| * <code>IllegalArgumentException.</code> If the array has length 1, <code>0</code> |
| * is returned, regardless of the value of the <code>cutoff.</code> |
| * |
| * <p><strong>Note that this class is not intended to be threadsafe.</strong> If |
| * multiple threads access an instance of this class concurrently, and one or |
| * more of these threads invoke property setters, external synchronization must |
| * be provided to ensure correct results.</p> |
| * |
| * @version $Revision: 1006299 $ $Date: 2010-10-10 16:47:17 +0200 (dim. 10 oct. 2010) $ |
| * @since 2.1 |
| */ |
| |
| public class SemiVariance extends AbstractUnivariateStatistic implements Serializable { |
| |
| /** |
| * The UPSIDE Direction is used to specify that the observations above the |
| * cutoff point will be used to calculate SemiVariance. |
| */ |
| public static final Direction UPSIDE_VARIANCE = Direction.UPSIDE; |
| |
| /** |
| * The DOWNSIDE Direction is used to specify that the observations below |
| * the cutoff point will be used to calculate SemiVariance |
| */ |
| public static final Direction DOWNSIDE_VARIANCE = Direction.DOWNSIDE; |
| |
| /** Serializable version identifier */ |
| private static final long serialVersionUID = -2653430366886024994L; |
| |
| /** |
| * Determines whether or not bias correction is applied when computing the |
| * value of the statisic. True means that bias is corrected. |
| */ |
| private boolean biasCorrected = true; |
| |
| /** |
| * Determines whether to calculate downside or upside SemiVariance. |
| */ |
| private Direction varianceDirection = Direction.DOWNSIDE; |
| |
| /** |
| * Constructs a SemiVariance with default (true) <code>biasCorrected</code> |
| * property and default (Downside) <code>varianceDirection</code> property. |
| */ |
| public SemiVariance() { |
| } |
| |
| /** |
| * Constructs a SemiVariance with the specified <code>biasCorrected</code> |
| * property and default (Downside) <code>varianceDirection</code> property. |
| * |
| * @param biasCorrected setting for bias correction - true means |
| * bias will be corrected and is equivalent to using the argumentless |
| * constructor |
| */ |
| public SemiVariance(final boolean biasCorrected) { |
| this.biasCorrected = biasCorrected; |
| } |
| |
| |
| /** |
| * Constructs a SemiVariance with the specified <code>Direction</code> property |
| * and default (true) <code>biasCorrected</code> property |
| * |
| * @param direction setting for the direction of the SemiVariance |
| * to calculate |
| */ |
| public SemiVariance(final Direction direction) { |
| this.varianceDirection = direction; |
| } |
| |
| |
| /** |
| * Constructs a SemiVariance with the specified <code>isBiasCorrected</code> |
| * property and the specified <code>Direction</code> property. |
| * |
| * @param corrected setting for bias correction - true means |
| * bias will be corrected and is equivalent to using the argumentless |
| * constructor |
| * |
| * @param direction setting for the direction of the SemiVariance |
| * to calculate |
| */ |
| public SemiVariance(final boolean corrected, final Direction direction) { |
| this.biasCorrected = corrected; |
| this.varianceDirection = direction; |
| } |
| |
| |
| /** |
| * Copy constructor, creates a new {@code SemiVariance} identical |
| * to the {@code original} |
| * |
| * @param original the {@code SemiVariance} instance to copy |
| */ |
| public SemiVariance(final SemiVariance original) { |
| copy(original, this); |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public SemiVariance copy() { |
| SemiVariance result = new SemiVariance(); |
| copy(this, result); |
| return result; |
| } |
| |
| |
| /** |
| * Copies source to dest. |
| * <p>Neither source nor dest can be null.</p> |
| * |
| * @param source SemiVariance to copy |
| * @param dest SemiVariance to copy to |
| * @throws NullPointerException if either source or dest is null |
| */ |
| public static void copy(final SemiVariance source, SemiVariance dest) { |
| dest.setData(source.getDataRef()); |
| dest.biasCorrected = source.biasCorrected; |
| dest.varianceDirection = source.varianceDirection; |
| } |
| |
| |
| /** |
| * This method calculates {@link SemiVariance} for the entire array against the mean, using |
| * instance properties varianceDirection and biasCorrection. |
| * |
| * @param values the input array |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if values is null |
| * |
| */ |
| @Override |
| public double evaluate(final double[] values) { |
| if (values == null) { |
| throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY); |
| } |
| return evaluate(values, 0, values.length); |
| } |
| |
| |
| /** |
| * <p>Returns the {@link SemiVariance} of the designated values against the mean, using |
| * instance properties varianceDirection and biasCorrection.</p> |
| * |
| * <p>Returns <code>NaN</code> if the array is empty and throws |
| * <code>IllegalArgumentException</code> if the array is null.</p> |
| * |
| * @param values the input array |
| * @param start index of the first array element to include |
| * @param length the number of elements to include |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if the parameters are not valid |
| * |
| */ |
| @Override |
| public double evaluate(final double[] values, final int start, final int length) { |
| double m = (new Mean()).evaluate(values, start, length); |
| return evaluate(values, m, varianceDirection, biasCorrected, 0, values.length); |
| } |
| |
| |
| /** |
| * This method calculates {@link SemiVariance} for the entire array against the mean, using |
| * the current value of the biasCorrection instance property. |
| * |
| * @param values the input array |
| * @param direction the {@link Direction} of the semivariance |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if values is null |
| * |
| */ |
| public double evaluate(final double[] values, Direction direction) { |
| double m = (new Mean()).evaluate(values); |
| return evaluate (values, m, direction, biasCorrected, 0, values.length); |
| } |
| |
| /** |
| * <p>Returns the {@link SemiVariance} of the designated values against the cutoff, using |
| * instance properties variancDirection and biasCorrection.</p> |
| * |
| * <p>Returns <code>NaN</code> if the array is empty and throws |
| * <code>IllegalArgumentException</code> if the array is null.</p> |
| * |
| * @param values the input array |
| * @param cutoff the reference point |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if values is null |
| */ |
| public double evaluate(final double[] values, final double cutoff) { |
| return evaluate(values, cutoff, varianceDirection, biasCorrected, 0, values.length); |
| } |
| |
| /** |
| * <p>Returns the {@link SemiVariance} of the designated values against the cutoff in the |
| * given direction, using the current value of the biasCorrection instance property.</p> |
| * |
| * <p>Returns <code>NaN</code> if the array is empty and throws |
| * <code>IllegalArgumentException</code> if the array is null.</p> |
| * |
| * @param values the input array |
| * @param cutoff the reference point |
| * @param direction the {@link Direction} of the semivariance |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if values is null |
| */ |
| public double evaluate(final double[] values, final double cutoff, final Direction direction) { |
| return evaluate(values, cutoff, direction, biasCorrected, 0, values.length); |
| } |
| |
| |
| /** |
| * <p>Returns the {@link SemiVariance} of the designated values against the cutoff |
| * in the given direction with the provided bias correction.</p> |
| * |
| * <p>Returns <code>NaN</code> if the array is empty and throws |
| * <code>IllegalArgumentException</code> if the array is null.</p> |
| * |
| * @param values the input array |
| * @param cutoff the reference point |
| * @param direction the {@link Direction} of the semivariance |
| * @param corrected the BiasCorrection flag |
| * @param start index of the first array element to include |
| * @param length the number of elements to include |
| * @return the SemiVariance |
| * @throws IllegalArgumentException if the parameters are not valid |
| * |
| */ |
| public double evaluate (final double[] values, final double cutoff, final Direction direction, |
| final boolean corrected, final int start, final int length) { |
| |
| test(values, start, length); |
| if (values.length == 0) { |
| return Double.NaN; |
| } else { |
| if (values.length == 1) { |
| return 0.0; |
| } else { |
| final boolean booleanDirection = direction.getDirection(); |
| |
| double dev = 0.0; |
| double sumsq = 0.0; |
| for (int i = start; i < length; i++) { |
| if ((values[i] > cutoff) == booleanDirection) { |
| dev = values[i] - cutoff; |
| sumsq += dev * dev; |
| } |
| } |
| |
| if (corrected) { |
| return sumsq / (length - 1.0); |
| } else { |
| return sumsq / length; |
| } |
| } |
| } |
| } |
| |
| /** |
| * Returns true iff biasCorrected property is set to true. |
| * |
| * @return the value of biasCorrected. |
| */ |
| public boolean isBiasCorrected() { |
| return biasCorrected; |
| } |
| |
| /** |
| * Sets the biasCorrected property. |
| * |
| * @param biasCorrected new biasCorrected property value |
| */ |
| public void setBiasCorrected(boolean biasCorrected) { |
| this.biasCorrected = biasCorrected; |
| } |
| |
| /** |
| * Returns the varianceDirection property. |
| * |
| * @return the varianceDirection |
| */ |
| public Direction getVarianceDirection () { |
| return varianceDirection; |
| } |
| |
| /** |
| * Sets the variance direction |
| * |
| * @param varianceDirection the direction of the semivariance |
| */ |
| public void setVarianceDirection(Direction varianceDirection) { |
| this.varianceDirection = varianceDirection; |
| } |
| |
| /** |
| * The direction of the semivariance - either upside or downside. The direction |
| * is represented by boolean, with true corresponding to UPSIDE semivariance. |
| */ |
| public enum Direction { |
| /** |
| * The UPSIDE Direction is used to specify that the observations above the |
| * cutoff point will be used to calculate SemiVariance |
| */ |
| UPSIDE (true), |
| |
| /** |
| * The DOWNSIDE Direction is used to specify that the observations below |
| * the cutoff point will be used to calculate SemiVariance |
| */ |
| DOWNSIDE (false); |
| |
| /** |
| * boolean value UPSIDE <-> true |
| */ |
| private boolean direction; |
| |
| /** |
| * Create a Direction with the given value. |
| * |
| * @param b boolean value representing the Direction. True corresponds to UPSIDE. |
| */ |
| Direction (boolean b) { |
| direction = b; |
| } |
| |
| /** |
| * Returns the value of this Direction. True corresponds to UPSIDE. |
| * |
| * @return true if direction is UPSIDE; false otherwise |
| */ |
| boolean getDirection () { |
| return direction; |
| } |
| } |
| } |