c++ - 使用 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 以外的东西?在这种情况下,什么?
解决方案
我今天有这个完全相同的问题,并让它与 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
推荐阅读
- mongodb - 尝试为特定用户更改我的 MongoDB 数据库中的某个字段
- java - 为 facebook 受众网络实施插页式广告的问题
- java - 为每个新用户创建新文档
- ruby - 找不到命令“rvm”,您的意思是:
- spring-kafka - 在 Spring Cloud Stream 中使用 StreamBridge 的问题
- python-3.x - python烧瓶会话不更新
- firebase - 添加应用插件时出错:'com.google.gms.google-services'
- ssl - 带有代理的 Web 请求是否总是需要新的连接?
- c# - 无法理解 IdentityTokenLifetime 以及我的 JWT 持续多长时间
- java - 具有许多占位符的 ItemStack