首页 > 解决方案 > 使用 Eigen SVD 进行线性回归

问题描述

我有一个超定的二维数据系统。我正在使用 Eigen 库来计算线性回归线。数据的形式为A x = b,其中A是一个 nx1 矩阵,b是一个 n 大小的向量。

当我运行 SVD 时,我计算了一个斜率,并且这条线穿过原点(即没有 Y 轴截距)。对于具有不通过原点的趋势线的数据,这不会导致我正在寻找的线。

这是一个例子:

//Eigen
#include <Eigen/Dense>
//std
#include <cstdlib>
#include <iostream>

int main() {
  
  Eigen::MatrixXd A(15,1);
  Eigen::VectorXd b(15);

  A << -4, -4, -4, -3, -3, -2, -2, -1, -1, -1, 0, 1, 1, 2, 2;
  b << 11.8, 10.9, 11.5, 9.6, 8.4, 7.4, 6.2, 4.8, 5.4, 4.5, 3.5, 1.5, 0.1, -0.5, -2;
  
  //Calculate the SVD and solve for the regression line
  Eigen::MatrixXd x = A.bdcSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
  Eigen::MatrixXd b_reg = A*x;

  std::cout << x << std::endl;
  std::cout << b_reg << std::endl;

  return EXIT_SUCCESS;
}

我预期的趋势线是 y = -2.079x + 2.907。我上面的程序报告x为-2.714,并且线穿过原点。

有没有一种简单的方法可以使用 SVD 来恢复“偏移”回归线?还是我应该使用 SVD 以外的东西?在这种情况下,什么?

标签: c++mathlinear-regressioneigensvd

解决方案


我今天有这个完全相同的问题,并让它与 Eigen 库一起工作。

Eigen 假设与您的问题相关的所有数据都编码在您传递的矩阵中。在您的情况下,您是在告诉 eigen 所有函数的形式为:

y = m*x

因为您的 A 矩阵是一维的。当然,您想要的是:

y = m*x + b

你怎么能让Eigen考虑到这一点?让我们以另一种形式重新编写它,因为您已经在代码中使用了传统线性代数格式的b :

b = p1*A + p2

其中 p1 和 p2 是您要求解的参数。如果您有 A 和 b 值的列表(您这样做了,这些是前 2 个方程中的 x 和 y 值),您可以用向量表示法将其写为:

Ap = b

其中p = {p1, p2} 和b = {b1, b2, b3... } (与您的数据一样多的条目)

现在想一想:如果p是一个 2x1 矩阵,b是一个 Nx1 矩阵(N = 你拥有的数据点的数量),那么A需要是什么维度?它必须是 Nx2。

“那么A的另一列是什么?” 你问?看一个案例:

A11 * p1 + A12 * p2 = b1

啊,但是等等,p2 是恒定的,并且是您要解决的 y 截距。所以:

A12 * p2 = p2

A22 * p2 = p2

A32 * p2 = p2

...

怎么会这样?如果A的第二列中的所有值都是 1。

所以...在您的代码中,将 A 设为 2 列矩阵,并用 1 填充第二列。结果将为您提供您正在寻找的两个参数。您可以通过此处文档中的示例输出值: JacobiSVD


推荐阅读