支持向量机
支持向量机(Support Vector Machine)为机器学习经典的有监督学习的算法,主要用于分类问题。如图,直观理解,要使的分类最为准确,那么需要找到最近的边界的点(Support Vector),使得Margin值最大,这也是SVM命名的由来

SVM优点: 1.对小样本集、非线性数据集和高维空间有较好的效果 2.准确率很高 3.自带L2正则化,一定程度减少过拟合 4.维数大于样本数情况有效,比如文本分类
SVM缺点:1.大量数据集训练时间比较长,如果特征和数据量均较大,可放弃,运行时间过长 2.不适用大型数据集 3.数据集有较多噪声时,SVM效果不好
硬间隔(hard margin):如果数据是线性可分的,存在超平面将数据完全分割开
软间隔(soft margin):有些噪点数据是线性不可分的,如果落在硬间隔内,为了最小化误差,一个新的正则化参数,添加了松弛变量,将模型的容忍度变大,容忍一些异常点,如下图,软间隔实际上是合叶损失函数+正则化项,一定程度上可以减少过拟合情况

对偶函数,通过对SVM目标原函数转化成对偶函数,一方面是可以引入核函数,另一方面,对偶化问题一定是凸优化问题,满足KKT条件凸优化必要条件,即局部最优解亦是全局最优解
核函数是将低维空间数据转换成高维数据,如图,二维的数据通过核函数转换成三维,当我们是二维无法通过线性分割,转换成3维明显可以透过超平面进行分割

常见核函数
1.线性核函数(Linear Kernel)最基本核函数,在处于大型稀疏数据量使用,常用于文本分类,已有文献证明线性核是RBF退化版,线性内核不会比调整过的RBF内核具有更加准确,但是数据速度快,a.当特征数大于样本数,选择线性核函数;b.当样本数小于特征数,选择高斯内核;c.如果样本数超过50000使用高斯内核速度会变慢,这时倾向于选择线性核函数
2.高斯函数(Gaussian Kernel)没有数据的先验知识时使用,内核服从正态分布
3.Gaussian radial basis function (RBF)常用内核,引入基于权重平方范数正则化项的惩罚
4.多项式函数(Polynomial kernel)是多项形式表现的核函数
5.双曲正切核神经网络中使用
6.sigmoid核回归问题、神经网络使用
本次的数据集选取的是天池的金融数据分析赛题1(随便选的,实际上不适合SVM分类),由于涉及较多的类别变量,编码采用One-Hot编码与label编码,当Categorical数据没有关系,比如各个省之间,不能青海省比江苏省那个好,变量之间没有关系,我们使用one-hot编码(one-hot编码注意虚拟陷阱,防止变量之间线性表出,完全共线),否则我们选label编码,比如学历,小学、初中、大专、高中、大学、硕士、博士,基于label encoding最合适不过了,下图为各个变量

import numpy as np
import pandas as pd
pd.set_option('display.max_columns', None)
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.model_selection import GridSearchCV
train = pd.read_csv("train.csv")
test = pd.read_csv("test.csv")
df=pd.concat([train,test])
df.info()

dicts_job={"unknown":0,"unemployed":1,"student":2,"housemaid":3,"retired":4,'self-employed':5,'blue-collar':6,'services':7,'admin.':8,
'technician':9,'management':10,'entrepreneur':11}
df[["job"]]=df["job"].map(dicts_job)
dicts_mar = {"unknown":0,'single':1,'divorced':2,'married':3}
df[["marital"]]=df["marital"].map(dicts_mar)
dicts_poutcome = {"nonexistent":0,'failure':1,'success':2}
df[["poutcome"]]=df["poutcome"].map(dicts_poutcome)
df['poutcome'].value_counts()
dicts_default = {"yes":0,'unknown':1,'no':2}
df[["default"]]=df["default"].map(dicts_default)
dicts_loan = {"unknown":0,'no':1,'yes':2}
df[["loan"]]=df["loan"].map(dicts_loan)
dicts_education = {"unknown":0,'illiterate':1,'basic.4y':2,'basic.6y':3,'basic.9y':4,'high.school':5,\
'university.degree':6,'professional.course':7}
df[["education"]]=df["education"].map(dicts_education)
dicts_housing = {"unknown":0,'yes':1,'no':2}
df[["housing"]]=df["housing"].map(dicts_housing)
dicts_cell = {"telephone":0,'cellular':1}
df[["contact"]]=df["contact"].map(dicts_cell)
dicts_subscribe= {"no":0,'yes':1}
df[["subscribe"]]=df["subscribe"].map(dicts_subscribe)
df = pd.get_dummies(df,columns=['month','day_of_week'],drop_first=True)
X_train = df[df['subscribe'].notnull()]
y_train = X_train['subscribe']
X_train = df[df['subscribe'].notnull()].drop(['subscribe','id'],axis=1)
scaler = StandardScaler()
X_test = df[df['subscribe'].isnull()].drop(['subscribe','id'],axis=1)
X_train = scaler.fit_transform(X_train)
X_test = scaler.transform(X_test)
SVM建模,这边原本为网格搜索,程序运行时间让人怀疑人生,最后贴代码,仅演示几个常见参数
svc=SVC()
svc.fit(X_train,y_train)
y_pred=svc.predict(X_test)
data = pd.DataFrame(y_pred,columns=['label'])
data['label'].value_counts()
0.0 7201
1.0 299
Name: label, dtype: int6
linear_svc=SVC(kernel='linear', C=1.0)
linear_svc.fit(X_train,y_train)
y_pred=linear_svc.predict(X_test)
data = pd.DataFrame(y_pred,columns=['label'])
data['label'].value_counts()
0.0 7311
1.0 189
Name: label, dtype: int64
svc=SVC(C=10.0,gamma=0.4)
svc.fit(X_train,y_train)
y_pred=svc.predict(X_test)
data = pd.DataFrame(y_pred,columns=['label'])
data['label'].value_counts()
0.0 7399
1.0 101
Name: label, dtype: int64
以上的分类结果和天池baseline有差距,天池采用的是lightgbm算法,无论是从数据量和特征数量,选择集成算法应该更有效
下面为网格搜索代码
svc=SVC()
parameters = [ {'C':[1, 10, 100, 1000], 'kernel':['linear']},
{'C':[1, 10, 100, 1000], 'kernel':['rbf'], 'gamma':[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]},
]
grid_search = GridSearchCV(estimator = svc,
param_grid = parameters,
scoring = 'accuracy',
cv = 5,
verbose=0)
grid_search.fit(X_train, y_train)