patterncsharpMinor
On-line evaluation of mean and variance in C#
Viewed 0 times
varianceevaluationlinemeanand
Problem
In various projects, I have to evaluate the mean and/or the variance of relatively large samples.
I wrote the following, to help me evaluate these quantities with a constant footprint. Basically, it adds elements one per one and updates the variables.
Which I specialized for doubles :
And Math.Net Vectors :
```
using MathNet.Numerics.LinearAlgebra.Double;
using System;
namespace DataStructures
{
///
/// Holds a "ghost sample" into memory. It h
I wrote the following, to help me evaluate these quantities with a constant footprint. Basically, it adds elements one per one and updates the variables.
namespace DataStructures
{
///
/// Holds a "ghost sample" into memory. It has a constant memory print
/// and updates the size, the average and the variance of the sample.
///
public interface IGhostSample
{
void Add(T element);
T Mean { get; }
T Variance { get; }
T StandardDev { get; }
}
}Which I specialized for doubles :
using System;
namespace DataStructures
{
///
/// Holds a "ghost sample" into memory. It has a constant memory print
/// and updates the size, the average and the variance of the sample.
///
public class GhostSample : IGhostSample
{
#region Private Attributes
private double _mean = 0;
private double _variance = 0;
private int _size = 0;
#endregion
#region Accessors
public int Size
{
get { return _size; }
}
public double Mean
{
get { return _mean; }
}
public double Variance
{
get { return _variance; }
}
public double StandardDev
{
get { return Math.Sqrt(_variance); }
}
#endregion
#region Methods
public void Add(double element)
{
double previousMean = _mean;
_mean = (previousMean * _size + element) / (_size + 1);
_variance = (_size * _variance + (element - previousMean) * (element - _mean)) / (_size + 1);
_size++;
}
#endregion
}
}And Math.Net Vectors :
```
using MathNet.Numerics.LinearAlgebra.Double;
using System;
namespace DataStructures
{
///
/// Holds a "ghost sample" into memory. It h
Solution
Unfortunately there is no interface that defines the operators but you could define your own data type and with a litte over-engineering you get his:
Base class for the argument:
Example double argument:
Calculation:
Usage:
I didn't know how to get rid of the default-parameters :-(
Base class for the argument:
public abstract class Argument
{
protected Argument(T value)
{
Value = value;
}
public T Value { get; }
public abstract Argument Add(Argument y);
public abstract Argument Subtract(Argument y);
public abstract Argument Multiply(Argument y);
public abstract Argument Divide(Argument y);
public abstract Argument Increment();
public abstract Argument Sqrt();
}Example double argument:
public class DoubleArgument : Argument
{
public static DoubleArgument Default = new DoubleArgument(0d);
public DoubleArgument(double value) : base(value) { }
public override Argument Add(Argument y) => (DoubleArgument)(Value + y.Value);
public override Argument Subtract(Argument y) => (DoubleArgument)(Value - y.Value);
public override Argument Multiply(Argument y) => (DoubleArgument)(Value * y.Value);
public override Argument Divide(Argument y) => (DoubleArgument)(Value / y.Value);
public override Argument Increment() => (DoubleArgument)(Value + 1.0);
public override Argument Sqrt() => (DoubleArgument)(Math.Sqrt(Value));
public static implicit operator DoubleArgument(double value) => new DoubleArgument(value);
}Calculation:
public class GhostSample
{
private Argument _mean;
private Argument _variance;
private Argument _size;
public GhostSample(Argument size, Argument mean, Argument variance)
{
_size = size;
_mean = mean;
_variance = variance;
}
public Argument Size => _size;
public Argument Mean => _mean;
public Argument Variance => _variance;
public Argument StandardDev => _variance.Sqrt();
public void Add(Argument element)
{
_size = _size.Increment();
var previousMean = _mean;
_mean = previousMean.Multiply(_size).Add(element).Divide(_size);
_variance = _size.Multiply(_variance).Add(element.Subtract(previousMean).Multiply(element.Subtract(_mean)).Divide(_size));
}
}Usage:
var doubleGhostSample = new GhostSample(DoubleArgument.Default, DoubleArgument.Default, DoubleArgument.Default);
doubleGhostSample.Add((DoubleArgument)2.0);
doubleGhostSample.Add((DoubleArgument)3.0);
doubleGhostSample.Add((DoubleArgument)8.0);I didn't know how to get rid of the default-parameters :-(
Code Snippets
public abstract class Argument<T>
{
protected Argument(T value)
{
Value = value;
}
public T Value { get; }
public abstract Argument<T> Add(Argument<T> y);
public abstract Argument<T> Subtract(Argument<T> y);
public abstract Argument<T> Multiply(Argument<T> y);
public abstract Argument<T> Divide(Argument<T> y);
public abstract Argument<T> Increment();
public abstract Argument<T> Sqrt();
}public class DoubleArgument : Argument<double>
{
public static DoubleArgument Default = new DoubleArgument(0d);
public DoubleArgument(double value) : base(value) { }
public override Argument<double> Add(Argument<double> y) => (DoubleArgument)(Value + y.Value);
public override Argument<double> Subtract(Argument<double> y) => (DoubleArgument)(Value - y.Value);
public override Argument<double> Multiply(Argument<double> y) => (DoubleArgument)(Value * y.Value);
public override Argument<double> Divide(Argument<double> y) => (DoubleArgument)(Value / y.Value);
public override Argument<double> Increment() => (DoubleArgument)(Value + 1.0);
public override Argument<double> Sqrt() => (DoubleArgument)(Math.Sqrt(Value));
public static implicit operator DoubleArgument(double value) => new DoubleArgument(value);
}public class GhostSample<T>
{
private Argument<T> _mean;
private Argument<T> _variance;
private Argument<T> _size;
public GhostSample(Argument<T> size, Argument<T> mean, Argument<T> variance)
{
_size = size;
_mean = mean;
_variance = variance;
}
public Argument<T> Size => _size;
public Argument<T> Mean => _mean;
public Argument<T> Variance => _variance;
public Argument<T> StandardDev => _variance.Sqrt();
public void Add(Argument<T> element)
{
_size = _size.Increment();
var previousMean = _mean;
_mean = previousMean.Multiply(_size).Add(element).Divide(_size);
_variance = _size.Multiply(_variance).Add(element.Subtract(previousMean).Multiply(element.Subtract(_mean)).Divide(_size));
}
}var doubleGhostSample = new GhostSample<double>(DoubleArgument.Default, DoubleArgument.Default, DoubleArgument.Default);
doubleGhostSample.Add((DoubleArgument)2.0);
doubleGhostSample.Add((DoubleArgument)3.0);
doubleGhostSample.Add((DoubleArgument)8.0);Context
StackExchange Code Review Q#132562, answer score: 3
Revisions (0)
No revisions yet.