Free cookie consent management tool by TermsFeed Policy Generator

source: trunk/sources/HeuristicLab.Problems.DataAnalysis/3.4/Implementation/Regression/RegressionEnsembleModel.cs @ 13704

Last change on this file since 13704 was 13704, checked in by mkommend, 8 years ago

#2590: Added model weights for ensembles.

File size: 7.9 KB
Line 
1#region License Information
2/* HeuristicLab
3 * Copyright (C) 2002-2015 Heuristic and Evolutionary Algorithms Laboratory (HEAL)
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
22using System;
23using System.Collections.Generic;
24using System.Linq;
25using HeuristicLab.Common;
26using HeuristicLab.Core;
27using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
28
29namespace HeuristicLab.Problems.DataAnalysis {
30  /// <summary>
31  /// Represents regression solutions that contain an ensemble of multiple regression models
32  /// </summary>
33  [StorableClass]
34  [Item("RegressionEnsembleModel", "A regression model that contains an ensemble of multiple regression models")]
35  public sealed class RegressionEnsembleModel : NamedItem, IRegressionEnsembleModel {
36
37    private List<IRegressionModel> models;
38    public IEnumerable<IRegressionModel> Models {
39      get { return new List<IRegressionModel>(models); }
40    }
41
42    [Storable(Name = "Models")]
43    private IEnumerable<IRegressionModel> StorableModels {
44      get { return models; }
45      set { models = value.ToList(); }
46    }
47
48    private List<double> modelWeights;
49    public IEnumerable<double> ModelWeights {
50      get { return modelWeights; }
51    }
52
53    [Storable(Name = "ModelWeights")]
54    private IEnumerable<double> StorableModelWeights {
55      get { return modelWeights; }
56      set { modelWeights = value.ToList(); }
57    }
58
59    [Storable]
60    private bool averageModelEstimates = true;
61    public bool AverageModelEstimates {
62      get { return averageModelEstimates; }
63      set {
64        if (averageModelEstimates != value) {
65          averageModelEstimates = value;
66          OnChanged();
67        }
68      }
69    }
70
71    #region backwards compatiblity 3.3.5
72    [Storable(Name = "models", AllowOneWay = true)]
73    private List<IRegressionModel> OldStorableModels {
74      set { models = value; }
75    }
76    #endregion
77
78    [StorableHook(HookType.AfterDeserialization)]
79    private void AfterDeserialization() {
80      // BackwardsCompatibility 3.3.14
81      #region Backwards compatible code, remove with 3.4
82      if (modelWeights == null || !modelWeights.Any())
83        modelWeights = new List<double>(models.Select(m => 1.0));
84      #endregion
85    }
86
87    [StorableConstructor]
88    private RegressionEnsembleModel(bool deserializing) : base(deserializing) { }
89    private RegressionEnsembleModel(RegressionEnsembleModel original, Cloner cloner)
90      : base(original, cloner) {
91      this.models = original.Models.Select(cloner.Clone).ToList();
92      this.modelWeights = new List<double>(original.ModelWeights);
93      this.averageModelEstimates = original.averageModelEstimates;
94    }
95    public override IDeepCloneable Clone(Cloner cloner) {
96      return new RegressionEnsembleModel(this, cloner);
97    }
98
99    public RegressionEnsembleModel() : this(Enumerable.Empty<IRegressionModel>()) { }
100    public RegressionEnsembleModel(IEnumerable<IRegressionModel> models) : this(models, models.Select(m => 1.0)) { }
101    public RegressionEnsembleModel(IEnumerable<IRegressionModel> models, IEnumerable<double> modelWeights)
102      : base() {
103      this.name = ItemName;
104      this.description = ItemDescription;
105
106
107      this.models = new List<IRegressionModel>(models);
108      this.modelWeights = new List<double>(modelWeights);
109    }
110
111    #region IRegressionEnsembleModel Members
112    public void Add(IRegressionModel model) {
113      Add(model, 1.0);
114    }
115    public void Add(IRegressionModel model, double weight) {
116      models.Add(model);
117      modelWeights.Add(weight);
118      OnChanged();
119    }
120
121    public void AddRange(IEnumerable<IRegressionModel> models) {
122      AddRange(models, models.Select(m => 1.0));
123    }
124    public void AddRange(IEnumerable<IRegressionModel> models, IEnumerable<double> weights) {
125      this.models.AddRange(models);
126      modelWeights.AddRange(weights);
127      OnChanged();
128    }
129
130    public void Remove(IRegressionModel model) {
131      var index = models.IndexOf(model);
132      models.RemoveAt(index);
133      modelWeights.RemoveAt(index);
134      OnChanged();
135    }
136    public void RemoveRange(IEnumerable<IRegressionModel> models) {
137      foreach (var model in models) {
138        var index = this.models.IndexOf(model);
139        this.models.RemoveAt(index);
140        modelWeights.RemoveAt(index);
141      }
142      OnChanged();
143    }
144
145    public double GetModelWeight(IRegressionModel model) {
146      var index = models.IndexOf(model);
147      return modelWeights[index];
148    }
149    public void SetModelWeight(IRegressionModel model, double weight) {
150      var index = models.IndexOf(model);
151      modelWeights[index] = weight;
152      OnChanged();
153    }
154
155    public IEnumerable<IEnumerable<double>> GetEstimatedValueVectors(IDataset dataset, IEnumerable<int> rows) {
156      var estimatedValuesEnumerators = (from model in models
157                                        select model.GetEstimatedValues(dataset, rows).GetEnumerator())
158                                       .ToList();
159
160      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
161        yield return from enumerator in estimatedValuesEnumerators
162                     select enumerator.Current;
163      }
164    }
165
166    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows, Func<int, IRegressionModel, bool> modelSelectionPredicate) {
167      var estimatedValuesEnumerators = GetEstimatedValueVectors(dataset, rows).GetEnumerator();
168      var rowsEnumerator = rows.GetEnumerator();
169
170      // aggregate to make sure that MoveNext is called for all enumerators
171      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.MoveNext()) {
172        int currentRow = rowsEnumerator.Current;
173
174        var filteredEstimates = models.Zip(estimatedValuesEnumerators.Current, (m, e) => new { Model = m, EstimatedValue = e })
175                                      .Where(f => modelSelectionPredicate(currentRow, f.Model))
176                                      .Select(f => f.EstimatedValue).DefaultIfEmpty(double.NaN);
177
178        yield return AggregateEstimatedValues(filteredEstimates);
179      }
180    }
181
182    private double AggregateEstimatedValues(IEnumerable<double> estimatedValuesVector) {
183      if (AverageModelEstimates)
184        return estimatedValuesVector.Average();
185      else
186        return estimatedValuesVector.Sum();
187    }
188
189    public event EventHandler Changed;
190    private void OnChanged() {
191      var handler = Changed;
192      if (handler != null)
193        handler(this, EventArgs.Empty);
194    }
195    #endregion
196
197    #region IRegressionModel Members
198    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
199      foreach (var estimatedValuesVector in GetEstimatedValueVectors(dataset, rows)) {
200        yield return AggregateEstimatedValues(estimatedValuesVector.DefaultIfEmpty(double.NaN));
201      }
202    }
203
204    public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
205      return new RegressionEnsembleSolution(this, new RegressionEnsembleProblemData(problemData));
206    }
207    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
208      return CreateRegressionSolution(problemData);
209    }
210    #endregion
211  }
212}
Note: See TracBrowser for help on using the repository browser.