机器学习-SVM的使用心得

             机器学习-SVM的使用心得

    亲爱的炼丹师,各位数据游侠,人生苦短,我们都要用python.这是我第一次使用csdn博客,可能格式啥的还不算太清楚,如果有写的不好的地方还请多多包涵。还麻烦大家点个赞,就是那种假装我写的很好的样子。
之前看过很多楼主的文章,很少有通过具体的实践来实现自己的目标,所以自己写了篇文章来作为自己的笔记,更多的是分享自己的经验,让各位道友们少走点弯路。话不多说,一些基本的SVM知识网上各大教程应有尽有,我不过多的介绍,主要我们这儿还是以实践为主。

              第一部分:数据集的介绍

    由于这是项目组的数据集,所以我不便公开啦,还希望大家理解 。我的数据集格式,行代表样本量(由于项目还在进行中,所以数据量暂时还是比较少的啦,到现在也才70多个样本)。列代表特征数(我这里的特征由12个传感器组合而成,每个传感器可以收集到5个特征,一共是60个特征),至于我的标签,因为我做的是4分类的问题,所以我的标签是1,2,3,4.每行都有一个标签与之相对应,说太多不如来一张图解决下我的文字解释。如下图: 在这里插入图片描述

              第二部分:特征工程(可直接跳过)

    特征工程是决定模型好坏的直接原因,或者首要条件,如果特征工程都做不好的话,后面的分类还有回归将无从谈起,因此这一步的重要性不亚于后面的调参。说到这里,我顺便提一下,其实第一部分所看到的数据集其实已经是我加工好的了,刚开始拿到的原始数据比较乱,在此在提取特征的时候,笔者是自己手写的一段代码实现的,由于该工作和我的方向有关,因此读者可以自行忽略这一部分,当然,这一实现也很简单,并没有很多的逻辑在里面。在此,我展示下我的部分特征提取的代码(这一部分可以直接忽略)

import pandas as pd
from pylab import *    #支持中文
import numpy as np
mpl.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams[ 'axes.unicode_minus' ] = False

data=pd.read_csv("F:\电子鼻\项目组数据新\整理好的数据/0801/传感器A.csv",engine="python")

a=[str(i) for i in range(1,13)]
data=data[a]

x1=data[0:12601]
y1=range(0,12601)

gap=30
time=300

avg_list=[]
cursor=1622+150
for m in range(1,37):     
    avg1=np.mean(data[cursor+time*(m-1):cursor+gap+time*(m-1)]) #对应配气
    avg2=np.mean(data[cursor+120+time*(m-1):cursor+120+gap+time*(m-1)]) #对应响应
    avg_list.append(avg2-avg1)
    #avg_list.append((avg2-avg1)/avg1)

#avg_list=avg_list[0:-1] 
#print(avg_list)
pd.DataFrame(avg_list).to_csv("稳1.csv")
#pd.DataFrame(avg_list).to_csv("稳2.csv")   

当然机器学习包里(sklearn)有一个对数据进行标准化处理的方法(Standarscalar),此方法不需要你自己手动编写程序,让数据进行归一化,标准化。导入的方式也很简单,这里不过多的解释,下面代码会有。 在这里插入图片描述

                第三部分:模型的选择

    有点机器学习基础的可能听说过很多分类器,比如随机森林,集成算法,向量机。。。。当然在此我得提前说明下,因为我的大目标是做分类的,并且是有监督,这些词大家应该不会陌生吧,至于什么叫分类与回归,有监督和无监督有啥区别,话跳到原来的地方,你可以先去看一看机器学习的基础,在这儿我就不细讲了。
             在这里插入图片描述
    我在项目中选择的机器学习方法是SVM(向量机),至于为啥选这个?我个人的理解:分类精度高,,并且SVM也是很普遍的实现方法,再加上sklearn机器学习的包,可以成功的摇身转变为"调包侠"。缺点也比较明显:速度可能没有达到那些预期的那样,其次可解释性也没那么强。在此可能有人会问,仅仅是用了SVM算法实现了该分类嘛?笔者在此说明下,我也同样用了其他一些方法(比如xgboost,随机森林。。。。),但是导师的要求让我用SVM,后面还会用到神经网络,卷积神经网络等等。当然,这些模型都搭好了,由于数据量少的可怜,所以后面的等有了数据再写吧。因为本文章主要是对SVM的实践,话不多说,直接上码:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC

