All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.invation.code.toval.statistic.Observation Maven / Gradle / Ivy

package de.invation.code.toval.statistic;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.invation.code.toval.misc.CollectionUtils;
import de.invation.code.toval.misc.FormatUtils;
import de.invation.code.toval.misc.MapUtils;


/**
 * Class for managing a set of observation values.
* Inserted values are kept in a sequential list in insertion order and additionally * in a map containing distinct values together with their frequency of occurrence. * Basic information like the average value, minimum and maximum * are extended by the probabilistic measures of value expectation * and a configurable set of discrete moments. * * @author Thomas Stocker */ public class Observation implements Serializable { private static final long serialVersionUID = 55062028890455772L; protected int momentPrecision = 6; protected int standardPrecision = 2; /** * Sequential list of all values in insertion order. */ protected ArrayList insertSeq = new ArrayList(); /** * Map of distinct inserted values together with their frequency of occurrence. */ protected HashMap insertStat = new HashMap(); /** * Number of inserted values. */ protected double observationCount = 0.0; /** * Average over the inserted values (arithmetic). */ private double average = 0.0; /** * Minimum inserted value. */ private double minimum = Double.MAX_VALUE; /** * Maximal inserted value. */ private double maximum = Double.MIN_VALUE; /** * The expected value (probabilistic measure). */ protected Double expectation = null; /** * Controls which central moments are calculated and kept in {@link Observation#moments} * Set to {@link Observation#DEFAULT_MOMENTS} if not set explicitly. */ protected Collection momentDegrees = DEFAULT_MOMENTS; /** * Predefined (default) set of moment degrees that comprises the values [2,3,4]. */ protected static final List DEFAULT_MOMENTS = Arrays.asList(2,3,4); /** * Central moments (probabilistic measures).
*
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
*/ protected HashMap moments = new HashMap(momentDegrees.size()); /** * Controls the observations' update behavior.
* If true the expectation and all moments are recalculated after every value insertion.
* Default value is false. */ private boolean alwaysUpToDate = false; /** * Name of the observation.
* Set to {@link Observation#DEFAULT_NAME} if not set explicitly. */ protected String name = DEFAULT_NAME; /** * Default observation name. */ protected static String DEFAULT_NAME = ""; /** * Index-pointer used for resetting the state of the observation.
* In case of a reset, all values having a higher index are deleted. */ private int resetIndex = -1; //-----CONSTRUCTORS-------------------------------------------------------------------------- /** * Creates a new empty observation.
* @see #Observation(String) */ public Observation() { this(DEFAULT_NAME); } /** * Creates a new empty observation using the given name.
* @param name The observations' name * @see Observation#name */ public Observation(String name) { this.name = name; } /** * Creates a new empty observation with the given update behavior.
* @param alwaysUpToDate The observations' update behavior. * @see Observation#alwaysUpToDate * @see #Observation(String, boolean) */ public Observation(boolean alwaysUpToDate){ this(DEFAULT_NAME, alwaysUpToDate); } /** * Creates a new empty observation with the given name and update behavior.
* @param name The observations' name * @param alwaysUpToDate The observations' update behavior * @see #name * @see #alwaysUpToDate */ public Observation(String name, boolean alwaysUpToDate){ this.name = name; this.alwaysUpToDate = alwaysUpToDate; } /** * Creates an observation with the given initial set of values.
* @param values Initial set of values. * @see #Observation(String, Collection) */ public Observation(Collection values) { this(DEFAULT_NAME, values); } /** * Creates an observation with the given name and initial set of values.
* @param name The observations' name * @param values Initial set of values. * @see #Observation(String) * @see #addValue(double) */ public Observation(String name, Collection values) { this(name); for(Double d: values) { addValue(d); } resetIndex = values.size()-1; } /** * Creates an observation with the given update behavior and initial set of values.
* @param values Initial set of values. * @param alwaysUpToDate The observations' update behavior * @see #Observation(String, Collection, boolean) */ public Observation(Collection values, boolean alwaysUpToDate) { this(DEFAULT_NAME, values, alwaysUpToDate); } /** * Creates an observation with the given name, update behavior and initial set of values.
* @param name The observations' name * @param values Initial set of values. * @param alwaysUpToDate The observations' update behavior * @see #Observation(String, Collection) * @see #update() */ public Observation(String name, Collection values, boolean alwaysUpToDate) { this(name, values); this.alwaysUpToDate = alwaysUpToDate; if(alwaysUpToDate) update(); } //-----GETTER + SETTER-------------------------------------------------------------------------- /** * Sets the standard precision used for String conversions of inserted values. */ public void setStandardPrecision(int precision) { if(precision < 0) throw new IllegalArgumentException("Floating-point format expected."); this.standardPrecision = precision; } /** * Sets the observations' update behavior.
* If true the expectation and all moments are recalculated after every value insertion. * @param alwaysUpToDate * @see #alwaysUpToDate */ public void setAlwaysUpToDate(boolean alwaysUpToDate) { this.alwaysUpToDate = alwaysUpToDate; } /** * Returns the observations' update behavior.
* If true the expectation and all moments are recalculated after every value insertion. * @return The observations' update behavior * @see #alwaysUpToDate */ public boolean isAlwaysUpToDate() { return alwaysUpToDate; } /** * Returns the minimal inserted value. * @return The minimal inserted value * @see #minimum */ public double getMinimum() { return minimum; } /** * Returns the maximal inserted value. * @return The maximal inserted value * @see #maximum */ public double getMaximum() { return maximum; } /** * Returns the degrees of the moments that are calculated. * Moments are characteristics of random variables (in this case relating to the inserted values) *
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
* @return The degrees of the moments that are calculated. * @see #momentDegrees * @see Collections#unmodifiableCollection(Collection) */ public Collection getMomentDegrees() { return Collections.unmodifiableCollection(momentDegrees); } /** * Sets the degrees of the moments that are calculated using a collection of integers.
* Moments are characteristics of random variables (in this case relating to the inserted values) *
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
* If there are calculated moments a recalculation is triggered. * @param degrees The degrees of the moments that are calculated. * @see #momentDegrees */ public void setMomentDegrees(Collection degrees){ momentDegrees = degrees; if(!moments.isEmpty()) setMoments(); } /** * Sets the degrees of the moments that are calculated using integer varargs.
* Moments are characteristics of random variables (in this case relating to the inserted values) *
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
* If there are calculated moments a recalculation is triggered. * @param degrees The degrees of the moments that are calculated. * @see #momentDegrees * @see #setMomentDegrees(Collection) */ public void setMomentDegrees(Integer... degrees) { setMomentDegrees(Arrays.asList(degrees)); } /** * Returns the number of inserted values. * @return The number of inserted values * @see #observationCount */ public double getObservationCount() { return observationCount; } /** * Returns the number of occurrences of the given value. * @param value The value for which the number of occurrences is desired * @return The number of occurrences of the given value * @throws IllegalArgumentException if there are no occurrences of value */ public Integer getOccurrencesOf(Double value) { if(!insertStat.containsKey(value)) throw new IllegalArgumentException("No occurrences of value \""+value+"\""); return insertStat.get(value); } /** * Returns the number of distinct values amongst all inserted values. * @return The number of distinct values */ public Set getDistinctValues(){ return insertStat.keySet(); } /** * Returns the average (arithmetic) of all inserted values. * @return The average (arithmetic) of all inserted values */ public double getAverage() { return average; } /** * Returns the last inserted value. * @return The last inserted value */ public double getLastValue() { return getValueAt(insertSeq.size()-1); } /** * Returns the inserted value of a given insertion step. * @param index Index of the desired insertion step * @return The inserted value of a given insertion step. */ public double getValueAt(int index) { if(index <0 || index>=insertSeq.size()) throw new IndexOutOfBoundsException(); return insertSeq.get(index); } /** * Returns a list containing all inserted values. * @return A list containing all inserted values * @see Collections#unmodifiableList(List) * @see #insertSeq */ public List getValues(){ return Collections.unmodifiableList(insertSeq); } /** * Returns the value statistic which consists of a list
* containing for every distinct inserted value the number of its occurrences. * @return A statistic of all inserted values * @see Collections#unmodifiableMap(Map) * @see #insertStat */ public Map getValueStatistic(){ return Collections.unmodifiableMap(insertStat); } /** * Returns the expected value (probabilistic measure). * @return The expected value (probabilistic measure) * @see #expectation */ public double getExpectation() { if(expectation == null) setExpectation(); return expectation; } /** * Returns a map containing all calculated moments (probabilistic measures), accessible by their degree. * Moments are characteristics of random variables (in this case relating to the inserted values) *
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
* @return The calculated moments (probabilistic measure) * @see #moments */ public HashMap getMoments() { if(moments.isEmpty()) setMoments(); return moments; } public double getVariance(){ if(moments.isEmpty()) setMoments(); return moments.get(2); } //-----FUNCTIONALITY-------------------------------------------------------------------------- /** * Adds a new value to the observation.
* The given value is inserted in a list containing sequential inserts ({@link #insertSeq})
* and in a map containing distinct values and occurrences ({@link #insertStat}).
* The {@link #average}, {@link #maximum} and {@link #minimum} are adjusted,
* just like the {@link #expectation} and all {@link #moments} in case the update behavior is set accordingly. * finally it increments the {@link #observationCount}. * @param value New value to be inserted * @see #alwaysUpToDate * @see #update() */ public void addValue(double value) { average = (average*observationCount + value) / (observationCount + 1); if(value < minimum) minimum = value; if(value > maximum) maximum = value; insertSeq.add(value); Integer c = insertStat.get(value); if(c == null) c = 0; insertStat.put(value, ++c); observationCount++; if(alwaysUpToDate) update(); } /** * Determines the expectation which is a probabilistic measure,
* estimating the next inserted value based on all values inserted so far. * @see #expectation */ protected void setExpectation() { expectation = 0.0; for(Double d: insertStat.keySet()) { expectation += d*(insertStat.get(d)/observationCount); } } /** * Determines moments (probabilistic measure) of all degrees specified by {@link #momentDegrees}. * Moments are characteristics of random variables (in this case relating to the inserted values) *
    *
  • 2nd moment: variance
  • *
  • 3rd moment: skewness (Schiefe)
  • *
  • 4th moment: kurtosis (Woelbung)
  • *
  • ...
  • *
*/ protected void setMoments() { moments.clear(); for(Integer i: momentDegrees) moments.put(i, 0.0); for(Double d: insertStat.keySet()) { for(int j: momentDegrees) moments.put(j, moments.get(j)+Math.pow(d-expectation, j)*(insertStat.get(d)/observationCount)); } } /** * Triggers a recalculation of the expectation and all moments. */ public void update() { setExpectation(); setMoments(); } /** * Resets the observation to the initial state after creation.
* Potential changed values for update behavior or moment degrees are kept. */ public void reset() { Double[] init = null; if(resetIndex>-1) init = Arrays.copyOfRange(insertSeq.toArray(new Double[resetIndex+1]), 0, resetIndex); insertSeq.clear(); insertStat.clear(); observationCount = 0.0; average = 0.0; minimum = Double.MAX_VALUE; maximum = Double.MIN_VALUE; expectation = null; moments.clear(); if(init != null) for(Double value: init) { addValue(value); } } /** * Returns a String representation of the observation containing all values and characteristics
* using identation which is specified by identation as the number of spaces. * @param identation The number of spaces used for identation * @return A String representation of the observation with identation */ public String toString(int identation) { if(identation <0) throw new IllegalArgumentException("identation cannot be <0"); String header; if(identation ==0) header=""; else header = String.format(String.format("%%%ss", identation), ""); StringBuilder builder = new StringBuilder(); builder.append(header); builder.append("[Obs] "); builder.append(name); builder.append("\n"); builder.append(header); builder.append(" inserts: "); builder.append(CollectionUtils.toString(insertSeq, standardPrecision)); builder.append("\n"); builder.append(header); builder.append(" count: "); builder.append((int) getObservationCount()); builder.append("\n"); builder.append(header); builder.append(" statistic: "); builder.append(MapUtils.toString(insertStat, standardPrecision)); builder.append("\n"); builder.append(header); builder.append(" expect: "); builder.append(FormatUtils.format(getExpectation())); builder.append("\n"); builder.append(header); builder.append(" moments: "); HashMap m = getMoments(); if(m.isEmpty()) { builder.append("- \n"); } else { for(Integer i: getMoments().keySet()) { builder.append(i); builder.append("="); builder.append(FormatUtils.format(m.get(i), momentPrecision)); builder.append(" "); } builder.append("\n"); } builder.append(header); builder.append(" updates: "); builder.append(alwaysUpToDate ? "update on insert" : "update on get"); builder.append("\n"); return builder.toString(); } /** * Returns a String representation of the observation containing all values and characteristics. * @return A String representation of the observation; * @see #toString(int) */ @Override public String toString() { return toString(0); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy