MATLAB 拟合完全指南
拟合是数据分析中的一项核心任务,其目标是找到一个函数(曲线或曲面),能够最好地描述一组数据点之间的关系,MATLAB 提供了强大的工具箱和函数来执行各种类型的拟合。

本教程将分为以下几个部分:
- 核心概念:什么是拟合?
- 基础入门:使用
polyfit和polyval进行多项式拟合 - 进阶工具:使用 Curve Fitting Toolbox™
- 交互式拟合工具 (
cftool) - 命令行拟合 (
fit)
- 交互式拟合工具 (
- 高级主题:非线性拟合
- 使用
fitnlm(推荐) - 使用
lsqcurvefit
- 使用
- 拟合结果评估与可视化
- 完整实例:从数据到模型
- 总结与建议
核心概念:什么是拟合?
假设我们有一组实验数据 (x, y),我们相信这些数据背后存在一个潜在的函数关系 y = f(x),但由于测量误差、噪声等因素,数据点并不会完美地落在 f(x) 上。
拟合的目标:找到一个模型函数 y = g(x),使得 g(x) 尽可能地接近所有数据点。
- 模型:我们选择的函数形式,直线 (
y = ax + b)、二次多项式 (y = ax² + bx + c)、指数函数 (y = a * e^(bx)) 等。 - 误差:模型预测值
g(x)与实际观测值y之间的差异,通常使用最小二乘法来最小化所有数据点的误差平方和。
基础入门:多项式拟合
对于许多简单问题,多项式拟合是首选,MATLAB 提供了两个核心函数:

p = polyfit(x, y, n):执行n阶多项式拟合。x,y:数据向量。n:多项式的阶数。- 输出
p是一个包含多项式系数的向量,p(1)*x^n + p(2)*x^(n-1) + ... + p(n+1)。
y_fit = polyval(p, x):使用polyfit得到的系数p来计算在x处的拟合值。
示例:线性拟合(一阶多项式)
% 1. 创建带有噪声的示例数据
x = (0:0.1:10)';
y = 2*x + 1 + randn(size(x)); % y = 2x + 1 + 噪声
% 2. 进行一阶多项式拟合 (即线性拟合)
p = polyfit(x, y, 1);
% 3. 查看拟合结果(系数)
disp('拟合得到的系数 (斜率, 截距):');
disp(p); % 应该接近 [2, 1]
% 4. 计算拟合值
y_fit = polyval(p, x);
% 5. 可视化结果
figure;
plot(x, y, 'o', 'MarkerFaceColor', 'b'); % 原始数据点
hold on;
plot(x, y_fit, 'r-', 'LineWidth', 2); % 拟合曲线
xlabel('x');
ylabel('y');'线性拟合 (polyfit)');
legend('原始数据', '拟合直线', 'Location', 'northwest');
grid on;
hold off;
代码解释:
- 我们生成了一条直线
y = 2x + 1并添加了高斯噪声。 polyfit(x, y, 1)告诉 MATLAB 用一条直线来拟合这些数据。- 输出的
p向量是[2.0123, 0.9876](具体数值因随机噪声而异),非常接近真实的[2, 1]。 polyval使用这个系数向量来生成完整的拟合直线。- 绘图清晰地展示了原始数据点和拟合的直线。
进阶工具:Curve Fitting Toolbox™
对于更复杂的拟合需求(如自定义函数、拟合优度统计、置信区间等),强烈推荐使用 Curve Fitting Toolbox,它提供了两种主要方式:交互式工具和命令行函数。
1 交互式拟合工具 (cftool)
这是最简单、最直观的方式,无需编写大量代码。
- 启动工具:在 MATLAB 命令窗口输入
cftool并回车。 - 导入数据:在弹出的窗口中,点击 "Data..." 按钮,选择你的
x和y变量。 - 选择拟合类型:
- 在 "Fit Type" 选项卡中,你可以选择:
- Polynomial:多项式拟合。
- Exponential:指数拟合,如
a*exp(b*x)。 - Fourier:傅里叶级数拟合。
- Gaussian:高斯函数拟合。
- Power:幂函数拟合,如
a*x^b。 - Rational:有理式拟合。
- Sum of Sinusoids:正弦函数和。
- Weibull:威布尔分布拟合。
- Custom Equation:最强大的功能,可以输入你自己的任意函数表达式。
- 在 "Fit Type" 选项卡中,你可以选择:
- 拟合与评估:选择好拟合类型和阶数后,点击 "Fit" 按钮,工具会自动完成拟合,并在结果窗口中显示:
- 拟合方程。
- 拟合系数及其置信区间。
- 拟合优度统计:R-square (决定系数)、SSE (误差平方和)、RMSE (均方根误差) 等。R-square 越接近 1,拟合效果越好。
- 残差图。
- 导出结果:你可以将拟合模型、方程、图形等导出到 MATLAB 工作区或文件中。
2 命令行拟合 (fit 函数)
如果你需要将拟合过程自动化或集成到脚本中,可以使用 fit 函数。