data = pd.read_csv('F:\电子鼻\项目组数据新\数据集/训练集.csv',engine="python")

X = data.loc[:, data.columns != "0"]
Y = data.loc[:, data.columns == "0"]

x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2,random_state = 0)
std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)
model = SVC()

model.fit(x_train, y_train)
y_predict = model.predict(x_test)
#print(y_predict)
print("验证集上的准确率:", model.score(x_test, y_test))
print("训练集上的准确率:", model.score(x_train, y_train))

    我大概解释下我这代码:导入必要的包之后,第一步用panda读取数据,这里注意后面一行,engine=" “,很多时候不加这个,pandas是读取不了的,当然这里还有其他一些参数(比如:你想选用指定的列,可以使用uescools=” "),你可以根据自己的需求,自行百度,这里也不一一介绍了。下面X和Y分别对应数据集和标签。再往下使用到了train_test_split()划分数据集的方法,我这里划分成了训练集80%,验证集20%。至于后面的random_state,如果你设置了数字,代表固定的顺序,相当于你每次运行代码结果都不会改变,一旦去掉这个random_state,每次他都是随机划分的,也就代表每次的运行结果可能不太一样。再往下就是StandardScaler,称之为标准化方法,下面不过多介绍。再往后就是选用svm的方法拟合模型了,也不过多的介绍了。

                第四部分:调参

    这一部分在我看来可能是一个关键的核心点,也是个难点,尤其是对于初学者。当我们确定下来一个模型(分类器)的时候,初学者可能一顿操作猛如虎,被现实揍成二百五的那种(手动滑稽)。在此,我以SVM举例:常见的做法为了测试集的准确率,拼了老命的加惩罚,什么?不够,继续加,最后导致模型的崩溃。举个简单的例子:怎么提高孩子的学习成绩,拼命的给他增加练习册,各种习题,让他适应各种题,也就是所谓的题海战术。这样导致的结果就是:可能孩子只会死板教条的学,只掌握了题目的表面,当题目一变型,或者出现一个新题型,他还是不会做。因此选择合适的惩罚系数(练习册的数量)才可以让孩子举一反三。说了这么多,无非就是想说明,参数的好坏对模型的预测起着核心的作用,当然特征工程也是一个很重要的一个因素。在第三部分,我们的参数是默认的,这里因为笔者写的SVM,所以主要说下对SVM影响最大的两个参数(默认为C=1,gamma=1/60(特征数)),分别为:C(惩罚系数,即对误差的宽容度。c越高,说明越不能容忍出现误差,容易过拟合(只会自己做过的题目,而不能应对新的题目,举一反三)。C越小,容易欠拟合(书上的题目都没做会,相当于考试考相同的题目,你都不会做,更别提新的题目了。)。C过大或过小,泛化能力变差),gamma(“决定了数据映射到新的特征空间后的分布,gamma越大,支持向量越少(高斯分布长得又高又瘦),gamma值越小,支持向量越多(高斯分布长得又矮又胖,搓是实锤了(狗头保命))。支持向量的个数影响训练与预测的速度。” 因此选择合适的C和g便成了一个问题,等等,刚才说到哪儿了???
调参,那就先来看一下默认的c和g的结果。

测试集上的准确率: 0.8
验证集上的准确率: 0.8771929824561403

    明显的感觉预测的效果虽然不至于很糟糕,但是也不是那么的好。下一步就是调参了,常见的方法是网格搜索法,这里笔者也不过多的介绍,有兴趣的可以和我交流,我这里采取的经验调参,当然也用网格验证过了,没啥区别,毕竟数据不多。在这儿,我这里默默的加了点惩罚,将C提高到了5,再看看最后的结果如何。在此说明下参数g的选择在下面会讲到,耐心点听我一一道来。如图,加了惩罚的结果。

测试集上的准确率: 0.9333333333333333
验证集上的准确率: 0.9649122807017544

哇,飙升到了93%哎!!!
大功告成,感觉自己萌萌哒?
等等,你这个准确率是真的准确率嘛??
神马??你刚才不是说调参,你现在跟我说这个不是真的准确率? 在这里插入图片描述
其实,我想说的是:我们的参数确定好了,怎么知道我们的模型是否过拟合呢?毫无疑问,交叉验证当仁不让的首选,在此我将交叉验证和学习曲线结合了起来,在此,我们先看下我的代码:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import preprocessing
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import learning_curve
from sklearn.model_selection import validation_curve   #可视化学习的整个过程
from sklearn.model_selection import cross_val_score  #交叉验证

data = pd.read_csv('F:\电子鼻\项目组数据新\数据集/训练集.csv',engine="python")

#print(data)
X = data.loc[:, data.columns != "0"]
Y = data.loc[:, data.columns == "0"]

x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2,random_state = 0)

