Alex_McAvoy

想要成为渔夫的猎手

支持向量回归

References:

【引入】

支持向量机是针对二分类问题提出的,其通过最大化间隔来找到一个分离超平面,使得绝大多数样本点位于两个决策边界的外侧

支持向量回归(Support Vector Regression)是支持向量机的一种改进,用于解决回归问题,其同样是考虑最大化间隔,但是考虑的是两个决策边界之间的点,使尽可能多的样本点位于间隔内

换句话说,SVM 要使超平面到最近的样本点的间隔最大,SVR 则要使超平面到最远的样本点的间隔最小

【假设形式】

对于给定的容量为 n 的训练集 D={(x1,y1),(x2,y2),,(xn,yn)},第 i 组样本中的输入 xi 具有 m 个特征值,即:xi=(xi(1),xi(2),,xi(m))Rm,输出 yiY,支持向量机学习到的模型为 f(x)=ωx+θ,使得 f(xi)yi

假设能容忍 f(xi)yi 间最多有 ε 的偏差,即仅当 f(xi)yi 之间差距的绝对值大于 ε 时才计算损失,这相当于以 f(x) 为中心,构建了一个宽度为 2ε 的间隔带,若训练样本落于该间隔带,则认为预测正确

由此,可给出支持向量回归的优化问题:

minω,θ12||ω||22s.t.|yi(ωxi+θ)|ε,i=1,2,,n

其中,ε>0 是间隔带大小

通过求解最优化问题,可以得到超平面:

S:ωx+θ=0

以及相应的回归函数:

f(x)=ωx+θ

【原始问题】

为每个样本点 (xi,yi) 引入松弛变量 ξiξi^,即每个样本点分别到两个决策边界的距离

此时,支持向量回归的优化问题可写为:

minω,θ,ξi,ξi^12||ω||22+Ci=1n(ξi+ξi^)s.t.yi(ωxi+θ)ε+ξi(ωxi+θ)yiε+ξi^ξi0ξi^0,i=1,2,,n

即为支持向量回归的原始问题,其中,C 为正则化常数

可以发现,支持向量回归只对间隔外的样本进行惩罚,当样本点位于间隔内,不计算其损失

【对偶问题】

对偶问题的转化

为求解支持向量回归的原始问题:

minω,θ,ξi,ξi^12||ω||22+Ci=1n(ξi+ξi^)s.t.yi(ωxi+θ)ε+ξi(ωxi+θ)yiε+ξi^ξi0ξi^0,i=1,2,,n

应用拉格朗日对偶性,通过求解对偶问题来得到原始问题的最优解

首先,构建拉格朗日函数,即为每个不等式约束引入拉格朗日乘子 λi0λi^0μi0μi^0,即:

L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=12||ω||22+Ci=1n(ξi+ξi^)+i=1nλi(yi(ωxi+θ)εξi)+i=1nλi^((ωxi+θ)yiεξi^)i=1nμiξii=1nui^ξi^

其中,λ=(λ1,λ2,,λn)Tλ^=(λ1^,λ2^,,λn^)Tμ=(μ1,μ2,,μn)Tμ^=(μ1^,μ2^,,μn^)T 为拉格朗日乘子向量

此时,根据拉格朗日对偶性,原始问题的对偶问题就变为极大极小问题,即:

maxλ,λ^,μ,μ^minω,θ,ξ,ξ^L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)

因此,为了得到对偶问题的解,就要先求拉格朗日函数 L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)ωθξξ^ 的极小,再求对 λλ^μμ^ 的极大

对偶问题中的极小问题

对于对偶问题中的极小问题:

minω,θ,ξ,ξ^L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)

令拉格朗日函数 L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^) 分别对 ωθξξ^ 求偏导,并令其等于 0,即:

