Free cookie consent management tool by TermsFeed Policy Generator

source: branches/GBT-trunkintegration/HeuristicLab.Algorithms.DataAnalysis/3.4/GradientBoostedTrees/LossFunctions/RelativeErrorLoss.cs @ 12597

Last change on this file since 12597 was 12597, checked in by gkronber, 9 years ago

#2261: comments

File size: 4.9 KB
Line 
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
23using System;
24using System.Collections.Generic;
25using System.Diagnostics;
26using System.Linq;
27using HeuristicLab.Common;
28
29namespace HeuristicLab.Algorithms.DataAnalysis {
30  // relative error loss is a special case of weighted absolute error loss
31  // absolute loss is weighted by (1/target)
32  public class RelativeErrorLoss : ILossFunction {
33    public double GetLoss(IEnumerable<double> target, IEnumerable<double> pred, IEnumerable<double> weight) {
34      var targetEnum = target.GetEnumerator();
35      var predEnum = pred.GetEnumerator();
36      var weightEnum = weight.GetEnumerator();
37
38      double s = 0;
39      while (targetEnum.MoveNext() & predEnum.MoveNext() & weightEnum.MoveNext()) {
40        double res = targetEnum.Current - predEnum.Current;
41        s += weightEnum.Current * Math.Abs(res) * Math.Abs(1.0 / targetEnum.Current);
42      }
43      if (targetEnum.MoveNext() | predEnum.MoveNext() | weightEnum.MoveNext())
44        throw new ArgumentException("target, pred and weight have differing lengths");
45
46      return s;
47    }
48
49    public IEnumerable<double> GetLossGradient(IEnumerable<double> target, IEnumerable<double> pred, IEnumerable<double> weight) {
50      var targetEnum = target.GetEnumerator();
51      var predEnum = pred.GetEnumerator();
52      var weightEnum = weight.GetEnumerator();
53
54      while (targetEnum.MoveNext() & predEnum.MoveNext() & weightEnum.MoveNext()) {
55        // weight * sign(res) * abs(1 / target)
56        var res = targetEnum.Current - predEnum.Current;
57        if (res > 0) yield return weightEnum.Current * 1.0 / Math.Abs(targetEnum.Current);
58        else if (res < 0) yield return -weightEnum.Current * 1.0 / Math.Abs(targetEnum.Current);
59        else yield return 0.0;
60      }
61      if (targetEnum.MoveNext() | predEnum.MoveNext() | weightEnum.MoveNext())
62        throw new ArgumentException("target, pred and weight have differing lengths");
63    }
64
65    public LineSearchFunc GetLineSearchFunc(IEnumerable<double> target, IEnumerable<double> pred, IEnumerable<double> weight) {
66      var targetArr = target.ToArray();
67      var predArr = pred.ToArray();
68      var weightArr = weight.ToArray();
69      Debug.Assert(weightArr.All(w => w.IsAlmost(1.0)));
70
71      if (targetArr.Length != predArr.Length || predArr.Length != weightArr.Length)
72        throw new ArgumentException("target, pred and weight have differing lengths");
73
74      // line search for relative error
75      // weighted median (weight = 1/target)
76      LineSearchFunc lineSearch = (idx, startIdx, endIdx) => {
77        // weighted median calculation
78        int nRows = endIdx - startIdx + 1; // startIdx and endIdx are inclusive
79        if (nRows == 1) return targetArr[idx[startIdx]] - predArr[idx[startIdx]]; // res
80        else if (nRows == 2) {
81          // weighted average of two residuals
82          var w0 = weightArr[idx[startIdx]] * Math.Abs(1.0 / targetArr[idx[startIdx]]);
83          var w1 = weightArr[idx[endIdx]] * Math.Abs(1.0 / targetArr[idx[endIdx]]);
84          return (w0 * (targetArr[idx[startIdx]] - predArr[idx[startIdx]]) + w1 * (targetArr[idx[endIdx]] - predArr[idx[endIdx]])) / (w0 + w1);
85        } else {
86          var ts = from offset in Enumerable.Range(0, nRows)
87                   let i = startIdx + offset
88                   let row = idx[i]
89                   select new { res = targetArr[row] - predArr[row], weight = weightArr[row] * Math.Abs(1.0 / targetArr[row]) };
90          ts = ts.OrderBy(t => t.res);
91          var totalWeight = ts.Sum(t => t.weight);
92          var tsEnumerator = ts.GetEnumerator();
93          tsEnumerator.MoveNext();
94
95          double aggWeight = tsEnumerator.Current.weight; // weight of first
96
97          while (aggWeight < totalWeight / 2) {
98            tsEnumerator.MoveNext();
99            aggWeight += tsEnumerator.Current.weight;
100          }
101          return tsEnumerator.Current.res;
102        }
103      };
104      return lineSearch;
105    }
106
107    public override string ToString() {
108      return "Relative error loss";
109    }
110  }
111}
Note: See TracBrowser for help on using the repository browser.