std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)

#model = SVC(C=200, cache_size=50, class_weight=None, coef0=0.0,decision_function_shape='ovr', degree=3, gamma=0.13, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True,tol=0.001, verbose=False)
model = SVC()
model.fit(x_train, y_train)
y_predict = model.predict(x_test)
#print(y_predict)
print("验证集上的准确率:", model.score(x_test, y_test))
print("训练集上的准确率:", model.score(x_train, y_train))

#case1:学习曲线
#构建学习曲线评估器,train_sizes:控制用于生成学习曲线的样本的绝对或相对数量
train_sizes,train_scores,test_scores=learning_curve(model,X=X,y=Y,train_sizes=np.linspace(0.1,1.0,4),cv=10)
#统计结果
train_mean= np.mean(train_scores,axis=1)
train_std = np.std(train_scores,axis=1)
test_mean =np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
#绘制效果
plt.plot(train_sizes,train_mean,color='blue',marker='o',markersize=5,label='training accuracy')
plt.fill_between(train_sizes,train_mean+train_std,train_mean-train_std,alpha=0.15,color='blue')
plt.plot(train_sizes,test_mean,color='green',linestyle='--',marker='s',markersize=5,label='Cross-validation')
plt.fill_between(train_sizes,test_mean+test_std,test_mean-test_std,alpha=0.15,color='green')
plt.grid()
plt.xlabel('Number of training samples')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
#plt.ylim([0.8,1.0])
plt.show()

前面的一部分我就不过多解释了,后面learning_curve调用学习曲线(常用的验证曲线是否过拟合方法)的方法,后面cv=10,代表我们采用10折交叉验证的方法,再下面就是画图。看看我们的曲线是否过拟合呢??如图:
         在这里插入图片描述
咦???怎么准确率变成了80%多点,刚才不是93%嘛,还有,这曲线明显的过拟合了呀??
             在这里插入图片描述
    再回到我刚才说到的话:准确率是真的准确率嘛,在这里,我自己的理解:刚才93%只是代表特定顺序下,准确率为93%,举个简单的例子:班上10个同学,2个成绩比较差,8个成绩比较好,按照数据集的摆放形式,前2个为成绩差的,后8个为成绩好的,最后抽取到的20%的偏偏就是2个成绩好的,结果当然比较好(也就对应着93%)。现在,交叉验证的目的就是把这几个人分成几批,根据每批次的结果求平均,这样法网恢恢,疏而不漏,差生毫无疑问会拉低全班的平均分(后来的80%多),但是这成绩哪个更具有代表性,或者代表这个班级的水平,结果不用我说了吧。所以,这里我宁可相信最后的准确率就是80多了一点。至于原来没调参的,自己可以去尝试下,交叉验证下来是没有80%多的,这边就一带而过了。
    好了,刚才解决了准确率的问题,现在改解决过拟合的问题了。为啥会出现这个现象,笔者分析:由于我的数据集比较惨淡,目前总共才70多个样本,要分4类,臣妾是真的做不到啊!但是通过曲线可以发现,随着数据的增加,结果也会变得越来越好,所以出现过拟合目前也很正常。
    说到这儿,是不是又感觉大功告成了,你还忘了个哥们(g在向你挥手呢,老哥!)