ωL(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=ωi=1n(λiλi^)xi=0θL(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=i=1n(λiλi^)=0ξiL(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=Cλiμi=0ξi^L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=Cλi^μi^=0

可得:

ω=i=1n(λiλi^)xii=1n(λiλi^)=0C=λi+μiC=λi^+μi^

将上式带回拉格朗日函数 L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^) 中,有:

L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=12||ω||22+Ci=1n(ξi+ξi^)+i=1nλi(yi(ωxi+θ)εξi)+i=1nλi^((ωxi+θ)yiεξi^)i=1nμiξii=1nui^ξi^=12i=1nj=1m(λiλi^)(λjλj^)xixj+i=1n(Cξi+Cξi^)+i=1nλiyii=1nλiωxiθi=1nλiεi=1nλii=1nλiξii=1nλi^yi+i=1nλi^ωxi+θi=1nλi^εi=1nλi^i=1nλi^ξi^i=1nμiξii=1nui^ξi^=12i=1nj=1m(λiλi^)(λjλj^)xixji=1n(λiλi^)ωxi+i=1n(λiλi^)yiθi=1n(λiλi^)εi=1n(λi+λi^)+i=1n((λi+μi)ξi+(λi^+μi^)ξi^)i=1n(μiξi+λiξi+λi^ξi^+ui^ξi^)=12i=1nj=1m(λiλi^)(λjλj^)xixj+i=1n(λiλi^)yiεi=1n(λi+λi^)

故有:

minω,θ,ξ,ξ^L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)=12i=1nj=1m(λiλi^)(λjλj^)xixj+i=1n(λiλi^)yiεi=1n(λi+λi^)

对偶问题中的极大问题

对于对偶问题中的极大问题:

maxλ,λ^,μ,μ^minω,θ,ξ,ξ^L(ω,θ,ξ,ξ^,λ,λ^,μ,μ^)

即为对偶问题,有:

maxλ,λ^12i=1nj=1m(λiλi^)(λjλj^)xixj+i=1n(λiλi^)yiεi=1n(λi+λi^)s.t.i=1n(λiλi^)=00λi,λi^C,i=1,2,,n

假设上述的对偶问题对 λλ^ξξ^ 的一个解为 λ=(λ1,λ2,,λn)Tλ^=(λ1^,λ2^,,λn^)Tξ=(ξ1,ξ2,,ξn)Tξ^=(ξ1^,ξ2^,,ξn^)T

可以发现,对偶问题满足 KKT 条件,即:

λi(ωx+θ)yiεξi)=0λi^(ωx+θ)yiεξi^)=0λiλi^=0ξiξi^=0(Cλi)ξi=0(Cλi^)ξi^=0

故而有:

ω=i=1n(λiλi^)xi

可以看出,当且仅当 (ωx+θ)yiεξi=0 时,λi 可取非零值,当且仅当 (ωx+θ)yiεξi^=0 时,λi^ 可取非零值,换言之,仅当样本 (xi,yi) 不落于 ε 间隔带时,相应的 λiλi^ 才可取非零值

此外,约束 (ωx+θ)yiεξi=0(ωx+θ)yiεξi^=0 不能同时成立,否则有 ξi=ξi^=ε,因此 λiλi^ 中至少有一个为零,即 λiλi^

而对于每个样本 (xi,yi),都有 (Cλi)ξi=0(ωx+θ)yiεξi=0,于是在得到 λi 后,若存在 0<λi<C,那么必有 ξi=0,进而对此 i 有:

θ=yi+εj=1n(λiλi^)xjxi

理论上来说,可以任意选取满足 0<λi<C 的样本,通过上式得到 θ,但在实际应用中,常选取所有的满足 0<λi<C 的样本,求取相应的 θ 后求其平均值 θ

故而,当 λiλi^0 时,有回归函数:

f(x)=i=1n(λiλi^)(xix)+θ

【非线性支持向量回归】

对于回归函数:

f(x)=i=1n(λiλi^)(xix)+θ

若考虑到非线性问题,可以参照非线性支持向量机的思路,使用核方法进行特征构建,引入核函数即可,故非线性 SVR 可表示为:

f(x)=i=1n(λiλi^)K(xi,x)+θ

关于核函数,详见:特征构建与核方法

【sklearn 实现】

线性支持向量回归

以 sklearn 中的波士顿房价数据集为例,实现线性支持向量回归

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.svm import LinearSVR
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score

# 特征提取
def deal_data():
boston = load_boston() # sklearn的波士顿房价数据集
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['result'] = boston.target
data = np.array(df)
return data[:, :-1], data[:, -1]