% 1. 准备数据 (与之前相同)
x = (0:0.1:10)';
y = 2*x + 1 + randn(size(x));
% 2. 使用 fit 函数进行拟合
% 'poly1' 表示一阶多项式 (linear)
% 'poly2' 表示二阶多项式 (quadratic)
% fittype('exp1') 表示指数函数 a*exp(b*x)
[fit_model, gof] = fit(x, y, 'poly1');
% 3. 查看拟合结果
disp('拟合模型:');
disp(fit_model);
disp('拟合优度:');
disp(gof); % 包含 R-square, SSE, RMSE 等信息
% 4. 使用模型进行预测
x_new = 12;
y_new = fit_model(x_new);
fprintf('在 x = %d 处的预测值为: %.4f\n', x_new, y_new);
% 5. 绘制结果
figure;
plot(fit_model, x, y); % cftool 生成的精美图形
xlabel('x');
ylabel('y');'使用 fit 函数进行线性拟合');
代码解释:
fit(x, y, 'poly1')直接创建了一个线性拟合模型。- 输出
fit_model是一个cfit对象,它封装了所有拟合信息,包括系数、方程等,你可以像调用函数一样使用它,fit_model(12)。 - 输出
gof(goodness of fit) 是一个结构体,包含了评估拟合质量的各项指标。
高级主题:非线性拟合
当数据不能用简单的多项式或预定义函数描述时,就需要使用非线性拟合,你需要提供一个自定义的函数形式。
1 使用 fitnlm (推荐)
fitnlm (Fit Nonlinear Model) 是 Curve Fitting Toolbox 中的首选函数,功能强大且输出信息丰富。
步骤:
- 定义非线性函数:创建一个
.m文件或使用匿名函数来定义你的模型。 - 提供初始猜测值:非线性拟合需要一个好的起点,否则可能收敛到局部最优解。
- 调用
fitnlm。
示例:拟合指数衰减函数 y = a * exp(b*x) + c
% 1. 创建数据
x = (0:0.1:5)';
y = 10 * exp(-0.5*x) + 2 + randn(size(x)); % y = 10*exp(-0.5x) + 2 + 噪声
% 2. 定义非线性函数 (使用匿名函数)
% 注意:函数的输入必须是 (x, 参数1, 参数2, ...)
my_fun = @(x, a, b, c) a * exp(b*x) + c;
% 3. 提供初始猜测值 [a, b, c]
% 这是非常关键的一步!观察数据,y的初始值约为12,所以a+c≈12,衰减很快,b应为负数。
start_point = [12, -1, 0];
% 4. 调用 fitnlm
% 'Robust', 'on' 可以使拟合对异常值更稳健
nlm_model = fitnlm(x, y, my_fun, start_point, 'Robust', 'on');
% 5. 查看结果
disp('非线性拟合模型系数:');
disp(nlm_model.Coefficients);
% 6. 绘制结果
figure;
scatter(x, y, 'b'); hold on;
% 使用 fitted 函数获取所有拟合点
plot(x, fitted(nlm_model), 'r-', 'LineWidth', 2);
xlabel('x');
ylabel('y');'非线性拟合 (fitnlm)');
legend('原始数据', '拟合曲线', 'Location', 'northwest');
grid on;
hold off;
2 使用 lsqcurvefit
lsqcurvefit 在 Optimization Toolbox 中,它是最小化平方和的通用工具,更底层。
% 1. 准备数据 (与上面相同)
x = (0:0.1:5)';
y = 10 * exp(-0.5*x) + 2 + randn(size(x));
% 2. 定义函数 (注意:函数的第一个参数必须是系数向量)
fun = @(params, x_data) params(1) * exp(params(2)*x_data) + params(3);
% 3. 提供初始猜测值
start_point = [12, -1, 0];
% 4. 调用 lsqcurvefit
% options = optimoptions('lsqcurvefit', 'Display', 'iter'); % 可选,查看迭代过程
params_fit = lsqcurvefit(fun, start_point, x, y);
% 5. 查看结果
disp('lsqcurvefit 拟合得到的系数:');
disp(params_fit);
% 6. 绘制结果 (与上面类似)
y_fit_lsq = fun(params_fit, x);
figure;
scatter(x, y, 'b'); hold on;
plot(x, y_fit_lsq, 'g-', 'LineWidth', 2);
xlabel('x');
ylabel('y');'非线性拟合 (lsqcurvefit)');
legend('原始数据', '拟合曲线', 'Location', 'northwest');
grid on;
hold off;
fitnlm vs lsqcurvefit:
fitnlm:更高级,专为拟合设计,直接提供拟合优度统计、系数置信区间、残差分析等,非常适合统计分析。lsqcurvefit:更通用,是优化工具箱的一部分,它只找到使误差最小的参数,不提供统计信息,如果你只需要参数值而不关心统计推断,它也可以用。
拟合结果评估与可视化
一个好的模型不仅要拟合数据,还要有良好的泛化能力。
- R-square (决定系数):
- 范围在 0 到 1 之间。
- 值越接近 1,表示模型能解释数据中越多的变异性。
- 警告:增加模型复杂度(如提高多项式阶数)总会使 R-square 增大,可能导致过拟合。
- Adjusted R-square (调整 R-square):
- 在 R-square 的基础上考虑了模型中自变量的数量。
- 在比较不同复杂度的模型时,它比 R-square 更可靠。
- SSE (Sum of Squares Due to Error):误差平方和,值越小越好。
- RMSE (Root Mean Squared Error):均方根误差,与因变量的单位相同,直观地表示了预测值的平均误差大小。
- 残差图:绘制残差 (实际值 - 预测值) 与预测值或自变量的图。
- 一个好的模型,其残差图应该呈现随机、无序地分布在
y=0附近。 - 如果残差图呈现出明显的模式(如曲线、喇叭形),则说明模型可能遗漏了某些重要信息(应该用更高阶的项或不同的函数形式)。
- 一个好的模型,其残差图应该呈现随机、无序地分布在
完整实例:从数据到模型
假设我们有以下数据,并相信它符合 y = a * x^b 的关系。
% 1. 数据准备
x_data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
y_data = [2.1, 5.5, 11.2, 19.8, 31.5, 45.9, 63.2, 83.1, 105.8, 131.2];
% 2. 探索性绘图 - 看起来像幂函数关系
figure;
plot(x_data, y_data, 'o');
xlabel('x');
ylabel('y');'原始数据散点图');
grid on;
% 3. 尝试幂函数拟合 (使用 cftool 的命令行版本)
power_model = fit(x_data', y_data', 'power1');
disp('幂函数拟合结果 (y = a*x^b):');
disp(power_model);
% 4. 评估拟合效果
figure;
plot(power_model, x_data', y_data'); % cftool 风格图
xlabel('x');
ylabel('y');'幂函数拟合结果');
% 5. 检查残差
residuals = y_data - power_model(x_data');
figure;
plot(x_data, residuals, 'o');
hold on;
plot([min(x_data), max(x_data)], [0, 0], 'r--'); % 画 y=0 参考线
xlabel('x');
ylabel('残差');'残差图');
grid on;
% 6. (可选) 线性化拟合 (对数变换)
% 对 y = a*x^b 两边取对数: log(y) = log(a) + b*log(x)
log_x = log(x_data);
log_y = log(y_data);
% 线性拟合 log(y) vs log(x)
p_log = polyfit(log_x, log_y, 1);
a_log = exp(p_log(2)); % a = exp(log(a))
b_log = p_log(1); % b 就是斜率
fprintf('\n通过线性化拟合得到的参数:\n');
fprintf('a = %.4f, b = %.4f\n', a_log, b_log);
% 绘制线性化拟合结果
figure;
plot(log_x, log_y, 'o', 'MarkerFaceColor', 'b');
hold on;
y_fit_log = polyval(p_log, log_x);
plot(log_x, y_fit_log, 'r-', 'LineWidth', 2);
xlabel('log(x)');
ylabel('log(y)');'线性化拟合 (log-log space)');
legend('log数据', '拟合直线', 'Location', 'northwest');
grid on;
实例分析:
- 初步绘图提示我们数据可能符合幂律关系。
- 使用
fit函数直接拟合power1模型,非常方便。 - 检查残差图,发现点随机分布在零附近,没有明显模式,说明幂函数模型是一个不错的选择。
- 我们还展示了线性化方法,这是一种经典的技巧,但对于带噪声的数据,直接非线性拟合 (
fitnlm或cftool) 通常更稳定和准确。
总结与建议
| 场景 | 推荐工具 | 优点 |
|---|---|---|
| 快速、一次性分析 | cftool (交互式) |
无需编程,可视化强,结果全面,最适合初学者。 |
| 多项式拟合 | polyfit / polyval |
简单、快速,是 MATLAB 内置函数,无需额外工具箱。 |
| 需要自动化/脚本化 | fit (命令行) |
功能强大,与 cftool 结果一致,易于集成到代码中。 |
| 自定义非线性函数 | fitnlm |
首选,提供完整的统计信息,稳健性好,易于使用。 |
| 通用最小二乘问题 | lsqcurvefit |
功能最底层灵活,但只提供参数值,无统计信息。 |
学习路径建议:
- 从
cftool开始:用它来理解不同类型的拟合和评估指标。 - 掌握
polyfit:用于处理简单的线性或多项式关系。 - 学习
fit:当你需要将拟合过程放入脚本时。 - 深入
fitnlm:当你遇到复杂的、自定义的非线性模型时,这是你的终极武器。
希望这份详尽的教程能帮助你掌握 MATLAB 拟合!多动手实践,尝试不同的数据和模型,你会很快上手的。
