#region License Information /* HeuristicLab * Copyright (C) 2002-2017 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 Split along the ordered training Instances /// internal class OrderImpurityCalculator { internal enum IncrementType { Left, Right, None } #region Properties private double SqSumLeft { get; set; } private double SqSumRight { get; set; } private double VarLeft { get; set; } private double VarRight { get; set; } private double Order { get; set; } private double VarTotal { get; set; } private int NoInstances { get; set; } private double NoLeft { get; set; } private double NoRight { get; set; } private double SumLeft { get; set; } private double SumRight { get; set; } public double Impurity { get; private set; } #endregion #region Constructors public OrderImpurityCalculator(int partition, IReadOnlyCollection data, double order) { var values = data; NoInstances = data.Count; VarTotal = values.VariancePop(); values = data.Take(partition).ToArray(); NoLeft = partition; SumLeft = values.Sum(); SqSumLeft = values.Sum(x => x * x); values = data.Skip(partition).ToArray(); NoRight = NoInstances - NoLeft; SumRight = values.Sum(); SqSumRight = values.Sum(x => x * x); Order = order; Increment(0.0, IncrementType.None); } #endregion #region IImpurityCalculator public void Increment(double value, IncrementType type) { double y, yl, yr; var valSq = value * value; switch (type) { case IncrementType.Left: NoLeft++; NoRight--; SumLeft += value; SumRight -= value; SqSumLeft += valSq; SqSumRight -= valSq; break; case IncrementType.Right: NoLeft--; NoRight++; SumLeft -= value; SumRight += value; SqSumLeft -= valSq; SqSumRight += valSq; break; case IncrementType.None: break; default: throw new ArgumentOutOfRangeException(type.ToString(), type, null); } VarLeft = NoLeft <= 0 ? 0 : Math.Abs(NoLeft * SqSumLeft - SumLeft * SumLeft) / (NoLeft * NoLeft); VarRight = NoRight <= 0 ? 0 : Math.Abs(NoRight * SqSumRight - SumRight * SumRight) / (NoRight * NoRight); if (Order <= 0) throw new ArgumentException("Split order must be larger than 0"); if (Order.IsAlmost(1)) { y = VarTotal; yl = VarLeft; yr = VarRight; } else { y = Math.Pow(VarTotal, 1.0 / Order); yl = Math.Pow(VarLeft, 1.0 / Order); yr = Math.Pow(VarRight, 1.0 / Order); } var t = NoRight + NoLeft; if (NoLeft <= 0.0 || NoRight <= 0.0) Impurity = double.MinValue; //Split = 0; else Impurity = y - NoLeft / t * yl - NoRight / t * yr; // Split = y - NoLeft / NoRight * yl - NoRight / NoLeft * yr } #endregion } }