You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用MathNet实现非线性回归时遇ArgumentNullException的修复方法

修复MathNet非线性回归代码中的ArgumentNullException异常

问题描述

尝试使用MathNet库进行非线性回归曲线拟合,编写了如下代码:

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]}");
        }
    }
}

运行时抛出异常:

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

修复方案

1. 问题根源

ObjectiveFunction.Value(objectiveFunction)返回的是ObjectiveFunction类型,它不实现IObjectiveModel接口,所以强制类型转换as IObjectiveModel会得到null,传递给optimizer.FindMinimum时触发空参数异常。

2. 具体修复步骤

方法一:移除不必要的类型转换

直接使用ObjectiveFunction.Value返回的实例,无需强制转换为IObjectiveModel:

// 去掉无效的类型转换
var objective = ObjectiveFunction.Value(objectiveFunction);

方法二:实现梯度函数(更推荐)

Levenberg-Marquardt算法可以利用梯度信息提升拟合效率,先实现目标函数的梯度计算:

// 实现目标函数的梯度:对每个参数求偏导
Func<Vector<double>, Vector<double>> gradientFunction = (parameters) =>
{
    double a = parameters[0];
    double b = parameters[1];
    double gradA = 0;
    double gradB = 0;

    for (int i = 0; i < xdata.Length; i++)
    {
        double x = xdata[i];
        double y = ydata[i];
        double modelVal = a * Math.Exp(b * x);
        double error = y - modelVal;

        // 对参数a的偏导
        gradA += -2 * error * Math.Exp(b * x);
        // 对参数b的偏导
        gradB += -2 * error * a * x * Math.Exp(b * x);
    }

    return Vector<double>.Build.Dense(new[] { gradA, gradB });
};

然后创建带梯度的目标函数:

var objective = ObjectiveFunction.Gradient(objectiveFunction, gradientFunction);

3. 完整修复后的代码

以方法二为例,完整代码如下:

using System;
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: a*e^(bx)
        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;
        };

        // 实现梯度函数
        Func<Vector<double>, Vector<double>> gradientFunction = (parameters) =>
        {
            double a = parameters[0];
            double b = parameters[1];
            double gradA = 0;
            double gradB = 0;

            for (int i = 0; i < xdata.Length; i++)
            {
                double x = xdata[i];
                double y = ydata[i];
                double modelVal = a * Math.Exp(b * x);
                double error = y - modelVal;

                gradA += -2 * error * Math.Exp(b * x);
                gradB += -2 * error * a * x * Math.Exp(b * x);
            }

            return Vector<double>.Build.Dense(new[] { gradA, gradB });
        };

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

        // 创建带梯度的目标函数
        var objective = ObjectiveFunction.Gradient(objectiveFunction, gradientFunction);

        // 使用Levenberg-Marquardt优化器
        var optimizer = new LevenbergMarquardtMinimizer();

        // 执行最小化
        var result = optimizer.FindMinimum(objective, initialGuess);

        // 输出结果
        if (result.MinimizingPoint.Count == 2)
        {
            Console.WriteLine("Fitted parameters:");
            Console.WriteLine($"a = {result.MinimizingPoint[0]:F4}");
            Console.WriteLine($"b = {result.MinimizingPoint[1]:F4}");
        }
    }
}

4. 运行结果说明

修复后运行代码,会输出拟合后的参数值(示例数据下大概是a≈1.15,b≈0.32),符合指数曲线拟合的预期结果。


内容的提问来源于stack exchange,提问作者user366312

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 22:50:37