抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

线性回归

用线性函数 f(x)=wx+bf(\bold x) = \bold w^{\top} \bold x + b 去拟合一组数据 D={(x1,y1),(x2,y2),...,(xn,yn)}D = \{(\bold x_1, y_1), (\bold x_2, y_2), ..., (\bold x_n, y_n)\},并且使得损失(cost function) J=1ni=1n(f(xi)yi)2J = \frac{1}{n}\sum_{i = 1}^n (f(\bold x_i) - y_i)^2 最小。

线性回归带来的过拟合问题

20170815210301014 (510×268)

Lasso回归和岭回归

Lasso 回归和岭回归(ridge regression)都是在标准线性回归的基础上修改 cost function,为了解决过拟合问题。

Lasso 的全称为 least absolute shrinkage and selection operator,又译最小绝对值收敛和选择算子、套索算法。

Lasso 回归对 JJ 加入 L1 正则化,其 cost function 如下:

J=1ni=1n(f(xi)yi)2+λw1J = \frac{1}{n}\sum_{i = 1}^n (f(\bold x_i) - y_i)^2 + \lambda \|w\|_1

其中 λw1=λj=1nwj\lambda||w||_1=\lambda \sum_{j=1}^n |w_j|

岭回归对式(2)加入 L2 正则化,其 cost function 如下:

J=1ni=1n(f(xi)yi)2+λw22J = \frac{1}{n}\sum_{i = 1}^n (f(\bold x_i) - y_i)^2 + \lambda \|w\|_2^2

其中 λw22=λj=1nwj2\lambda||w||_2^2=\lambda \sum_{j=1}^n w_j^2

其中,通俗来讲,最后一项正则化的加入使得程序不会让 ww 变得过于复杂,对过于复杂的 ww 进行惩罚。

约束范围

img

实例

image-20230117161337808

1
2
3
4
5
6
7
8
9
10
11
12
13
0.002 0.05 //两个参数
10 2
1.1 1.1
1.4 1.5
1.7 1.8
1.7 1.7
1.8 1.9
1.8 1.8
1.9 1.8
2.0 2.1
2.3 2.4
2.4 2.5
16.3 16.8 19.2 18.0 19.5 20.9 21.1 20.9 20.3 22.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include "matrix.h"
#include "euclid.h"
using namespace std;
Matrix<long double>X[20],Y,w;
long double res[20];
int n,m;
long double lambda=0.01;
Matrix<long double>grad(){
Matrix<long double>gw(1,m+1);
for (int j=1;j<=m+1;++j){
for (int i=1;i<=n;++i){
gw[1][j]+=2*X[i][1][j]*res[i]/n;
}
gw[1][j]+=2*lambda*w[1][j];//岭回归加上这一项
if (w[1][j]>0) gw[1][j]+=2*lambda;
if (w[1][j]<0) gw[1][j]-=2*lambda;//Lasso回归加上这一项
}
return gw;
}
int main(){
double alpha=0.03;
cin>>lambda>>alpha;
cin>>n>>m;
for (int i=1;i<=n;++i) X[i].resize(1,m+1);
Y.resize(n,1);
w.resize(1,m+1);
for (int i=1;i<=n;++i){
X[i][1][1]=1;
for (int j=1;j<=m;++j) cin>>X[i][1][j+1];
}
for (int i=1;i<=n;++i) cin>>Y[i][1];
int iter=50000;
while (iter--){
long double J=0;
for (int i=1;i<=n;++i){
res[i]=(X[i]&w)-Y[i][1];
J+=res[i]*res[i];
}
J/=n;
w=w-alpha*grad();
}
//数据统计部分
long double J=0;
for (int i=1;i<=n;++i){
res[i]=(X[i]&w)-Y[i][1];
cout<<res[i]<<endl;
J+=res[i]*res[i];
}
J/=n;
cout<<J<<endl;
cout<<w<<endl;
}

可以得到 10.9051 6.10542 -1.33797 之类的结果,和原数据比较接近。

(中间调参过程比较玄学)

评论