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

C++线性回归预测加密货币价格出现-nan(ind)错误求助

解决线性回归参数溢出与-nan(ind)问题的排查方案

我来帮你搞定这个头疼的-nan(ind)和参数溢出问题!从你给出的代码和运行数据来看,核心问题出在数据量级差异、学习率设置以及当前的梯度下降实现方式上,下面一步步拆解原因并给出解决办法:

问题原因分析

  • 特征数值量级悬殊:BTC/USDT、ETH/USDT的价格都是数千甚至数万级别的,而DOGE这类小币种价格极低。你当前的b1更新公式是b1 = b1 - alpha * err * ordersX[index].price,当ordersX[index].price是几万时,哪怕err只有几百,这个乘积都会瞬间拉满参数值,直接让b1爆炸到inf,后续运算自然出现nan。
  • 学习率(alpha)过高:0.01的学习率对小量级特征(比如DOGE的价格)可能勉强能用,但对BTC这种大数值特征来说,每一步的更新幅度过大,参数直接跳出收敛范围,彻底发散。
  • 单样本随机梯度下降(SGD)稳定性差:你现在每次只用单个样本更新参数,这种方式本身方差就大,再加上没有做特征归一化和学习率衰减,很容易导致参数震荡甚至直接溢出。

具体解决方法

1. 必须先做特征归一化/标准化

这是解决大数值特征梯度溢出最关键的一步,把所有X(价格)缩放到0-1或者-1到1的小范围,消除量级差异。比如用min-max归一化:

void LinearRegression::gradientDescent(std::vector<OrderBookEntry>& ordersX, std::vector<OrderBookEntry>& ordersY) {
    double b0 = 0;
    double b1 = 0;
    double alpha = 0.001;
    int epochs = 200;
    int n = ordersX.size();

    // 第一步:计算X的最大最小值,做min-max归一化
    double min_x = ordersX[0].price;
    double max_x = ordersX[0].price;
    for (auto& entry : ordersX) {
        min_x = std::min(min_x, entry.price);
        max_x = std::max(max_x, entry.price);
    }
    std::vector<double> scaled_x;
    for (auto& entry : ordersX) {
        // 缩放到0-1区间
        scaled_x.push_back((entry.price - min_x) / (max_x - min_x));
    }

    // 后续迭代用scaled_x替代原始price
    // ... 剩下的迭代代码
}

2. 调整学习率并添加衰减

把初始学习率调小(比如从0.01改成0.001甚至0.0001),然后随着迭代次数增加逐步降低学习率,避免后期参数震荡:

double alpha = 0.001;
for (int i = 0; i < epochs; i++) {
    // ... 参数更新逻辑

    // 每轮迭代后衰减学习率(比如乘以0.99)
    alpha *= 0.99;
}

3. 改用批量/小批量梯度下降

相比单样本SGD,批量梯度下降用所有样本的平均梯度更新参数,稳定性强很多,不容易发散:

void LinearRegression::gradientDescent(std::vector<OrderBookEntry>& ordersX, std::vector<OrderBookEntry>& ordersY) {
    double b0 = 0;
    double b1 = 0;
    double alpha = 0.001;
    int epochs = 200;
    int n = ordersX.size();

    // 特征归一化
    double min_x = ordersX[0].price;
    double max_x = ordersX[0].price;
    for (auto& entry : ordersX) {
        min_x = std::min(min_x, entry.price);
        max_x = std::max(max_x, entry.price);
    }
    std::vector<double> scaled_x;
    for (auto& entry : ordersX) {
        scaled_x.push_back((entry.price - min_x)/(max_x - min_x));
    }

    for (int i = 0; i < epochs; i++) {
        double sum_err_b0 = 0.0;
        double sum_err_b1 = 0.0;
        // 遍历所有样本计算总误差
        for (int j = 0; j < n; j++) {
            double p = b0 + b1 * scaled_x[j];
            double err = p - ordersY[j].price;
            sum_err_b0 += err;
            sum_err_b1 += err * scaled_x[j];
        }
        // 用平均梯度更新参数
        b0 -= alpha * (sum_err_b0 / n);
        b1 -= alpha * (sum_err_b1 / n);

        // 学习率衰减
        alpha *= 0.99;
    }

    // 计算最小误差(和你之前的逻辑保持一致)
    std::vector<double> error;
    for (int j = 0; j < n; j++) {
        double p = b0 + b1 * scaled_x[j];
        error.push_back(p - ordersY[j].price);
    }
    std::sort(error.begin(), error.end(), [](double a, double b) {
        return std::abs(a) < std::abs(b);
    });
    std::cout << "最终值: " << "B0=" << b0 << " " << "B1=" << b1 << " " << "error=" << error[0] << std::endl;
    std::cout << std::endl;
}

4. 添加溢出防护

可以在代码中加入判断,当参数出现inf时及时重置并降低学习率,避免直接走到nan:

// 参数更新后检查
if (std::isinf(b0) || std::isinf(b1)) {
    std::cout << "检测到参数溢出,降低学习率并重置参数" << std::endl;
    alpha *= 0.1;
    b0 = std::isinf(b0) ? 0 : b0;
    b1 = std::isinf(b1) ? 0 : b1;
}

总结

先做特征归一化消除量级差异,再调整学习率并添加衰减,最后换成批量梯度下降,这三步基本就能解决BTC/USDT和ETH/USDT的参数溢出与nan问题了。你可以先试试归一化+调小学习率,应该就能看到明显改善。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 07:51:06