SVM真的是很复杂的算法,原本以为原理看懂了实现就会很简单,然而事实并不是这样
sklearn中对于支持向量机提供了很多模型:LinearSVC
, LinearSVR
, NuSVC
, NuSVR
, SVC
, SVR
用于分类,用libsvm实现,参数如下:
1/n_features
(不是很懂)one vs one
,’ovr’表示one vs rest
。(多分类)模型训练结束后,可以使用下列参数:
LinearSVC(Linear Support Vector Classification)线性支持向量机,核函数是 linear
,不是基于libsvm实现的
参数:
squared_hinge(默认)
, squared_hinge
l1
, l2
nsamples>nfeatures
时dual=false
1e - 3
根据前面的参数,线性SVM有两种方式实现
LinearSVC(C)
SVC(C=1, kernel="linear"
使用鸢尾花数据的前两列,方便画图
iris = datasets.load_iris()
data = iris.data
target = iris.target
X = X[y<2, :2] # 只取前两列
y = y[y<2] # 只取前两类
plt.scatter(X[y==0,0], X[y==0, 1], color="red") # 所有0类的点,用红色
plt.scatter(X[y==1,0], X[y==1, 1], color="blue") # 所有1类的点,用蓝色
归一化处理:
# 对X进行归一化处理
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(X)
X_stand = scaler.transform(X)
使用LinearSVC分类
from sklearn.svm import LinearSVC
linearsvc = LinearSVC(C=1e9)
linearsvc.fit(X_stand, y)
# LinearSVC(C=1000000000.0, class_weight=None, dual=True, fit_intercept=True,
# intercept_scaling=1, loss='squared_hinge', max_iter=1000,
# multi_class='ovr', penalty='l2', random_state=None, tol=0.0001,
# verbose=0)
结果如下,linearsvc.coef_
是所有特征的权重,linearsvc.intercept_
是斜率(线性分类)
print(linearsvc.coef_) # w,所有x 的权值
print(linearsvc.intercept_) # b,
# 结果是数组,可能是多分类吧,等我研究了多分类再来看
画出决策边界,这函数不是很好懂。。很久才看明白。
meshgrid()
返回了有两个向量定义的方形空间中的所有点的集合。x0是x值,x1是y的值ravel()
将向量拉成一行c_[]
将向量排列在一起contourf()
等高线(没想到还能这样用)def plot_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),# 600个,影响列数
np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),# 600个,影响行数
)
# x0 和 x1 被拉成一列,然后拼接成360000行2列的矩阵,表示所有点
X_new = np.c_[x0.ravel(), x1.ravel()] # 变成 600 * 600行, 2列的矩阵
y_predict = model.predict(X_new) # 二维点集才可以用来预测
zz = y_predict.reshape(x0.shape) # (600, 600)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
# print(X_new)
plot_decision_boundary(linearsvc, axis=[-3, 3, -3, 3])
plt.scatter(X_stand[y==0,0], X_stand[y==0,1])
plt.scatter(X_stand[y==1,0], X_stand[y==1,1])
plt.show()
添加上下边界:
f(x,y) = w[0]x1 + w[1]x2 + b
是决策函数的形式。+1(或-1) = w[0]x1 + w[1]x2 + b
就是上下边界的表达式def plot_svc_decision_boundary(model, axis):
x0, x1 = np.meshgrid(
np.linspace(axis[0], axis[1], int((axis[1]-axis[0])*100)).reshape(-1, 1),# 600个,影响列数
np.linspace(axis[2], axis[3], int((axis[3]-axis[2])*100)).reshape(-1, 1),# 600个,影响行数
)
# x0 和 x1 被拉成一列,然后拼接成360000行2列的矩阵,表示所有点
X_new = np.c_[x0.ravel(), x1.ravel()] # 变成 600 * 600行, 2列的矩阵
y_predict = model.predict(X_new) # 二维点集才可以用来预测
zz = y_predict.reshape(x0.shape) # (600, 600)
from matplotlib.colors import ListedColormap
custom_cmap = ListedColormap(['#EF9A9A','#FFF59D','#90CAF9'])
plt.contourf(x0, x1, zz, linewidth=5, cmap=custom_cmap)
# 我终于看懂了!!!!!
w = model.coef_[0]
b = model.intercept_[0]
index_x = np.linspace(axis[0], axis[1], 100)
# f(x,y) = w[0]x1 + w[1]x2 + b
# 1 = w[0]x1 + w[1]x2 + b 上边界
# -1 = w[0]x1 + w[1]x2 + b 下边界
y_up = (1-w[0]*index_x - b) / w[1]
y_down = (-1-w[0]*index_x - b) / w[1]
x_index_up = index_x[(y_up<=axis[3]) & (y_up>=axis[2])]
x_index_down = index_x[(y_down<=axis[3]) & (y_down>=axis[2])]
y_up = y_up[(y_up<=axis[3]) & (y_up>=axis[2])]
y_down = y_down[(y_down<=axis[3]) & (y_down>=axis[2])]
plt.plot(x_index_up, y_up, color="black")
plt.plot(x_index_down, y_down, color="black")
def svc_plot(model, axis=[-3, 3, -3, 3], X_stand, y):
plot_svc_decision_boundary(model, axis=[-3, 3, -3, 3])
plt.scatter(X_stand[y==0,0], X_stand[y==0,1])
plt.scatter(X_stand[y==1,0], X_stand[y==1,1])
plt.show()
常数C越大,容错空间越小,上下边界越远;常数C越小,容错空间越大,上下边界越远。当C缩小到0.01时,上下边界已经很远了。
# C越小,容错空间越大上下边界应该更远,是的就是这样
linearsvc = LinearSVC(C=0.01)
linearsvc.fit(X_stand, y)
svc_plot(model=linearsvc,axis=[-3, 3, -3, 3], X_stand=X_stand, y=y)
这里可以手动使用 PolynomialFeature
将数据升维,再用LinearSVC进行分类。也可以直接使用SVC指定多项式核函数,即:
LinearSVC
,需要用PolynomialFeatures
升维SVC()
指定kernel=poly
使用sklearn自带的moon数据
moons = datasets.make_moons(noise=0.15)
X = moons[0]
y = moons[1]
plt.scatter(X[y==0,0], X[y==0, 1])
plt.scatter(X[y==1,0], X[y==1, 1])
使用LinearSVC分类,使用pipeline封装一下
from sklearn.preprocessing import PolynomialFeatures
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler
# 使用Pipeline的一条龙服务
def PolynomialSVC(degree, C=1.0):
return Pipeline([
("poly", PolynomialFeatures(degree=degree)),
("std_scaler", StandardScaler()),
("linearSVC", LinearSVC(C=C))
])
poly_svc = PolynomialSVC(degree=3)
poly_svc.fit(X, y)
poly_svc.predict(X)
plot_decision_boundary(poly_svc, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
使用多项式核函数分类:
def PolynomialSVC(degree, C=1):
return Pipeline([
("std_scaler", StandardScaler()),
("linearSVC", SVC(kernel="poly", C=C))
])
poly_svc2 = PolynomialSVC(3)
poly_svc2.fit(X,y)
plot_decision_boundary(poly_svc2, axis=[-1.5, 2.5, -1.0, 1.5])
plt.scatter(X[y==0,0], X[y==0,1])
plt.scatter(X[y==1,0], X[y==1,1])
我也不知道,为什么训练结果不太一样。而且多项式核函数还可以加参数gamma
,而多项式核函数中并没有gamma这个参数。。奇怪。
def SVC_(kernel="rbf", gamma=1):
return Pipeline([
("std_scaler", StandardScaler()),
("linearSVC", SVC(kernel="rbf", gamma=gamma))
])
svc = SVC_(kernel="rbf", gamma=0.7)
svc.fit(X_stand, y)
plot_decision_boundary(svc, [-3,3,-3,3])
plt.scatter(X_stand[y==0,0], X_stand[y==0,1])
plt.scatter(X_stand[y==1,0], X_stand[y==1,1])
改一下gamma的参数,
svc = SVC_(kernel="rbf", gamma=100)
svc.fit(X_stand, y)
plot_decision_boundary(svc, [-3,3,-3,3])
plt.scatter(X_stand[y==0,0], X_stand[y==0,1])
plt.scatter(X_stand[y==1,0], X_stand[y==1,1])
没想到还能用在回归上,伪造一个三阶函数的数据集:
x = np.linspace(0, 3, 50)
y = x * x + 10 + np.random.uniform(0,2,50)
x = x.reshape(-1,1)
plt.scatter(x,y)
from sklearn.svm import SVR
linear_svr = SVR(kernel="linear")
poly_svr = SVR(kernel="poly", degree=4)
rbf_svr = SVR(kernel="rbf")
linear_svr.fit(x,y)
poly_svr.fit(x,y)
rbf_svr.fit(x,y)
print(linear_svr.coef_, linear_svr.intercept_) # [[2.62357607]] [10.14231851]
画出三个模型
x_test = np.linspace(0,3,100).reshape(-1,1)
plt.scatter(x,y, color="green")
plt.plot(x_test, linear_svr.predict(x_test), color="red", label="linear")
plt.plot(x_test, poly_svr.predict(x_test), color="blue", label="poly")
plt.plot(x_test, rbf_svr.predict(x_test), color="black", label="rbf")
plt.legend()
借鉴自下面两位大佬的文章: