Free cookie consent management tool by TermsFeed Policy Generator

Ignore:
Timestamp:
07/15/17 10:29:40 (7 years ago)
Author:
gkronber
Message:

#2699,#2700
merged r14862, r14863, r14911, r14936, r15156, r15157, r15158, r15164, r15169, r15207:15209, r15225, r15227, r15234, r15248 from trunk to stable

Location:
stable
Files:
12 edited
1 copied

Legend:

Unmodified
Added
Removed
  • stable

  • stable/HeuristicLab.Algorithms.DataAnalysis

  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/CicularKernel.cs

    r14892 r15249  
    2525using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2626
    27 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     27namespace HeuristicLab.Algorithms.DataAnalysis {
    2828  [StorableClass]
    2929  [Item("CircularKernel", "A circular kernel function 2*pi*(acos(-d)-d*(1-d²)^(0.5)) where n = ||x-c|| and d = n/beta \n  As described in http://crsouza.com/2010/03/17/kernel-functions-for-machine-learning-applications/")]
    3030  public class CircularKernel : KernelBase {
    31 
    32     #region HLConstructors & Boilerplate
    3331    [StorableConstructor]
    3432    protected CircularKernel(bool deserializing) : base(deserializing) { }
    35     [StorableHook(HookType.AfterDeserialization)]
    36     private void AfterDeserialization() { }
     33
    3734    protected CircularKernel(CircularKernel original, Cloner cloner) : base(original, cloner) { }
    38     public CircularKernel() {
    39     }
     35
     36    public CircularKernel() { }
     37
    4038    public override IDeepCloneable Clone(Cloner cloner) {
    4139      return new CircularKernel(this, cloner);
    4240    }
    43     #endregion
    4441
    4542    protected override double Get(double norm) {
     43      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance while Beta is null");
    4644      var beta = Beta.Value;
    4745      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    5351    // 4*pi*n^3 / (beta^4 * sqrt(1-n^2/beta^2)
    5452    protected override double GetGradient(double norm) {
     53      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    5554      var beta = Beta.Value;
    5655      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/GaussianKernel.cs

    r14891 r15249  
    2727using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2828
    29 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     29namespace HeuristicLab.Algorithms.DataAnalysis {
    3030  [StorableClass]
    3131  [Item("GaussianKernel", "A kernel function that uses Gaussian function exp(-n²/beta²). As described in http://crsouza.com/2010/03/17/kernel-functions-for-machine-learning-applications/")]
    3232  public class GaussianKernel : KernelBase {
    33 
    34     #region HLConstructors & Boilerplate
    3533    [StorableConstructor]
    3634    protected GaussianKernel(bool deserializing) : base(deserializing) { }
    37     [StorableHook(HookType.AfterDeserialization)]
    38     private void AfterDeserialization() { }
     35
    3936    protected GaussianKernel(GaussianKernel original, Cloner cloner) : base(original, cloner) { }
     37
    4038    public GaussianKernel() {
    4139    }
     40
    4241    public override IDeepCloneable Clone(Cloner cloner) {
    4342      return new GaussianKernel(this, cloner);
    4443    }
    45     #endregion
    4644
    4745    protected override double Get(double norm) {
     46      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance while Beta is null");
    4847      var beta = Beta.Value;
    4948      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    5453    //2 * n²/b²* 1/b * exp(-n²/b²)
    5554    protected override double GetGradient(double norm) {
     55      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    5656      var beta = Beta.Value;
    5757      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/IKernel.cs

    r14887 r15249  
    2121
    2222
    23 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     23using System;
     24
     25namespace HeuristicLab.Algorithms.DataAnalysis {
    2426  public interface IKernel : ICovarianceFunction {
    2527    double? Beta { get; set; } // a kernel parameter
    2628    IDistance Distance { get; set; } // the distance function to use
     29
     30    event EventHandler BetaChanged;
     31    event EventHandler DistanceChanged;
    2732  }
    2833}
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/InverseMultiquadraticKernel.cs

    r14891 r15249  
    2525using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2626
    27 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     27namespace HeuristicLab.Algorithms.DataAnalysis {
    2828  [StorableClass]
    2929  [Item("InverseMultiquadraticKernel", "A kernel function that uses the inverse multi-quadratic function  1 / sqrt(1+||x-c||²/beta²). Similar to http://crsouza.com/2010/03/17/kernel-functions-for-machine-learning-applications/ with beta as a scaling factor.")]
    3030  public class InverseMultiquadraticKernel : KernelBase {
     31    private const double C = 1.0;
    3132
    32     private const double C = 1.0;
    33     #region HLConstructors & Boilerplate
    3433    [StorableConstructor]
    3534    protected InverseMultiquadraticKernel(bool deserializing) : base(deserializing) { }
    36     [StorableHook(HookType.AfterDeserialization)]
    37     private void AfterDeserialization() { }
     35
    3836    protected InverseMultiquadraticKernel(InverseMultiquadraticKernel original, Cloner cloner) : base(original, cloner) { }
     37
    3938    public InverseMultiquadraticKernel() { }
     39
    4040    public override IDeepCloneable Clone(Cloner cloner) {
    4141      return new InverseMultiquadraticKernel(this, cloner);
    4242    }
    43     #endregion
    4443
    4544    protected override double Get(double norm) {
     45      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance while Beta is null");
    4646      var beta = Beta.Value;
    4747      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    5252    //n²/(b³(n²/b² + C)^1.5)
    5353    protected override double GetGradient(double norm) {
     54      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    5455      var beta = Beta.Value;
    5556      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/KernelBase.cs

    r14887 r15249  
    2828using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2929
    30 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     30namespace HeuristicLab.Algorithms.DataAnalysis {
    3131  [StorableClass]
    3232  public abstract class KernelBase : ParameterizedNamedItem, IKernel {
    3333
    34     #region Parameternames
    3534    private const string DistanceParameterName = "Distance";
    36     #endregion
    37     #region Parameterproperties
    38     public ValueParameter<IDistance> DistanceParameter {
    39       get { return Parameters[DistanceParameterName] as ValueParameter<IDistance>; }
     35
     36    public IValueParameter<IDistance> DistanceParameter {
     37      get { return (IValueParameter<IDistance>)Parameters[DistanceParameterName]; }
    4038    }
    4139
    4240    [Storable]
    43     public double? Beta { get; set; }
    44     #endregion
    45     #region Properties
     41    private double? beta;
     42    public double? Beta {
     43      get { return beta; }
     44      set {
     45        if (value != beta) {
     46          beta = value;
     47          RaiseBetaChanged();
     48        }
     49      }
     50    }
     51
    4652    public IDistance Distance {
    4753      get { return DistanceParameter.Value; }
    48       set { DistanceParameter.Value = value; }
     54      set {
     55        if (DistanceParameter.Value != value) {
     56          DistanceParameter.Value = value;
     57        }
     58      }
    4959    }
    50 
    51     #endregion
    5260
    5361    [StorableConstructor]
    5462    protected KernelBase(bool deserializing) : base(deserializing) { }
    55     [StorableHook(HookType.AfterDeserialization)]
    56     private void AfterDeserialization() { }
    5763
    5864    protected KernelBase(KernelBase original, Cloner cloner)
    5965      : base(original, cloner) {
    60       Beta = original.Beta;
     66      beta = original.beta;
     67      RegisterEvents();
    6168    }
    6269
     
    6471      Parameters.Add(new ValueParameter<IDistance>(DistanceParameterName, "The distance function used for kernel calculation"));
    6572      DistanceParameter.Value = new EuclideanDistance();
     73      RegisterEvents();
     74    }
     75
     76    [StorableHook(HookType.AfterDeserialization)]
     77    private void AfterDeserialization() {
     78      RegisterEvents();
     79    }
     80
     81    private void RegisterEvents() {
     82      DistanceParameter.ValueChanged += (sender, args) => RaiseDistanceChanged();
    6683    }
    6784
     
    8299    public ParameterizedCovarianceFunction GetParameterizedCovarianceFunction(double[] p, int[] columnIndices) {
    83100      if (p.Length != GetNumberOfParameters(columnIndices.Length)) throw new ArgumentException("Illegal parametrization");
    84       var myClone = (KernelBase)Clone(new Cloner());
     101      var myClone = (KernelBase)Clone();
    85102      myClone.SetParameter(p);
    86103      var cov = new ParameterizedCovarianceFunction {
     
    101118      return dist.Get(r1, r2);
    102119    }
     120
     121    #region events
     122    public event EventHandler BetaChanged;
     123    public event EventHandler DistanceChanged;
     124
     125    protected void RaiseBetaChanged() {
     126      var handler = BetaChanged;
     127      if (handler != null) handler(this, EventArgs.Empty);
     128    }
     129
     130    protected void RaiseDistanceChanged() {
     131      var handler = DistanceChanged;
     132      if (handler != null) handler(this, EventArgs.Empty);
     133    }
     134    #endregion
    103135  }
    104136}
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/MultiquadraticKernel.cs

    r14891 r15249  
    2525using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2626
    27 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     27namespace HeuristicLab.Algorithms.DataAnalysis {
    2828  [StorableClass]
    2929  // conditionally positive definite. (need to add polynomials) see http://num.math.uni-goettingen.de/schaback/teaching/sc.pdf
     
    3232
    3333    private const double C = 1.0;
    34     #region HLConstructors & Boilerplate
     34
    3535    [StorableConstructor]
    3636    protected MultiquadraticKernel(bool deserializing) : base(deserializing) { }
    37     [StorableHook(HookType.AfterDeserialization)]
    38     private void AfterDeserialization() { }
    39     protected MultiquadraticKernel(MultiquadraticKernel original, Cloner cloner)
    40                 : base(original, cloner) { }
    4137
    42     public MultiquadraticKernel() {
    43     }
     38    protected MultiquadraticKernel(MultiquadraticKernel original, Cloner cloner) : base(original, cloner) { }
     39
     40    public MultiquadraticKernel() { }
     41
    4442    public override IDeepCloneable Clone(Cloner cloner) {
    4543      return new MultiquadraticKernel(this, cloner);
    4644    }
    47     #endregion
     45
    4846    protected override double Get(double norm) {
     47      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance while Beta is null");
    4948      var beta = Beta.Value;
    5049      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    5554    //-n²/(d³*sqrt(C+n²/d²))
    5655    protected override double GetGradient(double norm) {
     56      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    5757      var beta = Beta.Value;
    5858      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/PolysplineKernel.cs

    r14892 r15249  
    2727using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2828
    29 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     29namespace HeuristicLab.Algorithms.DataAnalysis {
    3030  [StorableClass]
    3131  // conditionally positive definite. (need to add polynomials) see http://num.math.uni-goettingen.de/schaback/teaching/sc.pdf
     
    3333  public class PolysplineKernel : KernelBase {
    3434
    35     #region Parameternames
    3635    private const string DegreeParameterName = "Degree";
    37     #endregion
    38     #region Parameterproperties
     36
    3937    public IFixedValueParameter<DoubleValue> DegreeParameter {
    40       get { return Parameters[DegreeParameterName] as IFixedValueParameter<DoubleValue>; }
     38      get { return (IFixedValueParameter<DoubleValue>)Parameters[DegreeParameterName]; }
    4139    }
    42     #endregion
    43     #region Properties
     40
    4441    public DoubleValue Degree {
    4542      get { return DegreeParameter.Value; }
    4643    }
    47     #endregion
    4844
    49     #region HLConstructors & Boilerplate
    5045    [StorableConstructor]
    5146    protected PolysplineKernel(bool deserializing) : base(deserializing) { }
    52     [StorableHook(HookType.AfterDeserialization)]
    53     private void AfterDeserialization() { }
     47
    5448    protected PolysplineKernel(PolysplineKernel original, Cloner cloner) : base(original, cloner) { }
     49
    5550    public PolysplineKernel() {
    5651      Parameters.Add(new FixedValueParameter<DoubleValue>(DegreeParameterName, "The degree of the kernel. Needs to be greater than zero.", new DoubleValue(1.0)));
    5752    }
     53
    5854    public override IDeepCloneable Clone(Cloner cloner) {
    5955      return new PolysplineKernel(this, cloner);
    6056    }
    61     #endregion
    6257
    6358    protected override double Get(double norm) {
     59      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    6460      var beta = Beta.Value;
    6561      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    7066    //-degree/beta * (norm/beta)^degree
    7167    protected override double GetGradient(double norm) {
     68      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    7269      var beta = Beta.Value;
    7370      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelFunctions/ThinPlatePolysplineKernel.cs

    r14892 r15249  
    2727using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
    2828
    29 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     29namespace HeuristicLab.Algorithms.DataAnalysis {
    3030  [StorableClass]
    3131  // conditionally positive definite. (need to add polynomials) see http://num.math.uni-goettingen.de/schaback/teaching/sc.pdf
     
    3333  public class ThinPlatePolysplineKernel : KernelBase {
    3434
    35     #region Parameternames
    3635    private const string DegreeParameterName = "Degree";
    37     #endregion
    38     #region Parameterproperties
     36
    3937    public IFixedValueParameter<DoubleValue> DegreeParameter {
    40       get { return Parameters[DegreeParameterName] as IFixedValueParameter<DoubleValue>; }
     38      get { return (IFixedValueParameter<DoubleValue>)Parameters[DegreeParameterName]; }
    4139    }
    42     #endregion
    43     #region Properties
    4440    public DoubleValue Degree {
    4541      get { return DegreeParameter.Value; }
    4642    }
    47     #endregion
    4843
    49     #region HLConstructors & Boilerplate
    5044    [StorableConstructor]
    5145    protected ThinPlatePolysplineKernel(bool deserializing) : base(deserializing) { }
    52     [StorableHook(HookType.AfterDeserialization)]
    53     private void AfterDeserialization() { }
     46
    5447    protected ThinPlatePolysplineKernel(ThinPlatePolysplineKernel original, Cloner cloner) : base(original, cloner) { }
     48
    5549    public ThinPlatePolysplineKernel() {
    5650      Parameters.Add(new FixedValueParameter<DoubleValue>(DegreeParameterName, "The degree of the kernel. Needs to be greater than zero.", new DoubleValue(2.0)));
    5751    }
     52
    5853    public override IDeepCloneable Clone(Cloner cloner) {
    5954      return new ThinPlatePolysplineKernel(this, cloner);
    6055    }
    61     #endregion
    6256
    6357    protected override double Get(double norm) {
     58      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance while Beta is null");
    6459      var beta = Beta.Value;
    6560      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
     
    7166    // (Degree/beta) * (norm/beta)^Degree * log(norm/beta)
    7267    protected override double GetGradient(double norm) {
     68      if (Beta == null) throw new InvalidOperationException("Can not calculate kernel distance gradient while Beta is null");
    7369      var beta = Beta.Value;
    7470      if (Math.Abs(beta) < double.Epsilon) return double.NaN;
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelRidgeRegression.cs

    r14888 r15249  
    2929using HeuristicLab.Parameters;
    3030using HeuristicLab.Persistence.Default.CompositeSerializers.Storable;
     31using HeuristicLab.PluginInfrastructure;
    3132using HeuristicLab.Problems.DataAnalysis;
    3233
    33 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     34namespace HeuristicLab.Algorithms.DataAnalysis {
    3435  [Item("Kernel Ridge Regression", "Kernelized ridge regression e.g. for radial basis function (RBF) regression.")]
    3536  [Creatable(CreatableAttribute.Categories.DataAnalysisRegression, Priority = 100)]
     
    5758
    5859    #region parameter properties
    59     public ValueParameter<IKernel> KernelParameter {
    60       get { return (ValueParameter<IKernel>)Parameters[KernelParameterName]; }
     60    public IConstrainedValueParameter<IKernel> KernelParameter {
     61      get { return (IConstrainedValueParameter<IKernel>)Parameters[KernelParameterName]; }
    6162    }
    6263
     
    102103    public KernelRidgeRegression() {
    103104      Problem = new RegressionProblem();
    104       Parameters.Add(new ValueParameter<IKernel>(KernelParameterName, "The kernel", new GaussianKernel()));
     105      var values = new ItemSet<IKernel>(ApplicationManager.Manager.GetInstances<IKernel>());
     106      Parameters.Add(new ConstrainedValueParameter<IKernel>(KernelParameterName, "The kernel", values, values.OfType<GaussianKernel>().FirstOrDefault()));
    105107      Parameters.Add(new FixedValueParameter<BoolValue>(ScaleInputVariablesParameterName, "Set to true if the input variables should be scaled to the interval [0..1]", new BoolValue(true)));
    106108      Parameters.Add(new FixedValueParameter<DoubleValue>(LambdaParameterName, "The log10-transformed weight for the regularization term lambda [-inf..+inf]. Small values produce more complex models, large values produce models with larger errors. Set to very small value (e.g. -1.0e15) for almost exact approximation", new DoubleValue(-2)));
    107       Parameters.Add(new FixedValueParameter<DoubleValue>(BetaParameterName, "The beta parameter for the kernel", new DoubleValue(2)));
     109      Parameters.Add(new FixedValueParameter<DoubleValue>(BetaParameterName, "The inverse width of the kernel ]0..+inf]. The distance between points is divided by this value before being plugged into the kernel.", new DoubleValue(2)));
    108110    }
    109     [StorableHook(HookType.AfterDeserialization)]
    110     private void AfterDeserialization() { }
    111111
    112112    public override IDeepCloneable Clone(Cloner cloner) {
     
    125125
    126126    public static IRegressionSolution CreateRadialBasisRegressionSolution(IRegressionProblemData problemData, ICovarianceFunction kernel, double lambda, bool scaleInputs, out double rmsError, out double looCvRMSE) {
    127       var model = new KernelRidgeRegressionModel(problemData.Dataset, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.TrainingIndices, scaleInputs, kernel, lambda);
     127      var model = KernelRidgeRegressionModel.Create(problemData.Dataset, problemData.TargetVariable, problemData.AllowedInputVariables, problemData.TrainingIndices, scaleInputs, kernel, lambda);
    128128      rmsError = double.NaN;
    129129      if (problemData.TestIndices.Any()) {
  • stable/HeuristicLab.Algorithms.DataAnalysis/3.4/KernelRidgeRegression/KernelRidgeRegressionModel.cs

    r14892 r15249  
    2828using HeuristicLab.Problems.DataAnalysis;
    2929
    30 namespace HeuristicLab.Algorithms.DataAnalysis.KernelRidgeRegression {
     30namespace HeuristicLab.Algorithms.DataAnalysis {
    3131  [StorableClass]
    3232  [Item("KernelRidgeRegressionModel", "A kernel ridge regression model")]
     
    3939    private readonly string[] allowedInputVariables;
    4040    public string[] AllowedInputVariables {
    41       get { return allowedInputVariables; }
     41      get { return allowedInputVariables.ToArray(); }
    4242    }
    4343
     
    8181      yOffset = original.yOffset;
    8282      yScale = original.yScale;
    83       if (original.kernel != null)
    84         kernel = cloner.Clone(original.kernel);
     83      kernel = original.kernel;
    8584    }
    8685    public override IDeepCloneable Clone(Cloner cloner) {
     
    8887    }
    8988
    90     public KernelRidgeRegressionModel(IDataset dataset, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
    91       bool scaleInputs, ICovarianceFunction kernel, double lambda = 0.1) : base(targetVariable) {
    92       if (kernel.GetNumberOfParameters(allowedInputVariables.Count()) > 0) throw new ArgumentException("All parameters in the kernel function must be specified.");
    93       name = ItemName;
    94       description = ItemDescription;
    95       this.allowedInputVariables = allowedInputVariables.ToArray();
     89    public static KernelRidgeRegressionModel Create(IDataset dataset, string targetVariable, IEnumerable<string> allowedInputVariables, IEnumerable<int> rows,
     90      bool scaleInputs, ICovarianceFunction kernel, double lambda = 0.1) {
    9691      var trainingRows = rows.ToArray();
    97       this.kernel = (ICovarianceFunction)kernel.Clone();
    98       this.lambda = lambda;
     92      var model = new KernelRidgeRegressionModel(dataset, targetVariable, allowedInputVariables, trainingRows, scaleInputs, kernel, lambda);
     93
    9994      try {
    100         if (scaleInputs)
    101           scaling = CreateScaling(dataset, trainingRows);
    102         trainX = ExtractData(dataset, trainingRows, scaling);
     95        int info;
     96        int n = model.trainX.GetLength(0);
     97        alglib.densesolverreport denseSolveRep;
     98        var gram = BuildGramMatrix(model.trainX, lambda, kernel);
     99        var l = new double[n, n];
     100        Array.Copy(gram, l, l.Length);
     101
     102        double[] alpha = new double[n];
     103        double[,] invG;
    103104        var y = dataset.GetDoubleValues(targetVariable, trainingRows).ToArray();
    104         yOffset = y.Average();
    105         yScale = 1.0 / y.StandardDeviation();
    106105        for (int i = 0; i < y.Length; i++) {
    107           y[i] -= yOffset;
    108           y[i] *= yScale;
    109         }
    110         int info;
    111         int n = trainX.GetLength(0);
    112         alglib.densesolverreport denseSolveRep;
    113         var gram = BuildGramMatrix(trainX, lambda);
    114         var l = new double[n, n]; Array.Copy(gram, l, l.Length);
    115 
    116         double[,] invG;
     106          y[i] -= model.yOffset;
     107          y[i] *= model.yScale;
     108        }
    117109        // cholesky decomposition
    118110        var res = alglib.trfac.spdmatrixcholesky(ref l, n, false);
    119         if (res == false) { //throw new ArgumentException("Could not decompose matrix. Is it quadratic symmetric positive definite?");
     111        if (res == false) { //try lua decomposition if cholesky faild
    120112          int[] pivots;
    121113          var lua = new double[n, n];
     
    127119          invG = lua;  // rename
    128120          alglib.rmatrixluinverse(ref invG, pivots, n, out info, out rep);
    129           if (info != 1) throw new ArgumentException("Could not invert Gram matrix.");
    130121        } else {
    131122          alglib.spdmatrixcholeskysolve(l, n, false, y, out info, out denseSolveRep, out alpha);
     
    135126          invG = l;   // rename
    136127          alglib.spdmatrixcholeskyinverse(ref invG, n, false, out info, out rep);
    137           if (info != 1) throw new ArgumentException("Could not invert Gram matrix.");
    138         }
     128        }
     129        if (info != 1) throw new ArgumentException("Could not invert Gram matrix.");
    139130
    140131        var ssqLooError = 0.0;
     
    142133          var pred_i = Util.ScalarProd(Util.GetRow(gram, i).ToArray(), alpha);
    143134          var looPred_i = pred_i - alpha[i] / invG[i, i];
    144           var error = (y[i] - looPred_i) / yScale;
     135          var error = (y[i] - looPred_i) / model.yScale;
    145136          ssqLooError += error * error;
    146137        }
    147         LooCvRMSE = Math.Sqrt(ssqLooError / n);
     138
     139        Array.Copy(alpha, model.alpha, n);
     140        model.LooCvRMSE = Math.Sqrt(ssqLooError / n);
    148141      } catch (alglib.alglibexception ae) {
    149142        // wrap exception so that calling code doesn't have to know about alglib implementation
    150143        throw new ArgumentException("There was a problem in the calculation of the kernel ridge regression model", ae);
    151144      }
     145      return model;
     146    }
     147
     148    private KernelRidgeRegressionModel(IDataset dataset, string targetVariable, IEnumerable<string> allowedInputVariables, int[] rows,
     149      bool scaleInputs, ICovarianceFunction kernel, double lambda = 0.1) : base(targetVariable) {
     150      this.allowedInputVariables = allowedInputVariables.ToArray();
     151      if (kernel.GetNumberOfParameters(this.allowedInputVariables.Length) > 0) throw new ArgumentException("All parameters in the kernel function must be specified.");
     152      name = ItemName;
     153      description = ItemDescription;
     154
     155      this.kernel = (ICovarianceFunction)kernel.Clone();
     156      this.lambda = lambda;
     157      if (scaleInputs) scaling = CreateScaling(dataset, rows, this.allowedInputVariables);
     158      trainX = ExtractData(dataset, rows, this.allowedInputVariables, scaling);
     159      var y = dataset.GetDoubleValues(targetVariable, rows).ToArray();
     160      yOffset = y.Average();
     161      yScale = 1.0 / y.StandardDeviation();
     162      alpha = new double[trainX.GetLength(0)];
    152163    }
    153164
     
    155166    #region IRegressionModel Members
    156167    public override IEnumerable<double> GetEstimatedValues(IDataset dataset, IEnumerable<int> rows) {
    157       var newX = ExtractData(dataset, rows, scaling);
     168      var newX = ExtractData(dataset, rows, allowedInputVariables, scaling);
    158169      var dim = newX.GetLength(1);
    159170      var cov = kernel.GetParameterizedCovarianceFunction(new double[0], Enumerable.Range(0, dim).ToArray());
     
    175186
    176187    #region helpers
    177     private double[,] BuildGramMatrix(double[,] data, double lambda) {
     188    private static double[,] BuildGramMatrix(double[,] data, double lambda, ICovarianceFunction kernel) {
    178189      var n = data.GetLength(0);
    179190      var dim = data.GetLength(1);
     
    190201    }
    191202
    192     private ITransformation<double>[] CreateScaling(IDataset dataset, int[] rows) {
    193       var trans = new ITransformation<double>[allowedInputVariables.Length];
     203    private static ITransformation<double>[] CreateScaling(IDataset dataset, int[] rows, IReadOnlyCollection<string> allowedInputVariables) {
     204      var trans = new ITransformation<double>[allowedInputVariables.Count];
    194205      int i = 0;
    195206      foreach (var variable in allowedInputVariables) {
     
    205216    }
    206217
    207     private double[,] ExtractData(IDataset dataset, IEnumerable<int> rows, ITransformation<double>[] scaling = null) {
     218    private static double[,] ExtractData(IDataset dataset, IEnumerable<int> rows, IReadOnlyCollection<string> allowedInputVariables, ITransformation<double>[] scaling = null) {
    208219      double[][] variables;
    209220      if (scaling != null) {
Note: See TracChangeset for help on using the changeset viewer.