[13646] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
| 3 | * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
| 4 | * and the BEACON Center for the Study of Evolution in Action.
|
---|
| 5 | *
|
---|
| 6 | * This file is part of HeuristicLab.
|
---|
| 7 | *
|
---|
| 8 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 9 | * it under the terms of the GNU General Public License as published by
|
---|
| 10 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 11 | * (at your option) any later version.
|
---|
| 12 | *
|
---|
| 13 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 16 | * GNU General Public License for more details.
|
---|
| 17 | *
|
---|
| 18 | * You should have received a copy of the GNU General Public License
|
---|
| 19 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 20 | */
|
---|
| 21 | #endregion
|
---|
| 22 |
|
---|
| 23 | using System;
|
---|
| 24 | using System.Collections.Generic;
|
---|
| 25 | using System.Linq;
|
---|
| 26 | using System.Threading;
|
---|
| 27 | using HeuristicLab.Analysis;
|
---|
| 28 | using HeuristicLab.Common;
|
---|
| 29 | using HeuristicLab.Core;
|
---|
| 30 | using HeuristicLab.Data;
|
---|
| 31 | using HeuristicLab.Encodings.SymbolicExpressionTreeEncoding;
|
---|
| 32 | using HeuristicLab.Optimization;
|
---|
| 33 | using HeuristicLab.Parameters;
|
---|
| 34 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
| 35 | using HeuristicLab.Problems.DataAnalysis;
|
---|
| 36 | using HeuristicLab.Problems.DataAnalysis.Symbolic;
|
---|
| 37 | using HeuristicLab.Problems.DataAnalysis.Symbolic.Regression;
|
---|
| 38 | using HeuristicLab.Random;
|
---|
[13653] | 39 | using HeuristicLab.Selection;
|
---|
[13646] | 40 |
|
---|
| 41 | namespace HeuristicLab.Algorithms.DataAnalysis.MctsSymbolicRegression {
|
---|
| 42 | [Item("Gradient Boosting Machine Regression (GBM)",
|
---|
| 43 | "Gradient boosting for any regression base learner (e.g. MCTS symbolic regression)")]
|
---|
| 44 | [StorableClass]
|
---|
| 45 | [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 350)]
|
---|
| 46 | public class GradientBoostingRegressionAlgorithm : BasicAlgorithm {
|
---|
| 47 | public override Type ProblemType {
|
---|
| 48 | get { return typeof(IRegressionProblem); }
|
---|
| 49 | }
|
---|
| 50 |
|
---|
| 51 | public new IRegressionProblem Problem {
|
---|
| 52 | get { return (IRegressionProblem)base.Problem; }
|
---|
| 53 | set { base.Problem = value; }
|
---|
| 54 | }
|
---|
| 55 |
|
---|
| 56 | #region ParameterNames
|
---|
| 57 |
|
---|
| 58 | private const string IterationsParameterName = "Iterations";
|
---|
| 59 | private const string NuParameterName = "Nu";
|
---|
| 60 | private const string MParameterName = "M";
|
---|
| 61 | private const string RParameterName = "R";
|
---|
| 62 | private const string RegressionAlgorithmParameterName = "RegressionAlgorithm";
|
---|
| 63 | private const string SeedParameterName = "Seed";
|
---|
| 64 | private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
|
---|
| 65 | private const string CreateSolutionParameterName = "CreateSolution";
|
---|
| 66 | private const string RegressionAlgorithmSolutionResultParameterName = "RegressionAlgorithmResult";
|
---|
| 67 |
|
---|
| 68 | #endregion
|
---|
| 69 |
|
---|
| 70 | #region ParameterProperties
|
---|
| 71 |
|
---|
| 72 | public IFixedValueParameter<IntValue> IterationsParameter {
|
---|
| 73 | get { return (IFixedValueParameter<IntValue>)Parameters[IterationsParameterName]; }
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | public IFixedValueParameter<DoubleValue> NuParameter {
|
---|
| 77 | get { return (IFixedValueParameter<DoubleValue>)Parameters[NuParameterName]; }
|
---|
| 78 | }
|
---|
| 79 |
|
---|
| 80 | public IFixedValueParameter<DoubleValue> RParameter {
|
---|
| 81 | get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
|
---|
| 82 | }
|
---|
| 83 |
|
---|
| 84 | public IFixedValueParameter<DoubleValue> MParameter {
|
---|
| 85 | get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
|
---|
| 86 | }
|
---|
| 87 |
|
---|
| 88 | // regression algorithms are currently: DataAnalysisAlgorithms, BasicAlgorithms and engine algorithms with no common interface
|
---|
| 89 | public IConstrainedValueParameter<IAlgorithm> RegressionAlgorithmParameter {
|
---|
| 90 | get { return (IConstrainedValueParameter<IAlgorithm>)Parameters[RegressionAlgorithmParameterName]; }
|
---|
| 91 | }
|
---|
| 92 |
|
---|
| 93 | public IFixedValueParameter<StringValue> RegressionAlgorithmSolutionResultParameter {
|
---|
| 94 | get { return (IFixedValueParameter<StringValue>)Parameters[RegressionAlgorithmSolutionResultParameterName]; }
|
---|
| 95 | }
|
---|
| 96 |
|
---|
| 97 | public IFixedValueParameter<IntValue> SeedParameter {
|
---|
| 98 | get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
|
---|
| 99 | }
|
---|
| 100 |
|
---|
| 101 | public FixedValueParameter<BoolValue> SetSeedRandomlyParameter {
|
---|
| 102 | get { return (FixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
|
---|
| 103 | }
|
---|
| 104 |
|
---|
| 105 | public IFixedValueParameter<BoolValue> CreateSolutionParameter {
|
---|
| 106 | get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | #endregion
|
---|
| 110 |
|
---|
| 111 | #region Properties
|
---|
| 112 |
|
---|
| 113 | public int Iterations {
|
---|
| 114 | get { return IterationsParameter.Value.Value; }
|
---|
| 115 | set { IterationsParameter.Value.Value = value; }
|
---|
| 116 | }
|
---|
| 117 |
|
---|
| 118 | public int Seed {
|
---|
| 119 | get { return SeedParameter.Value.Value; }
|
---|
| 120 | set { SeedParameter.Value.Value = value; }
|
---|
| 121 | }
|
---|
| 122 |
|
---|
| 123 | public bool SetSeedRandomly {
|
---|
| 124 | get { return SetSeedRandomlyParameter.Value.Value; }
|
---|
| 125 | set { SetSeedRandomlyParameter.Value.Value = value; }
|
---|
| 126 | }
|
---|
| 127 |
|
---|
| 128 | public double Nu {
|
---|
| 129 | get { return NuParameter.Value.Value; }
|
---|
| 130 | set { NuParameter.Value.Value = value; }
|
---|
| 131 | }
|
---|
| 132 |
|
---|
| 133 | public double R {
|
---|
| 134 | get { return RParameter.Value.Value; }
|
---|
| 135 | set { RParameter.Value.Value = value; }
|
---|
| 136 | }
|
---|
| 137 |
|
---|
| 138 | public double M {
|
---|
| 139 | get { return MParameter.Value.Value; }
|
---|
| 140 | set { MParameter.Value.Value = value; }
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | public bool CreateSolution {
|
---|
| 144 | get { return CreateSolutionParameter.Value.Value; }
|
---|
| 145 | set { CreateSolutionParameter.Value.Value = value; }
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | public IAlgorithm RegressionAlgorithm {
|
---|
| 149 | get { return RegressionAlgorithmParameter.Value; }
|
---|
| 150 | }
|
---|
| 151 |
|
---|
| 152 | public string RegressionAlgorithmResult {
|
---|
| 153 | get { return RegressionAlgorithmSolutionResultParameter.Value.Value; }
|
---|
| 154 | set { RegressionAlgorithmSolutionResultParameter.Value.Value = value; }
|
---|
| 155 | }
|
---|
| 156 |
|
---|
| 157 | #endregion
|
---|
| 158 |
|
---|
| 159 | [StorableConstructor]
|
---|
| 160 | protected GradientBoostingRegressionAlgorithm(bool deserializing)
|
---|
| 161 | : base(deserializing) {
|
---|
| 162 | }
|
---|
| 163 |
|
---|
| 164 | protected GradientBoostingRegressionAlgorithm(GradientBoostingRegressionAlgorithm original, Cloner cloner)
|
---|
| 165 | : base(original, cloner) {
|
---|
| 166 | }
|
---|
| 167 |
|
---|
| 168 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
| 169 | return new GradientBoostingRegressionAlgorithm(this, cloner);
|
---|
| 170 | }
|
---|
| 171 |
|
---|
| 172 | public GradientBoostingRegressionAlgorithm() {
|
---|
| 173 | Problem = new RegressionProblem(); // default problem
|
---|
| 174 | var mctsSymbReg = new MctsSymbolicRegressionAlgorithm();
|
---|
[13653] | 175 | mctsSymbReg.Iterations = 10000;
|
---|
| 176 | mctsSymbReg.StoreAlgorithmInEachRun = false;
|
---|
| 177 | var sgp = CreateOSGP();
|
---|
[13646] | 178 | var regressionAlgs = new ItemSet<IAlgorithm>(new IAlgorithm[] {
|
---|
[13653] | 179 | new RandomForestRegression(),
|
---|
| 180 | sgp,
|
---|
[13646] | 181 | mctsSymbReg
|
---|
| 182 | });
|
---|
| 183 | foreach (var alg in regressionAlgs) alg.Prepare();
|
---|
| 184 |
|
---|
| 185 |
|
---|
| 186 | Parameters.Add(new FixedValueParameter<IntValue>(IterationsParameterName,
|
---|
| 187 | "Number of iterations", new IntValue(100)));
|
---|
| 188 | Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName,
|
---|
| 189 | "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
|
---|
| 190 | Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName,
|
---|
| 191 | "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
|
---|
| 192 | Parameters.Add(new FixedValueParameter<DoubleValue>(NuParameterName,
|
---|
| 193 | "The learning rate nu when updating predictions in GBM (0 < nu <= 1)", new DoubleValue(0.5)));
|
---|
| 194 | Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName,
|
---|
| 195 | "The fraction of rows that are sampled randomly for the base learner in each iteration (0 < r <= 1)",
|
---|
| 196 | new DoubleValue(1)));
|
---|
| 197 | Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName,
|
---|
| 198 | "The fraction of variables that are sampled randomly for the base learner in each iteration (0 < m <= 1)",
|
---|
| 199 | new DoubleValue(0.5)));
|
---|
| 200 | Parameters.Add(new ConstrainedValueParameter<IAlgorithm>(RegressionAlgorithmParameterName,
|
---|
| 201 | "The regression algorithm to use as a base learner", regressionAlgs, mctsSymbReg));
|
---|
| 202 | Parameters.Add(new FixedValueParameter<StringValue>(RegressionAlgorithmSolutionResultParameterName,
|
---|
| 203 | "The name of the solution produced by the regression algorithm", new StringValue("Solution")));
|
---|
| 204 | Parameters[RegressionAlgorithmSolutionResultParameterName].Hidden = true;
|
---|
| 205 | Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName,
|
---|
| 206 | "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
|
---|
| 207 | Parameters[CreateSolutionParameterName].Hidden = true;
|
---|
| 208 | }
|
---|
| 209 |
|
---|
| 210 | protected override void Run(CancellationToken cancellationToken) {
|
---|
| 211 | // Set up the algorithm
|
---|
| 212 | if (SetSeedRandomly) Seed = new System.Random().Next();
|
---|
| 213 | var rand = new MersenneTwister((uint)Seed);
|
---|
| 214 |
|
---|
| 215 | // Set up the results display
|
---|
| 216 | var iterations = new IntValue(0);
|
---|
| 217 | Results.Add(new Result("Iterations", iterations));
|
---|
| 218 |
|
---|
| 219 | var table = new DataTable("Qualities");
|
---|
| 220 | table.Rows.Add(new DataRow("Loss (train)"));
|
---|
| 221 | table.Rows.Add(new DataRow("Loss (test)"));
|
---|
| 222 | Results.Add(new Result("Qualities", table));
|
---|
| 223 | var curLoss = new DoubleValue();
|
---|
| 224 | var curTestLoss = new DoubleValue();
|
---|
| 225 | Results.Add(new Result("Loss (train)", curLoss));
|
---|
| 226 | Results.Add(new Result("Loss (test)", curTestLoss));
|
---|
| 227 | var runCollection = new RunCollection();
|
---|
| 228 | Results.Add(new Result("Runs", runCollection));
|
---|
| 229 |
|
---|
| 230 | // init
|
---|
| 231 | var problemData = Problem.ProblemData;
|
---|
| 232 | var targetVarName = Problem.ProblemData.TargetVariable;
|
---|
[13707] | 233 | var activeVariables = problemData.AllowedInputVariables.Concat(new string[] { problemData.TargetVariable });
|
---|
[13646] | 234 | var modifiableDataset = new ModifiableDataset(
|
---|
[13707] | 235 | activeVariables,
|
---|
| 236 | activeVariables.Select(v => problemData.Dataset.GetDoubleValues(v).ToList()));
|
---|
[13646] | 237 |
|
---|
| 238 | var trainingRows = problemData.TrainingIndices;
|
---|
| 239 | var testRows = problemData.TestIndices;
|
---|
| 240 | var yPred = new double[trainingRows.Count()];
|
---|
| 241 | var yPredTest = new double[testRows.Count()];
|
---|
| 242 | var y = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
|
---|
| 243 | var curY = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TrainingIndices).ToArray();
|
---|
| 244 |
|
---|
| 245 | var yTest = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices).ToArray();
|
---|
| 246 | var curYTest = problemData.Dataset.GetDoubleValues(problemData.TargetVariable, problemData.TestIndices).ToArray();
|
---|
| 247 | var nu = Nu;
|
---|
| 248 | var mVars = (int)Math.Ceiling(M * problemData.AllowedInputVariables.Count());
|
---|
| 249 | var rRows = (int)Math.Ceiling(R * problemData.TrainingIndices.Count());
|
---|
| 250 | var alg = RegressionAlgorithm;
|
---|
| 251 | List<IRegressionModel> models = new List<IRegressionModel>();
|
---|
| 252 | try {
|
---|
| 253 |
|
---|
| 254 | // Loop until iteration limit reached or canceled.
|
---|
| 255 | for (int i = 0; i < Iterations; i++) {
|
---|
| 256 | cancellationToken.ThrowIfCancellationRequested();
|
---|
| 257 |
|
---|
| 258 | modifiableDataset.RemoveVariable(targetVarName);
|
---|
| 259 | modifiableDataset.AddVariable(targetVarName, curY.Concat(curYTest));
|
---|
| 260 |
|
---|
| 261 | SampleTrainingData(rand, modifiableDataset, rRows, problemData.Dataset, curY, problemData.TargetVariable, problemData.TrainingIndices); // all training indices from the original problem data are allowed
|
---|
| 262 | var modifiableProblemData = new RegressionProblemData(modifiableDataset,
|
---|
| 263 | problemData.AllowedInputVariables.SampleRandomWithoutRepetition(rand, mVars),
|
---|
| 264 | problemData.TargetVariable);
|
---|
| 265 | modifiableProblemData.TrainingPartition.Start = 0;
|
---|
| 266 | modifiableProblemData.TrainingPartition.End = rRows;
|
---|
| 267 | modifiableProblemData.TestPartition.Start = problemData.TestPartition.Start;
|
---|
| 268 | modifiableProblemData.TestPartition.End = problemData.TestPartition.End;
|
---|
| 269 |
|
---|
| 270 | if (!TrySetProblemData(alg, modifiableProblemData))
|
---|
| 271 | throw new NotSupportedException("The algorithm cannot be used with GBM.");
|
---|
| 272 |
|
---|
| 273 | IRegressionModel model;
|
---|
| 274 | IRun run;
|
---|
| 275 | // try to find a model. The algorithm might fail to produce a model. In this case we just retry until the iterations are exhausted
|
---|
| 276 | if (TryExecute(alg, RegressionAlgorithmResult, out model, out run)) {
|
---|
| 277 | int row = 0;
|
---|
| 278 | // update predictions for training and test
|
---|
| 279 | // update new targets (in the case of squared error loss we simply use negative residuals)
|
---|
| 280 | foreach (var pred in model.GetEstimatedValues(problemData.Dataset, trainingRows)) {
|
---|
| 281 | yPred[row] = yPred[row] + nu * pred;
|
---|
| 282 | curY[row] = y[row] - yPred[row];
|
---|
| 283 | row++;
|
---|
| 284 | }
|
---|
| 285 | row = 0;
|
---|
| 286 | foreach (var pred in model.GetEstimatedValues(problemData.Dataset, testRows)) {
|
---|
| 287 | yPredTest[row] = yPredTest[row] + nu * pred;
|
---|
| 288 | curYTest[row] = yTest[row] - yPredTest[row];
|
---|
| 289 | row++;
|
---|
| 290 | }
|
---|
| 291 | // determine quality
|
---|
| 292 | OnlineCalculatorError error;
|
---|
| 293 | var trainR = OnlinePearsonsRCalculator.Calculate(yPred, y, out error);
|
---|
| 294 | var testR = OnlinePearsonsRCalculator.Calculate(yPredTest, yTest, out error);
|
---|
| 295 |
|
---|
| 296 | // iteration results
|
---|
| 297 | curLoss.Value = error == OnlineCalculatorError.None ? trainR * trainR : 0.0;
|
---|
| 298 | curTestLoss.Value = error == OnlineCalculatorError.None ? testR * testR : 0.0;
|
---|
| 299 |
|
---|
| 300 | models.Add(model);
|
---|
| 301 |
|
---|
| 302 |
|
---|
| 303 | }
|
---|
| 304 |
|
---|
| 305 | runCollection.Add(run);
|
---|
| 306 | table.Rows["Loss (train)"].Values.Add(curLoss.Value);
|
---|
| 307 | table.Rows["Loss (test)"].Values.Add(curTestLoss.Value);
|
---|
| 308 | iterations.Value = i + 1;
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | // produce solution
|
---|
| 312 | if (CreateSolution) {
|
---|
| 313 | // when all our models are symbolic models we can easily combine them to a single model
|
---|
| 314 | if (models.All(m => m is ISymbolicRegressionModel)) {
|
---|
| 315 | Results.Add(new Result("Solution", CreateSymbolicSolution(models, Nu, (IRegressionProblemData)problemData.Clone())));
|
---|
| 316 | }
|
---|
| 317 | // just produce an ensemble solution for now (TODO: correct scaling or linear regression for ensemble model weights)
|
---|
[13699] | 318 |
|
---|
[13724] | 319 | var ensembleModel = new RegressionEnsembleModel(models) { AverageModelEstimates = false };
|
---|
| 320 | var ensembleSolution = ensembleModel.CreateRegressionSolution((IRegressionProblemData)problemData.Clone());
|
---|
[13699] | 321 | Results.Add(new Result("EnsembleSolution", ensembleSolution));
|
---|
[13646] | 322 | }
|
---|
[13699] | 323 | }
|
---|
| 324 | finally {
|
---|
[13646] | 325 | // reset everything
|
---|
| 326 | alg.Prepare(true);
|
---|
| 327 | }
|
---|
| 328 | }
|
---|
| 329 |
|
---|
[13653] | 330 |
|
---|
| 331 | private IAlgorithm CreateOSGP() {
|
---|
| 332 | // configure strict osgp
|
---|
| 333 | var alg = new OffspringSelectionGeneticAlgorithm.OffspringSelectionGeneticAlgorithm();
|
---|
| 334 | var prob = new SymbolicRegressionSingleObjectiveProblem();
|
---|
| 335 | prob.MaximumSymbolicExpressionTreeDepth.Value = 7;
|
---|
| 336 | prob.MaximumSymbolicExpressionTreeLength.Value = 15;
|
---|
| 337 | alg.Problem = prob;
|
---|
| 338 | alg.SuccessRatio.Value = 1.0;
|
---|
| 339 | alg.ComparisonFactorLowerBound.Value = 1.0;
|
---|
| 340 | alg.ComparisonFactorUpperBound.Value = 1.0;
|
---|
| 341 | alg.MutationProbability.Value = 0.15;
|
---|
| 342 | alg.PopulationSize.Value = 200;
|
---|
| 343 | alg.MaximumSelectionPressure.Value = 100;
|
---|
| 344 | alg.MaximumEvaluatedSolutions.Value = 20000;
|
---|
| 345 | alg.SelectorParameter.Value = alg.SelectorParameter.ValidValues.OfType<GenderSpecificSelector>().First();
|
---|
| 346 | alg.MutatorParameter.Value = alg.MutatorParameter.ValidValues.OfType<MultiSymbolicExpressionTreeManipulator>().First();
|
---|
| 347 | alg.StoreAlgorithmInEachRun = false;
|
---|
| 348 | return alg;
|
---|
| 349 | }
|
---|
| 350 |
|
---|
[13646] | 351 | private void SampleTrainingData(MersenneTwister rand, ModifiableDataset ds, int rRows,
|
---|
| 352 | IDataset sourceDs, double[] curTarget, string targetVarName, IEnumerable<int> trainingIndices) {
|
---|
| 353 | var selectedRows = trainingIndices.SampleRandomWithoutRepetition(rand, rRows).ToArray();
|
---|
| 354 | int t = 0;
|
---|
| 355 | object[] srcRow = new object[ds.Columns];
|
---|
| 356 | var varNames = ds.DoubleVariables.ToArray();
|
---|
| 357 | foreach (var r in selectedRows) {
|
---|
| 358 | // take all values from the original dataset
|
---|
| 359 | for (int c = 0; c < srcRow.Length; c++) {
|
---|
| 360 | var col = sourceDs.GetReadOnlyDoubleValues(varNames[c]);
|
---|
| 361 | srcRow[c] = col[r];
|
---|
| 362 | }
|
---|
| 363 | ds.ReplaceRow(t, srcRow);
|
---|
| 364 | // but use the updated target values
|
---|
| 365 | ds.SetVariableValue(curTarget[r], targetVarName, t);
|
---|
| 366 | t++;
|
---|
| 367 | }
|
---|
| 368 | }
|
---|
| 369 |
|
---|
| 370 | private static ISymbolicRegressionSolution CreateSymbolicSolution(List<IRegressionModel> models, double nu, IRegressionProblemData problemData) {
|
---|
| 371 | var symbModels = models.OfType<ISymbolicRegressionModel>();
|
---|
| 372 | var lowerLimit = symbModels.Min(m => m.LowerEstimationLimit);
|
---|
| 373 | var upperLimit = symbModels.Max(m => m.UpperEstimationLimit);
|
---|
| 374 | var interpreter = new SymbolicDataAnalysisExpressionTreeLinearInterpreter();
|
---|
| 375 | var progRootNode = new ProgramRootSymbol().CreateTreeNode();
|
---|
| 376 | var startNode = new StartSymbol().CreateTreeNode();
|
---|
| 377 |
|
---|
| 378 | var addNode = new Addition().CreateTreeNode();
|
---|
| 379 | var mulNode = new Multiplication().CreateTreeNode();
|
---|
| 380 | var scaleNode = (ConstantTreeNode)new Constant().CreateTreeNode(); // all models are scaled using the same nu
|
---|
| 381 | scaleNode.Value = nu;
|
---|
| 382 |
|
---|
| 383 | foreach (var m in symbModels) {
|
---|
| 384 | var relevantPart = m.SymbolicExpressionTree.Root.GetSubtree(0).GetSubtree(0); // skip root and start
|
---|
| 385 | addNode.AddSubtree((ISymbolicExpressionTreeNode)relevantPart.Clone());
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | mulNode.AddSubtree(addNode);
|
---|
| 389 | mulNode.AddSubtree(scaleNode);
|
---|
| 390 | startNode.AddSubtree(mulNode);
|
---|
| 391 | progRootNode.AddSubtree(startNode);
|
---|
| 392 | var t = new SymbolicExpressionTree(progRootNode);
|
---|
| 393 | var combinedModel = new SymbolicRegressionModel(t, interpreter, lowerLimit, upperLimit);
|
---|
| 394 | var sol = new SymbolicRegressionSolution(combinedModel, problemData);
|
---|
| 395 | return sol;
|
---|
| 396 | }
|
---|
| 397 |
|
---|
| 398 | private static bool TrySetProblemData(IAlgorithm alg, IRegressionProblemData problemData) {
|
---|
| 399 | var prob = alg.Problem as IRegressionProblem;
|
---|
| 400 | // there is already a problem and it is compatible -> just set problem data
|
---|
| 401 | if (prob != null) {
|
---|
| 402 | prob.ProblemDataParameter.Value = problemData;
|
---|
| 403 | return true;
|
---|
[13653] | 404 | } else return false;
|
---|
[13646] | 405 | }
|
---|
| 406 |
|
---|
| 407 | private static bool TryExecute(IAlgorithm alg, string regressionAlgorithmResultName, out IRegressionModel model, out IRun run) {
|
---|
| 408 | model = null;
|
---|
| 409 | using (var wh = new AutoResetEvent(false)) {
|
---|
| 410 | EventHandler<EventArgs<Exception>> handler = (sender, args) => wh.Set();
|
---|
| 411 | EventHandler handler2 = (sender, args) => wh.Set();
|
---|
| 412 | alg.ExceptionOccurred += handler;
|
---|
| 413 | alg.Stopped += handler2;
|
---|
| 414 | try {
|
---|
| 415 | alg.Prepare();
|
---|
| 416 | alg.Start();
|
---|
| 417 | wh.WaitOne();
|
---|
| 418 |
|
---|
| 419 | run = alg.Runs.Last();
|
---|
| 420 | var sols = alg.Results.Select(r => r.Value).OfType<IRegressionSolution>();
|
---|
| 421 | if (!sols.Any()) return false;
|
---|
| 422 | var sol = sols.First();
|
---|
| 423 | if (sols.Skip(1).Any()) {
|
---|
| 424 | // more than one solution => use regressionAlgorithmResult
|
---|
| 425 | if (alg.Results.ContainsKey(regressionAlgorithmResultName)) {
|
---|
| 426 | sol = (IRegressionSolution)alg.Results[regressionAlgorithmResultName].Value;
|
---|
| 427 | }
|
---|
| 428 | }
|
---|
| 429 | var symbRegSol = sol as SymbolicRegressionSolution;
|
---|
| 430 | // only accept symb reg solutions that do not hit the estimation limits
|
---|
| 431 | // NaN evaluations would not be critical but are problematic if we want to combine all symbolic models into a single symbolic model
|
---|
| 432 | if (symbRegSol == null ||
|
---|
| 433 | (symbRegSol.TrainingLowerEstimationLimitHits == 0 && symbRegSol.TrainingUpperEstimationLimitHits == 0 &&
|
---|
| 434 | symbRegSol.TestLowerEstimationLimitHits == 0 && symbRegSol.TestUpperEstimationLimitHits == 0) &&
|
---|
| 435 | symbRegSol.TrainingNaNEvaluations == 0 && symbRegSol.TestNaNEvaluations == 0) {
|
---|
| 436 | model = sol.Model;
|
---|
| 437 | }
|
---|
[13699] | 438 | }
|
---|
| 439 | finally {
|
---|
[13646] | 440 | alg.ExceptionOccurred -= handler;
|
---|
| 441 | alg.Stopped -= handler2;
|
---|
| 442 | }
|
---|
| 443 | }
|
---|
| 444 | return model != null;
|
---|
| 445 | }
|
---|
| 446 | }
|
---|
| 447 | }
|
---|