在Matlab中如何计算决定系数R^2和相关系数r
Problem
当你使用 polyfit
函数进行多项式拟合之后,你希望计算决定系数或者相关系数看看拟合效果如何。聪明的你肯定觉得聪明的 Matlab 的 polyfit
函数的返回值中会有 \(R^2\) 或者 \(r\) 吧。你尝试 disp
了一下,发现有一个结构体 \(S\)。再查一查帮助文档,发现误差估计结构体 \(S\) 中只有一个范德蒙德矩阵 \(R\)、自由度 \(df\) 和残差的范数 \(normr\),并没有你想要的 \(R^2\) 或者 \(r\)。
Solution
很遗憾,我们还是需要手动计算这两个系数。
假设X
是原始数据自变量,Y
是原始数据因变量,我们先进行多项式拟合:
p = polyfit(X, Y, n); % n是多项式次数
Y_pre = polyval(p,X);
得到了Y_pre
为多项式拟合后的预测值。
决定系数R-squared的计算
我们使用如下公式计算\(R^2\):
代码如下:
SSerr = sum((Y_pre - Y).^2); % 残差平方和
SStot = sum((Y - mean(Y)).^2); % 总平方和
R_squared = 1 - (SSerr / SStot); % R-squared
相关系数r的计算
计算相关系数\(r\),可以使用corrcoef
函数先计算相关系数矩阵,取其非对角线元素的值。
代码如下:
r = corrcoef(Y_pre, Y);
disp(r(1,2))
Others
\(r\)(相关系数)和 \(R^2\)(决定系数,也称为R-squared)是可以用于衡量数据的不同的方面的两个不同的统计量。
Calculation
Comparison
- 相关系数 \(r\in[-1,1]\):衡量两个变量之间线性关系的强度和方向。
- \(r = 1\) 表示完全正相关。
- \(r = -1\) 表示完全负相关。
- \(r = 0\) 表示没有线性相关。
- 决定系数 \(R^2\in[0,1]\):衡量模型对因变量变异的解释程度。
- R² = 1 表示模型完美地解释了数据的变异。
- R² = 0 表示模型没有解释数据的任何变异。
R² 衡量模型拟合优度的指标,告诉我们模型对数据变异的解释程度有多好。而相关系数 r 仅仅告诉我们两个变量之间线性关系的强度,它并不对模型拟合优度全面评估。
如果想要更全面的评估,通常会看 \(R^2\) 。
如果只关心两个变量之间是否有线性关系,看相关系数 \(r\)。
后续
补充于2024-7-31
但是有时候会出现 \(R^2<0\) 的情况。等等,为什么 \(R^2\) 会小于零?它不是 \(r\) 的平方吗?
当出现拟合效果特别差的时候,就有可能会出现(?)
今天我们在研读一篇论文的时候,遇到了“多元线性回归”。而由于题目背景,有些小组疑惑是否要规定常数项为 0。假如使用 Matlab 中的多元线性回归函数 regress
的话,当 X
不存在全为 1 的一列时,会出现报错:
警告: R 方和 F 统计量的定义不良,除非 X 有一列全部为 1。
键入 "help regress" 了解详细信息。
同时,如果硬要输出 regress
返回值中的 stat(1)
的话,会发现 \(R^2\) 可能是一个负数。(演示代码见附录)
实际上这是因为 \(R^2\) 的定义不同导致的。
-
范德蒙德矩阵
[b,bint,r,rint,stats]=regress(Y,X,0.05); fprintf("R^2=stats(1)=%f\n",stats(1));
输出 R^2=stats(1)=-0.381201
,为负数。
-
\(1-\frac{ESS}{TSS}\)
Y_pre=X*b; ESS=sum((Y_pre-Y).^2); TSS=sum((Y-mean(Y)).^2); fprintf("R^2=1-ESS/TSS=%f\n",1-ESS/TSS);
输出
R^2=1-ESS/TSS=-0.381201
,结果与范德蒙德矩阵结果一致。 -
\(\frac{RSS}{TSS}\)
RSS=sum((Y_pre-mean(Y)).^2); fprintf("R^2=RSS/TSS=%f\n",RSS/TSS);
输出
R^2=RSS/TSS=3.746787
,为正数。 -
\(r^2\)
r = corrcoef(Y_pre, Y); fprintf("r=corrcoef()(1,2)=%f=>r^2=%f\n",r(1,2),(r(1,2)).^2);
输出
r=corrcoef()(1,2)=0.869397=>r^2=0.755851
,为正数。
以上。
References
polyfit and R^2 value - MATLAB Answers - MATLAB Central (mathworks.cn)
相关系数 - MATLAB corrcoef - MathWorks 中国
Code
X_data=[120 73 180 80 125 125 81.1000000000000 90
133.020000000000 73 180 80 125 125 81.1000000000000 90
129.630000000000 73 180 80 125 125 81.1000000000000 90
158.770000000000 73 180 80 125 125 81.1000000000000 90
145.320000000000 73 180 80 125 125 81.1000000000000 90
120 78.5960000000000 180 80 125 125 81.1000000000000 90
120 75.4500000000000 180 80 125 125 81.1000000000000 90
120 90.4870000000000 180 80 125 125 81.1000000000000 90
120 83.8480000000000 180 80 125 125 81.1000000000000 90
120 73 231.390000000000 80 125 125 81.1000000000000 90
120 73 198.480000000000 80 125 125 81.1000000000000 90
120 73 212.640000000000 80 125 125 81.1000000000000 90
120 73 190.550000000000 80 125 125 81.1000000000000 90
120 73 180 75.8570000000000 125 125 81.1000000000000 90
120 73 180 65.9580000000000 125 125 81.1000000000000 90
120 73 180 87.2580000000000 125 125 81.1000000000000 90
120 73 180 97.8240000000000 125 125 81.1000000000000 90
120 73 180 80 150.710000000000 125 81.1000000000000 90
120 73 180 80 141.580000000000 125 81.1000000000000 90
120 73 180 80 132.370000000000 125 81.1000000000000 90
120 73 180 80 156.930000000000 125 81.1000000000000 90
120 73 180 80 125 138.880000000000 81.1000000000000 90
120 73 180 80 125 131.210000000000 81.1000000000000 90
120 73 180 80 125 141.710000000000 81.1000000000000 90
120 73 180 80 125 149.290000000000 81.1000000000000 90
120 73 180 80 125 125 60.5820000000000 90
120 73 180 80 125 125 70.9620000000000 90
120 73 180 80 125 125 64.8540000000000 90
120 73 180 80 125 125 75.5290000000000 90
120 73 180 80 125 125 81.1000000000000 104.840000000000
120 73 180 80 125 125 81.1000000000000 111.220000000000
120 73 180 80 125 125 81.1000000000000 98.0920000000000
120 73 180 80 125 125 81.1000000000000 120.440000000000];
X=X_data;
Y=Y_data(:,1);
[b,bint,r,rint,stats]=regress(Y,X,0.05);
fprintf("R^2=stats(1)=%f\n",stats(1));
Y_pre=X*b;
ESS=sum((Y_pre-Y).^2);
TSS=sum((Y-mean(Y)).^2);
fprintf("R^2=1-ESS/TSS=%f\n",1-ESS/TSS);
RSS=sum((Y_pre-mean(Y)).^2);
fprintf("R^2=RSS/TSS=%f\n",RSS/TSS);
r = corrcoef(Y_pre, Y);
fprintf("r=corrcoef()(1,2)=%f=>r^2=%f\n",r(1,2),(r(1,2)).^2);