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

Last change on this file since 13705 was 13705, checked in by mkommend, 6 years ago

#2590: Added view for ensemble weights.

File size: 8.0 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                                        let weight = GetModelWeight(model)
158                                        select model.GetEstimatedValues(dataset, rows).Select(e => weight * e)
159                                        .GetEnumerator()).ToList();
160
161      while (estimatedValuesEnumerators.All(en => en.MoveNext())) {
162        yield return from enumerator in estimatedValuesEnumerators
163                     select enumerator.Current;
164      }
165    }
166
167    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows, Func<int, IRegressionModel, bool> modelSelectionPredicate) {
168      var estimatedValuesEnumerators = GetEstimatedValueVectors(dataset, rows).GetEnumerator();
169      var rowsEnumerator = rows.GetEnumerator();
170
171      // aggregate to make sure that MoveNext is called for all enumerators
172      while (rowsEnumerator.MoveNext() & estimatedValuesEnumerators.MoveNext()) {
173        int currentRow = rowsEnumerator.Current;
174
175        var filteredEstimates = models.Zip(estimatedValuesEnumerators.Current, (m, e) => new { Model = m, EstimatedValue = e })
176                                      .Where(f => modelSelectionPredicate(currentRow, f.Model))
177                                      .Select(f => f.EstimatedValue).DefaultIfEmpty(double.NaN);
178
179        yield return AggregateEstimatedValues(filteredEstimates);
180      }
181    }
182
183    private double AggregateEstimatedValues(IEnumerable<double> estimatedValuesVector) {
184      if (AverageModelEstimates)
185        return estimatedValuesVector.Average();
186      else
187        return estimatedValuesVector.Sum();
188    }
189
190    public event EventHandler Changed;
191    private void OnChanged() {
192      var handler = Changed;
193      if (handler != null)
194        handler(this, EventArgs.Empty);
195    }
196    #endregion
197
198    #region IRegressionModel Members
199    public IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
200      foreach (var estimatedValuesVector in GetEstimatedValueVectors(dataset, rows)) {
201        yield return AggregateEstimatedValues(estimatedValuesVector.DefaultIfEmpty(double.NaN));
202      }
203    }
204
205    public RegressionEnsembleSolution CreateRegressionSolution(IRegressionProblemData problemData) {
206      return new RegressionEnsembleSolution(this, new RegressionEnsembleProblemData(problemData));
207    }
208    IRegressionSolution IRegressionModel.CreateRegressionSolution(IRegressionProblemData problemData) {
209      return CreateRegressionSolution(problemData);
210    }
211    #endregion
212  }
213}
Note: See TracBrowser for help on using the repository browser.