话不多说,还是直接上码:

import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
from sklearn import preprocessing
from sklearn.svm import SVC
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.model_selection import learning_curve
from sklearn.model_selection import validation_curve   #可视化学习的整个过程
from sklearn.model_selection import cross_val_score  #交叉验证

data = pd.read_csv('F:\电子鼻\项目组数据新\数据集/训练集.csv',engine="python")

#print(data)
X = data.loc[:, data.columns != "0"]
Y = data.loc[:, data.columns == "0"]

x_train, x_test, y_train, y_test = train_test_split(X, Y, test_size=0.2,random_state = 0)

std = StandardScaler()
x_train = std.fit_transform(x_train)
x_test = std.transform(x_test)

#model = SVC(C=200, cache_size=50, class_weight=None, coef0=0.0,decision_function_shape='ovr', degree=3, gamma=0.13, kernel='rbf', max_iter=-1, probability=False, random_state=None, shrinking=True,tol=0.001, verbose=False)
model = SVC(C=5)
model.fit(x_train, y_train)
y_predict = model.predict(x_test)
#print(y_predict)
print("验证集上的准确率:", model.score(x_test, y_test))
print("训练集上的准确率:", model.score(x_train, y_train))

#case2:验证曲线,验证曲线validation Curve:评估参数和指标的关系
param_range=[0.001,0.01,0.1,1.0,10.0]
#10折,验证正则化参数C
train_scores,test_scores =validation_curve(model,X=x_train,y=y_train,param_name='gamma',param_range=param_range,cv=5)

#统计结果
train_mean= np.mean(train_scores,axis=1)
train_std = np.std(train_scores,axis=1)
test_mean =np.mean(test_scores,axis=1)
test_std=np.std(test_scores,axis=1)
plt.plot(param_range,train_mean,color='blue',marker='o',markersize=5,label='training accuracy')
plt.fill_between(param_range,train_mean+train_std,train_mean-train_std,alpha=0.15,color='blue')
plt.plot(param_range,test_mean,color='green',linestyle='--',marker='s',markersize=5,label='test accuracy')
plt.fill_between(param_range,test_mean+test_std,test_mean-test_std,alpha=0.15,color='green')
plt.grid()
plt.xscale('log')
plt.xlabel('Parameter g')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')
#plt.ylim([0.8,1.0])
plt.show()

结果怎么样呢?如图:
          在这里插入图片描述
     我们g默认是啥的?1/60约为0.016,和我们的最佳0.01几乎差不多,如果你想要更加细微的调参数g,可以把param_range这个参数里面的范围划分的更细腻点,说到这里,我们的调参工作终于大功告成了。说明:此结果并非最后结果,只是分享了下我的调参方法,人嘛,还是需要多留给你发挥的余地的,充分发挥自己的主观能动性。                  在这里插入图片描述

                第五部分:保存模型

首先导入以下的包:

from sklearn.externals import joblib

最后保存模型,其实很简单:

joblib.dump(model, 'model.pkl')

                 在这里插入图片描述
写到这里,也很累了,只要你能学到东西,也不枉费撸了几个小时的字了。有兴趣的可以和我一起交流,欢迎大家的指正,最后,那个。。。。。?
                 在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值