上一次修改时间:2018-06-26 20:29:52

支持向量机SVM-代码

说明:数据同Logistic回归

# python 2.7    python 2.7    python 2.7  
#import必要的模块
import pandas as pd
import numpy as np

from sklearn.model_selection import GridSearchCV

from sklearn import metrics
from sklearn.metrics import accuracy_score

from matplotlib import pyplot
import seaborn as sns
%matplotlib inline

读取数据&数据探索

#读取数据
dpath = './logistic/'
train = pd.read_csv(dpath + "Otto_train_test.csv")
train.head()

image.png

train.info()

image.png......

#各属性的统计特性
train.describe()

image.png

# Target 分布,查看各类样本分布是否均衡
# 当各类样本数量不均衡时,交叉验证对分类任务要采用StratifiedKFold,即在每折采样时根据各类样本按比例采样,
# 交叉验证的代码中缺省的就是StratifiedKFold
sns.countplot(train.target)
pyplot.xlabel('target')
pyplot.ylabel('Number of occurrences')

image.png

特征编码

# 将类别字符串变成数字
y_train = train['target'] #形式为Class_x
y_train = y_train.map(lambda s: s[6:])
y_train = y_train.map(lambda s: int(s) - 1)
 
train = train.drop(["id" , "target"] , axis = 1)
X_train = np.array(train)

数据预处理

# 数据标准化
from sklearn.preprocessing import StandardScaler
# 初始化特征的标准化器
ss_X = StandardScaler()
# 分别对训练和测试数据的特征进行标准化处理
X_train = ss_X.fit_transform(X_train)
# 因采用的是交叉验证,所以没有划分出训练数据和测试数据
#X_test = ss_X.transform(X_test)

模型训练

# 训练样本大时,交叉验证太慢,用train_test_split估计模型性能
from sklearn.model_selection import train_test_split
X_train_part , X_val , y_train_part , y_val = train_test_split(X_train , y_train , random_state=33 , test_size=0.2)

default SVC

#线性SVM
from sklearn.svm import LinearSVC

SVC1 = LinearSVC().fit(X_train_part , y_train_part)
#在校验集上测试,估计模型性能
y_predict = SVC1.predict(X_val)

print("sklearn中线性SVM的默认参数: \n%s:\n模型分类结果\n%s\n" % (SVC1 , metrics.classification_report(y_val , y_predict)))
print("混淆矩阵 :\n %s" % (metrics.confusion_matrix(y_val , y_predict)))

out:

image.png

image.png

混淆矩阵对角线性上是分类分对的样本,非对角线上的是分错的样本,比如矩阵的第一行,第一个4表示:该4个样本点应该是第一类,分类判断也是第一类(分类正确),矩阵第一行最后面的5则表示:这5个样本应该是第一类的,但却被分成了第9类; 模型分类结果中: precision(查准率)表示被模型的预测结果中,每类预测正确的样本数/每类预测的总数,如混淆矩阵中的第一列,第一列的总数为4+1+6=11,表示模型将141个样本的11个分成了第一类,其中第一行第一列的4,表示这4个样本是第一类,且被分到了第一类(分类正确),第9行第一列的6,表示有6个第9类的样本数被模型错分到了第一类,第7行第一列的1同理,因此,第一类的查准率为4/4+1+6 = 0.36; recall(查全率)表示用于模型预测的数据中,每类预测对的数量/每类实际的总数,如混淆矩阵中的第一列表示用于模型预测中的数据中,第一类样本的总数为4+4+5=13,分对的为4,为错的为4+5,因此查全率为4/4+4+5=0.31; f1-score是precision和recall的加权平均,计算公式为:f1 = 2(precisionrecall) / (precision+recall);

线性SVM正则参数调优

线性SVM LinearSVC中,需要调整的正则超参数包括:C(正则系数,一般在log域(取log后的值)均匀设置候选参数),penalty(正则函数L2/L1); 参数确定的方式采用交叉验证,网格搜索步骤同Logistic回归的正则参数处理类似;这里用校验集(X_val , y_val)来估计模型性能;

def fit_grid_point_Linear(C , X_train , y_train , X_val , y_val):
    #在训练集利用SVC训练
    SVC2 = LinearSVC(C = C)
    SVC2 = SVC2.fit(X_train , y_train)
    
    #在校验集上返回accuracy
    accuracy = SVC2.score(X_val , y_val)
    
    print("accuracy:{}".format(accuracy))
    return accuracy
#需要调优的参数
C_s = np.logspace(-4 , 3 , 7)#logspace(a , b , N)把10的a次方到10的b次方分成N个等比数列
penalty_s = ['l1' , 'l2']

accuracy_s = []
for j , penalty in enumerate(penalty_s):
    tmpArr = []
    for i , oneC in enumerate(C_s):
        tmp = fit_grid_point_Linear(oneC , X_train , y_train , X_val , y_val)
        tmpArr.append(tmp)
    accuracy_s.append(tmpArr)
       
x_axis = np.log10(C_s)

for j , penalty in enumerate(penalty_s):
    pyplot.plot(x_axis , np.array(accuracy_s[j]) , '2-')
   
pyplot.legend()
pyplot.xlabel('log(C)')
pyplot.ylabel('accuracy')
pyplot.savefig('SVM_Otto.png')

pyplot.show()

out:

image.png

image.png

RBF核SVM正则参数调优

RBF核是SVM最常用的核函数(没有之一)。RBF核SVM的需要调整正则超参数包括C(正则系数,一般在log域(取log后的值)均匀设置候选参数)和核函数的宽度gamma; 参数确定的方式采用交叉验证,网格搜索步骤同Logistic回归的正则参数处理类似;这里用校验集(X_val , y_val)来估计模型性能;

from sklearn.svm import SVC
def fit_grid_point_RBF(C , gamma , X_train , y_train , X_val , y_val):
    
    #在训练集利用SVC训练
    SVC3 = SVC(C = C , kernel='rbf' , gamma = gamma)
    SVC3 = SVC3.fit(X_train , y_train)
    
    #在校验集上返回accuracy
    accuracy = SVC3.score(X_val , y_val)
    
    print("accuracy:{}".format(accuracy))
    return accuracy
#需要调优的参数
C_s = np.logspace(-2 , 2 ,5)#logspace(a , b , N)把10的a次方到10的b次方区间等分成N份
gamma_s = np.logspace(-2 , 2 , 3)

accuracy_s = []

for i , oneC in enumerate(C_s):
    for j , gamma in enumerate(gamma_s):
        tmp = fit_grid_point_RBF(oneC , gamma , X_train , y_train , X_val , y_val)
        accuracy_s.append(tmp)

out:

image.png

实际运行中,可以将从已运行的结果查看参数是否合适,不合适时,可以停止模型,重新设置参数; gamma越大,对应RBF核的sigma越小,决策边界更复杂,可能发生了过拟合,所以要调小gamma值;

# 绘制结果
number_C = len(C_s)
number_gamma = len(gamma_s)

#np中才有array函数,作用是将python中的list转换成array,reshape(a , b)函数则是将array分成一个a行b行的多维数组
accuracy_s1 = np.array(accuracy_s).reshape(number_C , number_gamma)

x_axis = np.log10(C_s)
#accuracy_s1[: , j]是取accuracy_s1数组中的第j列
for j , gamma in enumerate(gamma_s):
    pyplot.plot(x_axis , np.array(accuracy_s1[: , j]) , label = 'gamma' + str(gamma))
    
pyplot.legend()
pyplot.xlabel('log(C)')
pyplot.ylabel('accuracy')
pyplot.savefig('RBF_SVM_Otto.png')

pyplot.show()

image.png