[6241] | 1 | #region License Information
|
---|
| 2 | /* HeuristicLab
|
---|
[15584] | 3 | * Copyright (C) 2002-2018 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
|
---|
[6241] | 4 | *
|
---|
| 5 | * This file is part of HeuristicLab.
|
---|
| 6 | *
|
---|
| 7 | * HeuristicLab is free software: you can redistribute it and/or modify
|
---|
| 8 | * it under the terms of the GNU General Public License as published by
|
---|
| 9 | * the Free Software Foundation, either version 3 of the License, or
|
---|
| 10 | * (at your option) any later version.
|
---|
| 11 | *
|
---|
| 12 | * HeuristicLab is distributed in the hope that it will be useful,
|
---|
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 15 | * GNU General Public License for more details.
|
---|
| 16 | *
|
---|
| 17 | * You should have received a copy of the GNU General Public License
|
---|
| 18 | * along with HeuristicLab. If not, see <http://www.gnu.org/licenses/>.
|
---|
| 19 | */
|
---|
| 20 | #endregion
|
---|
| 21 |
|
---|
[15061] | 22 | using System.Threading;
|
---|
[6241] | 23 | using HeuristicLab.Common;
|
---|
| 24 | using HeuristicLab.Core;
|
---|
| 25 | using HeuristicLab.Data;
|
---|
| 26 | using HeuristicLab.Optimization;
|
---|
[8786] | 27 | using HeuristicLab.Parameters;
|
---|
[6241] | 28 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
| 29 | using HeuristicLab.Problems.DataAnalysis;
|
---|
| 30 |
|
---|
| 31 | namespace HeuristicLab.Algorithms.DataAnalysis {
|
---|
| 32 | /// <summary>
|
---|
| 33 | /// Random forest classification data analysis algorithm.
|
---|
| 34 | /// </summary>
|
---|
[13297] | 35 | [Item("Random Forest Classification (RF)", "Random forest classification data analysis algorithm (wrapper for ALGLIB).")]
|
---|
[12708] | 36 | [Creatable(CreatableAttribute.Categories.DataAnalysisClassification, Priority = 120)]
|
---|
[6241] | 37 | [StorableClass]
|
---|
| 38 | public sealed class RandomForestClassification : FixedDataAnalysisAlgorithm<IClassificationProblem> {
|
---|
| 39 | private const string RandomForestClassificationModelResultName = "Random forest classification solution";
|
---|
| 40 | private const string NumberOfTreesParameterName = "Number of trees";
|
---|
| 41 | private const string RParameterName = "R";
|
---|
[8786] | 42 | private const string MParameterName = "M";
|
---|
| 43 | private const string SeedParameterName = "Seed";
|
---|
| 44 | private const string SetSeedRandomlyParameterName = "SetSeedRandomly";
|
---|
[13283] | 45 | private const string CreateSolutionParameterName = "CreateSolution";
|
---|
[8786] | 46 |
|
---|
[6241] | 47 | #region parameter properties
|
---|
[8786] | 48 | public IFixedValueParameter<IntValue> NumberOfTreesParameter {
|
---|
| 49 | get { return (IFixedValueParameter<IntValue>)Parameters[NumberOfTreesParameterName]; }
|
---|
[6241] | 50 | }
|
---|
[8786] | 51 | public IFixedValueParameter<DoubleValue> RParameter {
|
---|
| 52 | get { return (IFixedValueParameter<DoubleValue>)Parameters[RParameterName]; }
|
---|
[6241] | 53 | }
|
---|
[8786] | 54 | public IFixedValueParameter<DoubleValue> MParameter {
|
---|
| 55 | get { return (IFixedValueParameter<DoubleValue>)Parameters[MParameterName]; }
|
---|
| 56 | }
|
---|
| 57 | public IFixedValueParameter<IntValue> SeedParameter {
|
---|
| 58 | get { return (IFixedValueParameter<IntValue>)Parameters[SeedParameterName]; }
|
---|
| 59 | }
|
---|
| 60 | public IFixedValueParameter<BoolValue> SetSeedRandomlyParameter {
|
---|
| 61 | get { return (IFixedValueParameter<BoolValue>)Parameters[SetSeedRandomlyParameterName]; }
|
---|
| 62 | }
|
---|
[13283] | 63 | public IFixedValueParameter<BoolValue> CreateSolutionParameter {
|
---|
| 64 | get { return (IFixedValueParameter<BoolValue>)Parameters[CreateSolutionParameterName]; }
|
---|
| 65 | }
|
---|
[6241] | 66 | #endregion
|
---|
| 67 | #region properties
|
---|
| 68 | public int NumberOfTrees {
|
---|
| 69 | get { return NumberOfTreesParameter.Value.Value; }
|
---|
| 70 | set { NumberOfTreesParameter.Value.Value = value; }
|
---|
| 71 | }
|
---|
| 72 | public double R {
|
---|
| 73 | get { return RParameter.Value.Value; }
|
---|
| 74 | set { RParameter.Value.Value = value; }
|
---|
| 75 | }
|
---|
[8786] | 76 | public double M {
|
---|
| 77 | get { return MParameter.Value.Value; }
|
---|
| 78 | set { MParameter.Value.Value = value; }
|
---|
| 79 | }
|
---|
| 80 | public int Seed {
|
---|
| 81 | get { return SeedParameter.Value.Value; }
|
---|
| 82 | set { SeedParameter.Value.Value = value; }
|
---|
| 83 | }
|
---|
| 84 | public bool SetSeedRandomly {
|
---|
| 85 | get { return SetSeedRandomlyParameter.Value.Value; }
|
---|
| 86 | set { SetSeedRandomlyParameter.Value.Value = value; }
|
---|
| 87 | }
|
---|
[13283] | 88 | public bool CreateSolution {
|
---|
| 89 | get { return CreateSolutionParameter.Value.Value; }
|
---|
| 90 | set { CreateSolutionParameter.Value.Value = value; }
|
---|
| 91 | }
|
---|
[6241] | 92 | #endregion
|
---|
[8786] | 93 |
|
---|
[6241] | 94 | [StorableConstructor]
|
---|
| 95 | private RandomForestClassification(bool deserializing) : base(deserializing) { }
|
---|
| 96 | private RandomForestClassification(RandomForestClassification original, Cloner cloner)
|
---|
| 97 | : base(original, cloner) {
|
---|
| 98 | }
|
---|
[8786] | 99 |
|
---|
[6241] | 100 | public RandomForestClassification()
|
---|
| 101 | : base() {
|
---|
| 102 | Parameters.Add(new FixedValueParameter<IntValue>(NumberOfTreesParameterName, "The number of trees in the forest. Should be between 50 and 100", new IntValue(50)));
|
---|
| 103 | Parameters.Add(new FixedValueParameter<DoubleValue>(RParameterName, "The ratio of the training set that will be used in the construction of individual trees (0<r<=1). Should be adjusted depending on the noise level in the dataset in the range from 0.66 (low noise) to 0.05 (high noise). This parameter should be adjusted to achieve good generalization error.", new DoubleValue(0.3)));
|
---|
[8786] | 104 | Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
|
---|
| 105 | Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
|
---|
| 106 | Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
|
---|
[13283] | 107 | Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
|
---|
| 108 | Parameters[CreateSolutionParameterName].Hidden = true;
|
---|
| 109 |
|
---|
[6241] | 110 | Problem = new ClassificationProblem();
|
---|
| 111 | }
|
---|
[8786] | 112 |
|
---|
[6241] | 113 | [StorableHook(HookType.AfterDeserialization)]
|
---|
[8786] | 114 | private void AfterDeserialization() {
|
---|
[13283] | 115 | // BackwardsCompatibility3.3
|
---|
| 116 | #region Backwards compatible code, remove with 3.4
|
---|
[8786] | 117 | if (!Parameters.ContainsKey(MParameterName))
|
---|
| 118 | Parameters.Add(new FixedValueParameter<DoubleValue>(MParameterName, "The ratio of features that will be used in the construction of individual trees (0<m<=1)", new DoubleValue(0.5)));
|
---|
| 119 | if (!Parameters.ContainsKey(SeedParameterName))
|
---|
| 120 | Parameters.Add(new FixedValueParameter<IntValue>(SeedParameterName, "The random seed used to initialize the new pseudo random number generator.", new IntValue(0)));
|
---|
| 121 | if (!Parameters.ContainsKey((SetSeedRandomlyParameterName)))
|
---|
| 122 | Parameters.Add(new FixedValueParameter<BoolValue>(SetSeedRandomlyParameterName, "True if the random seed should be set to a random value, otherwise false.", new BoolValue(true)));
|
---|
[13283] | 123 | if (!Parameters.ContainsKey(CreateSolutionParameterName)) {
|
---|
| 124 | Parameters.Add(new FixedValueParameter<BoolValue>(CreateSolutionParameterName, "Flag that indicates if a solution should be produced at the end of the run", new BoolValue(true)));
|
---|
| 125 | Parameters[CreateSolutionParameterName].Hidden = true;
|
---|
| 126 | }
|
---|
| 127 | #endregion
|
---|
[8786] | 128 | }
|
---|
[6241] | 129 |
|
---|
| 130 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
| 131 | return new RandomForestClassification(this, cloner);
|
---|
| 132 | }
|
---|
| 133 |
|
---|
| 134 | #region random forest
|
---|
[15061] | 135 | protected override void Run(CancellationToken cancellationToken) {
|
---|
[6241] | 136 | double rmsError, relClassificationError, outOfBagRmsError, outOfBagRelClassificationError;
|
---|
[16835] | 137 | if (SetSeedRandomly) Seed = Random.RandomSeedGenerator.GetSeed();
|
---|
[8786] | 138 |
|
---|
[13283] | 139 | var model = CreateRandomForestClassificationModel(Problem.ProblemData, NumberOfTrees, R, M, Seed, out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
|
---|
[6241] | 140 | Results.Add(new Result("Root mean square error", "The root of the mean of squared errors of the random forest regression solution on the training set.", new DoubleValue(rmsError)));
|
---|
| 141 | Results.Add(new Result("Relative classification error", "Relative classification error of the random forest regression solution on the training set.", new PercentValue(relClassificationError)));
|
---|
| 142 | Results.Add(new Result("Root mean square error (out-of-bag)", "The out-of-bag root of the mean of squared errors of the random forest regression solution.", new DoubleValue(outOfBagRmsError)));
|
---|
| 143 | Results.Add(new Result("Relative classification error (out-of-bag)", "The out-of-bag relative classification error of the random forest regression solution.", new PercentValue(outOfBagRelClassificationError)));
|
---|
[13283] | 144 |
|
---|
| 145 | if (CreateSolution) {
|
---|
[14027] | 146 | var solution = new RandomForestClassificationSolution(model, (IClassificationProblemData)Problem.ProblemData.Clone());
|
---|
[13283] | 147 | Results.Add(new Result(RandomForestClassificationModelResultName, "The random forest classification solution.", solution));
|
---|
| 148 | }
|
---|
[6241] | 149 | }
|
---|
[14027] | 150 |
|
---|
[13283] | 151 | // keep for compatibility with old API
|
---|
| 152 | public static RandomForestClassificationSolution CreateRandomForestClassificationSolution(IClassificationProblemData problemData, int nTrees, double r, double m, int seed,
|
---|
[6241] | 153 | out double rmsError, out double relClassificationError, out double outOfBagRmsError, out double outOfBagRelClassificationError) {
|
---|
[15474] | 154 | var model = CreateRandomForestClassificationModel(problemData, nTrees, r, m, seed,
|
---|
| 155 | out rmsError, out relClassificationError, out outOfBagRmsError, out outOfBagRelClassificationError);
|
---|
[14027] | 156 | return new RandomForestClassificationSolution(model, (IClassificationProblemData)problemData.Clone());
|
---|
[6241] | 157 | }
|
---|
[13283] | 158 |
|
---|
| 159 | public static RandomForestModel CreateRandomForestClassificationModel(IClassificationProblemData problemData, int nTrees, double r, double m, int seed,
|
---|
| 160 | out double rmsError, out double relClassificationError, out double outOfBagRmsError, out double outOfBagRelClassificationError) {
|
---|
[15474] | 161 | return RandomForestModel.CreateClassificationModel(problemData, nTrees, r, m, seed,
|
---|
| 162 | rmsError: out rmsError, relClassificationError: out relClassificationError, outOfBagRmsError: out outOfBagRmsError, outOfBagRelClassificationError: out outOfBagRelClassificationError);
|
---|
[13283] | 163 | }
|
---|
[6241] | 164 | #endregion
|
---|
| 165 | }
|
---|
| 166 | }
|
---|