#region License Information
/* HeuristicLab
* Copyright (C) Heuristic and Evolutionary Algorithms Laboratory (HEAL)
*
* This file is part of HeuristicLab.
*
* HeuristicLab is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* HeuristicLab is distributed in 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with HeuristicLab. If not, see .
*/
#endregion
using System;
using System.Collections.Generic;
using System.Linq;
using HeuristicLab.Common;
namespace HeuristicLab.Algorithms.DataAnalysis {
///
/// Helper class for incremental split calculation.
/// Used while moving a potential splitter along the ordered training instances
///
internal class UnivariateOnlineLR {
#region state
private readonly NeumaierSum targetMean;
private readonly NeumaierSum attributeMean;
private readonly NeumaierSum targetVarSum;
private readonly NeumaierSum attributeVarSum;
private readonly NeumaierSum comoment;
private readonly NeumaierSum ssr;
private int size;
#endregion
public double Ssr {
get { return ssr.Get(); }
}
public int Size {
get { return size; }
}
private double Beta {
get { return comoment.Get() / attributeVarSum.Get(); }
}
private double Alpha {
get { return targetMean.Get() - Beta * attributeMean.Get(); }
}
public UnivariateOnlineLR(ICollection attributeValues, ICollection targetValues) {
if (attributeValues.Count != targetValues.Count) throw new ArgumentException("Targets and Attributes need to have the same length");
size = attributeValues.Count;
var yMean = targetValues.Average();
var xMean = attributeValues.Average();
targetMean = new NeumaierSum(yMean);
attributeMean = new NeumaierSum(xMean);
targetVarSum = new NeumaierSum(targetValues.VariancePop() * size);
attributeVarSum = new NeumaierSum(attributeValues.VariancePop() * size);
comoment = new NeumaierSum(attributeValues.Zip(targetValues, (x, y) => (x - xMean) * (y - yMean)).Sum());
var beta = comoment.Get() / attributeVarSum.Get();
var alpha = yMean - beta * xMean;
ssr = new NeumaierSum(attributeValues.Zip(targetValues, (x, y) => y - alpha - beta * x).Sum(x => x * x));
}
public void Add(double attributeValue, double targetValue) {
var predictOld = Predict(attributeValue, targetValue);
size++;
var dx = attributeValue - attributeMean.Get();
var dy = targetValue - targetMean.Get();
attributeMean.Add(dx / size);
targetMean.Add(dy / size);
var dx2 = attributeValue - attributeMean.Get();
var dy2 = targetValue - targetMean.Get();
attributeVarSum.Add(dx * dx2);
targetVarSum.Add(dy * dy2);
comoment.Add(dx * dy2);
ssr.Add(predictOld * Predict(attributeValue, targetValue));
}
public void Remove(double attributeValue, double targetValue) {
var predictOld = Predict(attributeValue, targetValue);
var dx2 = attributeValue - attributeMean.Get();
var dy2 = targetValue - targetMean.Get();
attributeMean.Mul(size / (size - 1.0));
targetMean.Mul(size / (size - 1.0));
attributeMean.Add(-attributeValue / (size - 1.0));
targetMean.Add(-targetValue / (size - 1.0));
var dx = attributeValue - attributeMean.Get();
var dy = targetValue - targetMean.Get();
attributeVarSum.Add(-dx * dx2);
targetVarSum.Add(-dy * dy2);
comoment.Add(-dx * dy2);
size--;
ssr.Add(-predictOld * Predict(attributeValue, targetValue));
}
private double Predict(double attributeValue, double targetValue) {
return targetValue - Alpha - Beta * attributeValue;
}
}
}