如何使用c ++获得线性回归线的斜率?

god*_*lla 7 c++ math linear-regression

我需要获得类似于以下链接中的excel函数实现方式的线性回归:

http://office.microsoft.com/en-gb/excel-help/slope-function-HP010342903.aspx
Run Code Online (Sandbox Code Playgroud)

是否有一个C++库或一个人创建的简单编码解决方案可以做到这一点?我已经根据这个公式实现了代码,但它并不总能给我正确的结果(取自这里http://easycalculation.com/statistics/learn-regression.php)....

Slope(b) = (N?XY - (?X)(?Y)) / (N?X2 - (?X)2)
         = ((5)*(1159.7)-(311)*(18.6))/((5)*(19359)-(311)2)
         = (5798.5 - 5784.6)/(96795 - 96721)
         = 13.9/74
         = 0.19 
Run Code Online (Sandbox Code Playgroud)

如果我对下面的向量进行尝试,我会得到错误的结果(我应该期待0.305556):x = 6,5,11,7,5,4,4 y = 2,3,9,1,8,7 ,5

提前致谢

Cas*_*eri 21

这是一个C++ 11实现:

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

double slope(const std::vector<double>& x, const std::vector<double>& y) {
    const auto n    = x.size();
    const auto s_x  = std::accumulate(x.begin(), x.end(), 0.0);
    const auto s_y  = std::accumulate(y.begin(), y.end(), 0.0);
    const auto s_xx = std::inner_product(x.begin(), x.end(), x.begin(), 0.0);
    const auto s_xy = std::inner_product(x.begin(), x.end(), y.begin(), 0.0);
    const auto a    = (n * s_xy - s_x * s_y) / (n * s_xx - s_x * s_x);
    return a;
}

int main() {
    std::vector<double> x{6, 5, 11, 7, 5, 4, 4};
    std::vector<double> y{2, 3, 9, 1, 8, 7, 5};
    std::cout << slope(x, y) << '\n';  // outputs 0.305556
}
Run Code Online (Sandbox Code Playgroud)

您可以为数学要求添加测试(x.size() == y.size()并且x不是常量),或者,如上面的代码,假设用户将负责这一点.


Qué*_*dre 16

你为什么不写这样一个简单的代码(不是最好的解决方案,当然,只是一个基于帮助文章的例子):

double slope(const vector<double>& x, const vector<double>& y){
    if(x.size() != y.size()){
        throw exception("...");
    }
    double n = x.size();

    double avgX = accumulate(x.begin(), x.end(), 0.0) / n;
    double avgY = accumulate(y.begin(), y.end(), 0.0) / n;

    double numerator = 0.0;
    double denominator = 0.0;

    for(int i=0; i<n; ++i){
        numerator += (x[i] - avgX) * (y[i] - avgY);
        denominator += (x[i] - avgX) * (x[i] - avgX);
    }

    if(denominator == 0){
        throw exception("...");
    }

    return numerator / denominator;
}
Run Code Online (Sandbox Code Playgroud)

请注意,accumulate函数的第三个参数必须是0.0而不是0,否则编译器会将其类型推断为int,并且很有可能累积调用的结果将是错误的(使用MSVC2010和mingw-w64时传递0实际上是错误的作为第三个参数).


The*_*ist 6

以下是我用于线性回归(拟合)的模板化函数.它需要std :: vector作为数据

template <typename T>
std::vector<T> GetLinearFit(const std::vector<T>& data)
{
    T xSum = 0, ySum = 0, xxSum = 0, xySum = 0, slope, intercept;
    std::vector<T> xData;
    for (long i = 0; i < data.size(); i++)
    {
        xData.push_back(static_cast<T>(i));
    }
    for (long i = 0; i < data.size(); i++)
    {
        xSum += xData[i];
        ySum += data[i];
        xxSum += xData[i] * xData[i];
        xySum += xData[i] * data[i];
    }
    slope = (data.size() * xySum - xSum * ySum) / (data.size() * xxSum - xSum * xSum);
    intercept = (ySum - slope * xSum) / data.size();
    std::vector<T> res;
    res.push_back(slope);
    res.push_back(intercept);
    return res;
}
Run Code Online (Sandbox Code Playgroud)

该函数返回一个向量,第一个元素是斜率,第二个元素是线性回归的截距.

使用它的示例:

std::vector<double> myData;
myData.push_back(1);
myData.push_back(3);
myData.push_back(4);
myData.push_back(2);
myData.push_back(5);

std::vector<double> linearReg = GetLinearFit(myData);
double slope = linearReg[0];
double intercept = linearReg[1];
Run Code Online (Sandbox Code Playgroud)

请注意,该函数假设您的x轴有一系列数字(这就是我需要的).如果您愿意,可以在函数中更改它.