# 模型训练
def train_model(features, labels):
# 建立线性支持向量回归模型
model = LinearSVR(random_state=0, tol=1e-05)

# 训练
model.fit(features, labels)
return model

# 模型评估
def estimate_model(y_true, y_pred):
MSE = mean_squared_error(y_true, y_pred)
RMSE = np.sqrt(MSE)
MAE = mean_absolute_error(y_true, y_pred)
R2 = r2_score(y_true, y_pred)
indicators = {"MSE": MSE, "RMSE":RMSE, "MAE":MAE, "R2":R2}
return indicators

# 可视化
def visualization(y_true, y_pred, model):
# 绘图
plt.plot(range(y_true.shape[0]), y_true, "b-")
plt.plot(range(y_true.shape[0]), y_pred, "r-.")
plt.legend(["original value", "predicted value"])
plt.xlabel("samples", fontsize="15")
plt.ylabel("y", fontsize="15")

plt.show()

if __name__ == "__main__":
# 特征提取
x, y = deal_data()

# 简单交叉验证
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=0)

# 模型训练
model = train_model(x_train, y_train)

# 预测结果
y_pred = model.predict(x_test) # predict()输入输出均为二维
print("y test:", y_test[:10]) # 测试集y值
print("y pred:", y_pred[:10]) # 预测y值

# 模型评估
indicators = estimate_model(y_test, y_pred)
print("MSE:", indicators["MSE"])
print("RMSE:", indicators["RMSE"])
print("MAE:", indicators["MAE"])
print("R2:", indicators["R2"])

# 可视化
visualization(y_test, y_pred, model)

非线性支持向量回归

以 sklearn 中的波士顿房价数据集为例,实现线性支持向量回归

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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.svm import SVR
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_squared_error
from sklearn.metrics import mean_absolute_error
from sklearn.metrics import r2_score

# 特征提取
def deal_data():
boston = load_boston() # sklearn的波士顿房价数据集
df = pd.DataFrame(boston.data, columns=boston.feature_names)
df['result'] = boston.target
data = np.array(df)
return data[:, :-1], data[:, -1]

# 模型训练
def train_model(features, labels):
# 建立非线性SVR模型
# kernel可选:
# - linear:线性核函数,与LinearSVR效果一致,但速度较慢
# - poly:多项式核函数,gamma为多项式的系数,degree为多项式的次数,coef0为多项式截距
# - rbf:高斯核函数,gamma为1/2σ
# - sigmoid:sigmoid核函数,coef0为多项式截距
model = SVR(kernel='rbf', degree=3, C=1.0, epsilon=0.2)

# 训练
model.fit(features, labels)
return model

# 模型评估
def estimate_model(y_true, y_pred):
MSE = mean_squared_error(y_true, y_pred)
RMSE = np.sqrt(MSE)
MAE = mean_absolute_error(y_true, y_pred)
R2 = r2_score(y_true, y_pred)
indicators = {"MSE": MSE, "RMSE":RMSE, "MAE":MAE, "R2":R2}
return indicators

# 可视化
def visualization(y_true, y_pred, model):
# 绘图
plt.plot(range(y_true.shape[0]), y_true, "b-")
plt.plot(range(y_true.shape[0]), y_pred, "r-.")
plt.legend(["original value", "predicted value"])
plt.xlabel("samples", fontsize="15")
plt.ylabel("y", fontsize="15")

plt.show()

if __name__ == "__main__":
# 特征提取
x, y = deal_data()

# 简单交叉验证
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3,random_state=0)

# 模型训练
model = train_model(x_train, y_train)

# 预测结果
y_pred = model.predict(x_test) # predict()输入输出均为二维
print("y test:", y_test[:10]) # 测试集y值
print("y pred:", y_pred[:10]) # 预测y值

# 模型评估
indicators = estimate_model(y_test, y_pred)
print("MSE:", indicators["MSE"])
print("RMSE:", indicators["RMSE"])
print("MAE:", indicators["MAE"])
print("R2:", indicators["R2"])

# 可视化
visualization(y_test, y_pred, model)
感谢您对我的支持,让我继续努力分享有用的技术与知识点!
0 comments
Anonymous
Markdown is supported

Be the first person to leave a comment!