GSL 中的多元线性回归是否正确?
Multiple linear regression in GSL is correct?
我正在尝试使用 GSL 执行多元线性回归。 beta 的估计量是 beta=(X'X)^(-1)X'y。使用了三种方法 -
- 直接,即使用所需的操作计算此公式的右侧;
- 求解X'Xb=X'y,即求解系统Ax=b,其中A=X'X,b=X'y,x=b;
- 使用函数 gsl_multifit_linear。测试数据来自here.
三种方法都给出了相同的错误结果:
beta1=0.0365505,beta2=0.0435827,alpha=0.645627。
相同的数据文件在 R 中产生正确的输出:
beta1=0.086409,beta2=0.087602,alpha=-4.1。
另一个数据集的结果(来自 here 的 WHO 预期寿命数据)在 GSL 和 R 之间也不同。
很可能我在某处出错了。但是,如果至少有人可以确认 GSL 多元线性回归是否正确工作,那就太好了。
编辑1。
语言是C++。
选项 1 的代码,即 beta=(X'X)^(-1)X'y
void mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//the function accepts vector of predictant values and matrix of predictands
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
//multiply X' by X
gsl_matrix*xxTranspose=gsl_matrix_alloc(m,m);
gsl_blas_dgemm(CblasTrans,CblasNoTrans,1.0,x,x,0.0,xxTranspose);
/////////////////////////////////
//perform LU decomposition of xxTranspose to find it's inverse
gsl_permutation*p=gsl_permutation_alloc(m);
int s;
gsl_linalg_LU_decomp(xxTranspose,p,&s);
//////////////////////////////
//compute inverse of xxTranspose matrix
gsl_matrix*xxTransposeInverse=gsl_matrix_alloc(m,m);
gsl_linalg_LU_invert(xxTranspose,p,xxTransposeInverse);
//////////////////////////////
//multiply inverse of xxTranspose matrix by xTranspose
gsl_matrix*xxTransposeInverseXtranspose=gsl_matrix_alloc(m,n);
gsl_blas_dgemm(CblasNoTrans,CblasTrans,1.0,xxTransposeInverse,x,0.0,xxTransposeInverseXtranspose);
//////////////////////////////////////
//multiply matrix (X'X)^(-1)X' and vector y; this must give values of beta
gsl_vector*b=gsl_vector_alloc(m);
gsl_blas_dgemv(CblasNoTrans,1.0,xxTransposeInverseXtranspose,y,0.0,b);
//write beta values to file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
////////////////////
}
选项2的代码,即求解系统X'Xbeta=X'y
oid mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
/////////////////////
//compute X'X
gsl_matrix*xxTranspose=gsl_matrix_alloc(m,m);
gsl_blas_dgemm(CblasTrans,CblasNoTrans,1.0,x,x,0.0,xxTranspose);
/////////////////////////////////
//compute X'y
gsl_vector*XtransposeY=gsl_vector_alloc(m);
gsl_blas_dgemv(CblasTrans,1.0,x,y,0.0,XtransposeY);
//////////////////////////////////////
//solve the linear system X'Xb=X'y to find coefficients beta
gsl_vector*b=gsl_vector_alloc(m);
int k=n;
if(m<n) {
k=m;
}
gsl_vector*tau=gsl_vector_alloc(k);
gsl_linalg_QR_decomp(xxTranspose,tau);
gsl_linalg_QR_solve(xxTranspose,tau,XtransposeY,b);
//write beta values into file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
////////////////////////////////
}
选项3的代码,即使用gsl_multifit_linear。
void mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
///////////////////////////
//Use gsl_multifit_linear
gsl_multifit_linear_workspace*w=gsl_multifit_linear_alloc(n,2);
double chisq;
gsl_matrix*cov=gsl_matrix_alloc(m,m);
gsl_vector*b=gsl_vector_alloc(m);
gsl_multifit_linear(x,y,b,cov,&chisq,w);
//////////////////////
//write beta values into file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
//////////////////////////
}
编辑2。
还要绝对确保正确读取输入数据,将以下代码添加到选项 3 代码中:
FILE*xyWrite;
xyWrite=fopen("molsInputData.dat","w");
for(int i=0;i<n;i++) {
fputs(to_string(gsl_vector_get(y,i)).c_str(),xyWrite);
fputs(" ",xyWrite);
fputs(to_string(gsl_matrix_get(x,i,0)).c_str(),xyWrite);
fputs(" ",xyWrite);
fputs(to_string(gsl_matrix_get(x,i,1)).c_str(),xyWrite);
fputs("\n",xyWrite);
}
此代码将 gsl_vector(s) x 和 y(用作输入)写入文件。然后将该文件加载到 R 中并执行多元线性回归。结果是正确的。证明输入数据正确读入
目前为gsl_multifit_linear
编写C驱动程序对我来说有点麻烦;据我所知,它必须来自 C 或 C++ 运行,因为 R 的 gsl
包似乎不包含此函数的包装器...
但是,按照您建议的两种方式(在 R 中)进行线性代数计算得到与 lm()
相同的答案:
m1 <- lm(Job_Perf~Mech_Apt+Consc, data=dd)
y <- dd$Job_Perf
X <- model.matrix(~Mech_Apt+Consc, data=dd)
cbind(lm=coef(m1),
solve1=c(solve(crossprod(X)) %*% t(X) %*% y),
solve2=c(solve(crossprod(X), t(X)%*%y)))
## lm solve1 solve2
## (Intercept) -4.10358123 -4.10358123 -4.10358123
## Mech_Apt 0.08640901 0.08640901 0.08640901
## Consc 0.08760164 0.08760164 0.08760164
我在手动实现回归时看到的最常见错误是忘记了 R 自动在模型矩阵中包含一个截距列,但是当您列出 alpha
估计时,我猜您没有犯那个错误...?
我最好的猜测是你设置 X
在某些方面不正确:它应该看起来像这样
(Intercept) Mech_Apt Consc
1 40 25
1 45 20
1 38 30
...
数据:
dd <- read.table(header=TRUE, text="
Job_Perf Mech_Apt Consc
1 40 25
2 45 20
1 38 30
3 50 30
2 48 28
3 55 30
3 53 34
4 55 36
4 58 32
3 40 34
5 55 38
3 48 28
3 45 30
2 55 36
4 60 34
5 60 38
5 60 42
5 65 38
4 50 34
3 58 38
")
我正在尝试使用 GSL 执行多元线性回归。 beta 的估计量是 beta=(X'X)^(-1)X'y。使用了三种方法 -
- 直接,即使用所需的操作计算此公式的右侧;
- 求解X'Xb=X'y,即求解系统Ax=b,其中A=X'X,b=X'y,x=b;
- 使用函数 gsl_multifit_linear。测试数据来自here.
三种方法都给出了相同的错误结果:
beta1=0.0365505,beta2=0.0435827,alpha=0.645627。
相同的数据文件在 R 中产生正确的输出:
beta1=0.086409,beta2=0.087602,alpha=-4.1。
另一个数据集的结果(来自 here 的 WHO 预期寿命数据)在 GSL 和 R 之间也不同。
很可能我在某处出错了。但是,如果至少有人可以确认 GSL 多元线性回归是否正确工作,那就太好了。
编辑1。 语言是C++。 选项 1 的代码,即 beta=(X'X)^(-1)X'y
void mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//the function accepts vector of predictant values and matrix of predictands
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
//multiply X' by X
gsl_matrix*xxTranspose=gsl_matrix_alloc(m,m);
gsl_blas_dgemm(CblasTrans,CblasNoTrans,1.0,x,x,0.0,xxTranspose);
/////////////////////////////////
//perform LU decomposition of xxTranspose to find it's inverse
gsl_permutation*p=gsl_permutation_alloc(m);
int s;
gsl_linalg_LU_decomp(xxTranspose,p,&s);
//////////////////////////////
//compute inverse of xxTranspose matrix
gsl_matrix*xxTransposeInverse=gsl_matrix_alloc(m,m);
gsl_linalg_LU_invert(xxTranspose,p,xxTransposeInverse);
//////////////////////////////
//multiply inverse of xxTranspose matrix by xTranspose
gsl_matrix*xxTransposeInverseXtranspose=gsl_matrix_alloc(m,n);
gsl_blas_dgemm(CblasNoTrans,CblasTrans,1.0,xxTransposeInverse,x,0.0,xxTransposeInverseXtranspose);
//////////////////////////////////////
//multiply matrix (X'X)^(-1)X' and vector y; this must give values of beta
gsl_vector*b=gsl_vector_alloc(m);
gsl_blas_dgemv(CblasNoTrans,1.0,xxTransposeInverseXtranspose,y,0.0,b);
//write beta values to file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
////////////////////
}
选项2的代码,即求解系统X'Xbeta=X'y
oid mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
/////////////////////
//compute X'X
gsl_matrix*xxTranspose=gsl_matrix_alloc(m,m);
gsl_blas_dgemm(CblasTrans,CblasNoTrans,1.0,x,x,0.0,xxTranspose);
/////////////////////////////////
//compute X'y
gsl_vector*XtransposeY=gsl_vector_alloc(m);
gsl_blas_dgemv(CblasTrans,1.0,x,y,0.0,XtransposeY);
//////////////////////////////////////
//solve the linear system X'Xb=X'y to find coefficients beta
gsl_vector*b=gsl_vector_alloc(m);
int k=n;
if(m<n) {
k=m;
}
gsl_vector*tau=gsl_vector_alloc(k);
gsl_linalg_QR_decomp(xxTranspose,tau);
gsl_linalg_QR_solve(xxTranspose,tau,XtransposeY,b);
//write beta values into file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
////////////////////////////////
}
选项3的代码,即使用gsl_multifit_linear。
void mols(vector <double> predictandVector,vector <vector <double> > predictorMatrix) {
//convert input vectors into gsl_vector
int n=predictandVector.size();
int m=predictorMatrix[0].size();
gsl_vector*y=gsl_vector_alloc(n);
gsl_matrix*x=gsl_matrix_alloc(n,m);
for(int i=0;i<n;i++) {
gsl_vector_set(y,i,predictandVector[i]);
for(int j=0;j<m;j++) {
gsl_matrix_set(x,i,j,predictorMatrix[i][j]);
}
}
///////////////////////////
//Use gsl_multifit_linear
gsl_multifit_linear_workspace*w=gsl_multifit_linear_alloc(n,2);
double chisq;
gsl_matrix*cov=gsl_matrix_alloc(m,m);
gsl_vector*b=gsl_vector_alloc(m);
gsl_multifit_linear(x,y,b,cov,&chisq,w);
//////////////////////
//write beta values into file
FILE*f;
f=fopen("molsResult.dat","w");
gsl_vector_fprintf(f,b,"%g");
//////////////////////////
}
编辑2。 还要绝对确保正确读取输入数据,将以下代码添加到选项 3 代码中:
FILE*xyWrite;
xyWrite=fopen("molsInputData.dat","w");
for(int i=0;i<n;i++) {
fputs(to_string(gsl_vector_get(y,i)).c_str(),xyWrite);
fputs(" ",xyWrite);
fputs(to_string(gsl_matrix_get(x,i,0)).c_str(),xyWrite);
fputs(" ",xyWrite);
fputs(to_string(gsl_matrix_get(x,i,1)).c_str(),xyWrite);
fputs("\n",xyWrite);
}
此代码将 gsl_vector(s) x 和 y(用作输入)写入文件。然后将该文件加载到 R 中并执行多元线性回归。结果是正确的。证明输入数据正确读入
目前为gsl_multifit_linear
编写C驱动程序对我来说有点麻烦;据我所知,它必须来自 C 或 C++ 运行,因为 R 的 gsl
包似乎不包含此函数的包装器...
但是,按照您建议的两种方式(在 R 中)进行线性代数计算得到与 lm()
相同的答案:
m1 <- lm(Job_Perf~Mech_Apt+Consc, data=dd)
y <- dd$Job_Perf
X <- model.matrix(~Mech_Apt+Consc, data=dd)
cbind(lm=coef(m1),
solve1=c(solve(crossprod(X)) %*% t(X) %*% y),
solve2=c(solve(crossprod(X), t(X)%*%y)))
## lm solve1 solve2
## (Intercept) -4.10358123 -4.10358123 -4.10358123
## Mech_Apt 0.08640901 0.08640901 0.08640901
## Consc 0.08760164 0.08760164 0.08760164
我在手动实现回归时看到的最常见错误是忘记了 R 自动在模型矩阵中包含一个截距列,但是当您列出 alpha
估计时,我猜您没有犯那个错误...?
我最好的猜测是你设置 X
在某些方面不正确:它应该看起来像这样
(Intercept) Mech_Apt Consc
1 40 25
1 45 20
1 38 30
...
数据:
dd <- read.table(header=TRUE, text="
Job_Perf Mech_Apt Consc
1 40 25
2 45 20
1 38 30
3 50 30
2 48 28
3 55 30
3 53 34
4 55 36
4 58 32
3 40 34
5 55 38
3 48 28
3 45 30
2 55 36
4 60 34
5 60 38
5 60 42
5 65 38
4 50 34
3 58 38
")