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

求拟合类正弦数据下界的Linear/Polynomial回归算法(所有点不低于曲线)

拟合离散数据下界曲线的解决方案:带约束的回归方法

Hey there! 不用客气,研究初期遇到这类问题太正常了~你需要的是带不等式约束的回归算法——常规回归是找贴合数据中心的曲线,而我们要强制所有数据点都在拟合曲线的上方,也就是对每个数据点$(x_i, y_i)$,必须满足$\hat{y}(x_i) \leq y_i$($\hat{y}(x)$是拟合出的下界曲线)。下面给你拆解具体思路和代码示例:

核心思路:约束最小二乘回归

常规多项式回归的目标是最小化$\sum_{i=1}^n (y_i - \hat{y}(x_i))^2$(整体拟合误差),现在我们要给这个目标加上硬约束:所有$\hat{y}(x_i)$都不能超过$y_i$。这属于带不等式约束的优化问题,有两种常用实现方式:

1. 线性规划(适合线性回归场景)

如果选择线性拟合$\hat{y}(x) = ax + b$,约束条件就是$ax_i + b \leq y_i$对所有数据点成立。我们可以把目标设为最小化曲线的整体"偏差"(比如最小化$\sum_{i=1}^n (y_i - (ax + b))$),转化为线性规划问题求解,很多数值库都支持这类求解。

2. 带约束的最小二乘(推荐用于多项式回归)

如果要拟合更高阶的多项式(比如二次、三次,对应你说的"更佳方案"),目标还是最小化平方误差,但要满足$\hat{y}(x_i) \leq y_i$的约束。这类问题可以用拉格朗日乘数法推导,或者直接借助成熟的数值优化库(比如Eigen、GSL)来快速实现,不用自己造轮子。

C++ 示例代码(二次多项式下界拟合)

下面用Eigen库(轻量级线性代数库,很适合C++做数值计算)实现二次多项式的下界拟合,代码里包含了数据模拟、约束构建和结果验证:

#include <Eigen/Dense>
#include <Eigen/ConstrainedLeastSquares>
#include <vector>
#include <iostream>
#include <cmath>

using namespace Eigen;

// 构建多项式特征矩阵:给每个x生成[1, x, x², ..., x^degree]
MatrixXd buildPolyFeatures(const std::vector<double>& x, int degree) {
    MatrixXd features(x.size(), degree + 1);
    for (int i = 0; i < x.size(); ++i) {
        double xi = x[i];
        features(i, 0) = 1.0;
        for (int d = 1; d <= degree; ++d) {
            features(i, d) = pow(xi, d);
        }
    }
    return features;
}

int main() {
    // 模拟你的类正弦离散数据(蓝色点)
    std::vector<double> x = {0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0};
    std::vector<double> y = {0.1, 0.6, 0.9, 0.7, 0.3, 0.2, 0.5, 0.8, 0.9};

    // 选择二次多项式拟合(degree=2,你可以改成3、4等更高阶)
    int degree = 2;
    MatrixXd X = buildPolyFeatures(x, degree);
    VectorXd Y(y.data(), y.size());

    // 构建约束:要求拟合值X*w ≤ Y(所有数据点都在曲线上方)
    ConstrainedLeastSquaresProblem<MatrixXd, VectorXd> clsp;
    clsp.setUnconstrainedProblem(X, Y); // 基础最小二乘目标
    clsp.addInequalityConstraint(X, Y); // 添加不等式约束

    // 求解带约束的最小二乘
    VectorXd w = clsp.solve();

    // 输出拟合得到的多项式系数
    std::cout << "拟合的二次多项式系数:" << std::endl;
    std::cout << "常数项 w0 = " << w(0) << "\n一次项 w1 = " << w(1) << "\n二次项 w2 = " << w(2) << std::endl;

    // 验证每个数据点是否满足约束
    std::cout << "\n验证所有数据点是否在拟合曲线上方:" << std::endl;
    for (int i = 0; i < x.size(); ++i) {
        double y_hat = w(0) + w(1)*x[i] + w(2)*pow(x[i], 2);
        // 加1e-6是避免浮点精度误差导致的误判
        bool constraint_satisfied = (y_hat <= y[i] + 1e-6);
        std::cout << "x=" << x[i] << " | 原始y=" << y[i] << " | 拟合下界y_hat=" << y_hat << " | 约束满足:" << (constraint_satisfied ? "是" : "否") << std::endl;
    }

    return 0;
}

额外说明

  • 如果你不想用Eigen库,也可以手动实现带约束的梯度下降:每次更新多项式参数后,检查所有数据点的约束是否被违反,若违反则调整参数回到约束范围内,反复迭代直到收敛;
  • 你提到的"理想解决方案"(绿色曲线),其实就是约束最小二乘的最优结果——在满足所有点在上方的前提下,让曲线尽可能贴近数据的下界,平衡了约束和拟合精度;
  • 如果是线性回归场景,约束逻辑更简单,甚至可以用线性规划的单纯形法手动实现,但用库会更高效稳定。

内容的提问来源于stack exchange,提问作者Kowalski Paweł

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:38:05