1 | // #region License Information
|
---|
2 | // /* HeuristicLab
|
---|
3 | // * Copyright (C) 2002-2018 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 |
|
---|
22 | using System;
|
---|
23 | using System.Collections.Generic;
|
---|
24 | using System.Linq;
|
---|
25 | using HeuristicLab.Common;
|
---|
26 | using HeuristicLab.Core;
|
---|
27 | using HeuristicLab.Data;
|
---|
28 | using HeuristicLab.Parameters;
|
---|
29 | using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
|
---|
30 |
|
---|
31 | namespace HeuristicLab.Problems.DataAnalysis {
|
---|
32 | [Item("Rescale", "Rescale the data to a given range (e.g. [0-1]).")]
|
---|
33 | [StorableClass]
|
---|
34 | public class RescaleTransformation : Transformation<double> {
|
---|
35 |
|
---|
36 | #region Parameters
|
---|
37 | private IFixedValueParameter<DoubleRange> TargetRangeParameter {
|
---|
38 | get { return (IFixedValueParameter<DoubleRange>)Parameters["Target Range"]; }
|
---|
39 | }
|
---|
40 | private IFixedValueParameter<DoubleRange> OriginalRangeParameter {
|
---|
41 | get { return (IFixedValueParameter<DoubleRange>)Parameters["Original Range"]; }
|
---|
42 | }
|
---|
43 | #endregion
|
---|
44 |
|
---|
45 | #region Properties
|
---|
46 | public double TargetMin {
|
---|
47 | get { return TargetRangeParameter.Value.Start; }
|
---|
48 | set { TargetRangeParameter.Value.Start = value; }
|
---|
49 | }
|
---|
50 | public double TargetMax {
|
---|
51 | get { return TargetRangeParameter.Value.End; }
|
---|
52 | set { TargetRangeParameter.Value.End = value; }
|
---|
53 | }
|
---|
54 | public double OriginalMin {
|
---|
55 | get { return OriginalRangeParameter.Value.Start; }
|
---|
56 | private set { OriginalRangeParameter.Value.Start = value; }
|
---|
57 | }
|
---|
58 | public double OriginalMax {
|
---|
59 | get { return OriginalRangeParameter.Value.End; }
|
---|
60 | private set { OriginalRangeParameter.Value.End = value; }
|
---|
61 | }
|
---|
62 | #endregion
|
---|
63 |
|
---|
64 | #region Constructor, Cloning & Persistence
|
---|
65 | public RescaleTransformation()
|
---|
66 | : base() {
|
---|
67 | Parameters.Add(new FixedValueParameter<DoubleRange>("Target Range", new DoubleRange(0.0, 1.0)));
|
---|
68 | Parameters.Add(new FixedValueParameter<DoubleRange>("Original Range", new DoubleRange(double.NaN, double.NaN)) { Hidden = true });
|
---|
69 | }
|
---|
70 |
|
---|
71 | protected RescaleTransformation(RescaleTransformation original, Cloner cloner)
|
---|
72 | : base(original, cloner) {
|
---|
73 | }
|
---|
74 | public override IDeepCloneable Clone(Cloner cloner) {
|
---|
75 | return new RescaleTransformation(this, cloner);
|
---|
76 | }
|
---|
77 |
|
---|
78 | [StorableConstructor]
|
---|
79 | protected RescaleTransformation(bool deserializing)
|
---|
80 | : base(deserializing) {
|
---|
81 | }
|
---|
82 | #endregion
|
---|
83 |
|
---|
84 | public override bool Check(IEnumerable<double> data, out string errorMessage) {
|
---|
85 | if (data.StandardDeviationPop().IsAlmost(0.0)) {
|
---|
86 | errorMessage = "Rescaling cannot be applied for data with a standard deviation of zero.";
|
---|
87 | return false;
|
---|
88 | }
|
---|
89 | return base.Check(data, out errorMessage);
|
---|
90 | }
|
---|
91 |
|
---|
92 | public override void Configure(IEnumerable<double> data) {
|
---|
93 | Configure(data, out double originalMin, out double originalMax);
|
---|
94 | OriginalMin = originalMin;
|
---|
95 | OriginalMax = originalMax;
|
---|
96 | base.Configure(data);
|
---|
97 | }
|
---|
98 |
|
---|
99 | public override IEnumerable<double> Apply(IEnumerable<double> data) {
|
---|
100 | if (double.IsNaN(OriginalMin) || double.IsNaN(OriginalMax))
|
---|
101 | throw new InvalidOperationException("Transformation is not configured");
|
---|
102 |
|
---|
103 | return Apply(data, TargetMin, TargetMax, OriginalMin, OriginalMax);
|
---|
104 | }
|
---|
105 |
|
---|
106 | public override IEnumerable<double> InverseApply(IEnumerable<double> data) {
|
---|
107 | if (double.IsNaN(OriginalMin) || double.IsNaN(OriginalMax))
|
---|
108 | throw new InvalidOperationException("Transformation is not configured");
|
---|
109 |
|
---|
110 | return InverseApply(data, TargetMin, TargetMax, OriginalMin, OriginalMax);
|
---|
111 | }
|
---|
112 |
|
---|
113 |
|
---|
114 | public static void Configure(IEnumerable<double> data, out double originalMin, out double originalMax) {
|
---|
115 | originalMin = data.Min();
|
---|
116 | originalMax = data.Max();
|
---|
117 | }
|
---|
118 |
|
---|
119 | public static IEnumerable<double> Apply(IEnumerable<double> data, double targetMin, double targetMax, double originalMin = double.NaN, double originalMax = double.NaN) {
|
---|
120 | if (double.IsNaN(originalMin)) originalMin = data.Min();
|
---|
121 | if (double.IsNaN(originalMax)) originalMax = data.Max();
|
---|
122 |
|
---|
123 | GetLinearTransformationParameters(targetMin, targetMax, originalMin, originalMax, out double scale, out double offset);
|
---|
124 |
|
---|
125 | return LinearTransformation.Apply(data, scale, offset);
|
---|
126 | }
|
---|
127 |
|
---|
128 | public static IEnumerable<double> InverseApply(IEnumerable<double> data, double targetMin, double targetMax, double originalMin, double originalMax) {
|
---|
129 | GetLinearTransformationParameters(targetMin, targetMax, originalMin, originalMax, out double scale, out double offset);
|
---|
130 |
|
---|
131 | return LinearTransformation.InverseApply(data, scale, offset);
|
---|
132 | }
|
---|
133 |
|
---|
134 | private static void GetLinearTransformationParameters(double targetMin, double targetMax, double originalMin, double originalMax,
|
---|
135 | out double scale, out double offset) {
|
---|
136 | var originalRange = originalMax - originalMin;
|
---|
137 | var targetRange = targetMax - targetMin;
|
---|
138 |
|
---|
139 | scale = targetRange / originalRange;
|
---|
140 | offset = targetMin - originalMin * scale;
|
---|
141 | }
|
---|
142 | }
|
---|
143 | } |
---|