Search code examples
c#curve-fittingnon-linear-regressionmathnet-numerics

How can I do nonlinear regression using MathNet library?


I am trying to use MathNet library to compute curve fitting based on nonlinear regression.

using System;
using System.Linq;
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra;
using MathNet.Numerics.Optimization;

class NonLinearRegressionExample
{
    static void Main()
    {
        // Example data points
        double[] xdata = new double[] { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 };
        double[] ydata = new double[] { 1.0, 2.7, 5.8, 6.6, 7.5, 9.9 };

        // Define the model function
        Func<Vector<double>, double, double> modelFunc = (parameters, x) =>
            parameters[0] * Math.Exp(parameters[1] * x);

        // Objective function: sum of squared residuals
        Func<Vector<double>, double> objectiveFunction = (parameters) =>
        {
            double sumOfSquares = 0;
            for (int i = 0; i < xdata.Length; i++)
            {
                double error = ydata[i] - modelFunc(parameters, xdata[i]);
                sumOfSquares += error * error;
            }
            return sumOfSquares;
        };

        // Gradient of the objective function (if it's not provided, you'll need to implement this)
        Func<Vector<double>, Vector<double>> gradientFunction = (parameters) =>
        {
            // You'll need to implement the gradient here
            throw new NotImplementedException("Gradient function is not implemented.");
        };

        // Initial guess for parameters a and b
        var initialGuess = Vector<double>.Build.DenseOfArray(new double[] { 1.0, 0.1 });

        // Create the objective function without a gradient
        var objective = ObjectiveFunction.Value(objectiveFunction) as IObjectiveModel;
        

        // Use a Levenberg-Marquardt optimizer for minimization
        var optimizer = new LevenbergMarquardtMinimizer();

        // Minimize the objective function starting from the initial guess
        var result = optimizer.FindMinimum(objective, initialGuess);

        // Output the results
        if (result.MinimizingPoint.Count == 2)
        {
            Console.WriteLine("Fitted parameters:");
            Console.WriteLine($"a = {result.MinimizingPoint[0]}");
            Console.WriteLine($"b = {result.MinimizingPoint[1]}");
        }
    }
}

However, I am getting the following exception:

System.ArgumentNullException: 'Value cannot be null.
Parameter name: objective'

How can I fix it?


Solution

  • I wrote you a comment due to your exception being the wrong function/model (ObjectiveFunction.Value returns an object with interface IObjectiveFunction). The minimizer needs to know your model in order to minimize the function parameters. I put your data in a piece of working code below using the Levenberg Marquardt minimizer and it seems to converge on my system after 18 iterations.

    using MathNet.Numerics.LinearAlgebra;
    using MathNet.Numerics.LinearAlgebra.Double;
    using MathNet.Numerics.Optimization;
    
    // example data
    var xData = new DenseVector(new double[] { 0.0, 1.0, 2.0, 3.0, 4.0, 5.0 });
    var yData = new DenseVector(new double[] { 1.0, 2.7, 5.8, 6.6, 7.5, 9.9 });
    
    Vector<double> Model(Vector<double> parameters, Vector<double> x)
    {
        var y = CreateVector.Dense<double>(x.Count);    
        for (int i = 0; i < x.Count; i++)
        {    
            y[i] = parameters[0] * Math.Exp(parameters[1] * x[i]);
        }
        return y;        
    }
    
    var start = new DenseVector(new double[] { 1.0, 0.1 });
    var objective = ObjectiveFunction.NonlinearModel(Model, xData, yData);
    var solver = new LevenbergMarquardtMinimizer(maximumIterations: 10000);
    var result = solver.FindMinimum(objective, start);