svm实操小案例

前言

上一篇文章 SVM原理推导(课堂笔记及思路整理)
我们探索了hard margin SVM和 soft margin SVM的底层原理。
相信大家对乘法系数 C 和高斯分布的方差 gamma 会有更深刻的理解。本文从一个小案例用sklearn包来实现已下用SVM来分类。
(数据集来源于网上,侵删, 具体在哪我也不知道)

本文链接: https://blog.csdn.net/weixin_43850253/article/details/109713755
数据集下载(.zip文件中就一个train.csv文件而已): 点我下载 https://gitee.com/chen_shu_ming/some_exe/raw/master/machineLearningdata/train.zip
这里说明一下,train.csv文件来源于网上,仅用于学习用途,侵删。还有文件虽然叫train.csv,但是为了给大家演示已下如何分训练集和测试集,还是会把train.csv中的数据给划分成训练集和测试集的。这里只有800多条数据,所以压缩包很小,只有20.6KB。

本文内容是根据泰坦尼克号上乘客的性别 年龄 舱位级别等信息预测乘客是否生还。
另外强烈建议大家动手实现一下,动手做印象才会比较深刻。跟着敲也会有进步的!



准备工作

  • 具有 python 和 pip 的环境
  • 下载sklearn, numpy, pandas, matplotlib
pip install sklearn
pip install numpy
pip install pandas
pip install matplotlib

如果没有配置镜像的同学可以看我另一篇博客: pip镜像管理和npm镜像管理。配置完镜像后下载速度提升一般是几个数量级的(当然还收到您网速的影响)



开始做实验啦

在pycharm中使用Scientific Mode.
在这里插入图片描述然后我们就可以用 # %%分隔运行了。
运行只要点击 # %%左边的绿色小三角形或者在你要运行的区域按ctrl + Enter键即可。
在这里插入图片描述


在正式开始试验之前,我们先来说说数据预处理的部分。

(由于我代码已经处理好所以你们运行示例代码的时候不会出现这种情况)
数据预处理这块要根据具体的项目具体分析。工作量在整个数据挖掘过程中占比还蛮大的。
这里举个简单例子,我们

# %%
print(train_X.info())
print(train_Y)

看到Age只有496个非空, 小于训练集的数据个数623个,说明Age是需要被处理的。
在这里插入图片描述
出现这个问题和我们处理数据的方式和顺序有关,比如说这里我们应该先处理好Initail那一列,再去处理Age

data['Initial'].replace(
   ['Mlle', 'Mme', 'Ms', 'Dr', 'Major', 'Lady', 'Countess', 'Jonkheer', 'Col', 'Rev', 'Capt', 'Sir', 'Don'],
  ['Miss', 'Miss', 'Miss', 'Mr', 'Mr', 'Mrs', 'Mrs', 'Other', 'Other', 'Other', 'Mr', 'Mr', 'Mr'], inplace=True)
  
data.loc[(data.Age.isnull()) & (data.Initial == 'Mr'), 'Age'] = 33
data.loc[(data.Age.isnull()) & (data.Initial == 'Mrs'), 'Age'] = 36
data.loc[(data.Age.isnull()) & (data.Initial == 'Master'), 'Age'] = 5
data.loc[(data.Age.isnull()) & (data.Initial == 'Miss'), 'Age'] = 22
data.loc[(data.Age.isnull()) & (data.Initial == 'Other'), 'Age'] = 46

data['Initial'].replace(['Mr', 'Mrs', 'Miss', 'Master', 'Other'], [0, 1, 2, 3, 4], inplace=True)

这三者顺序不要颠倒
处理好后我们再输出看看

data1 = data.loc[data.Age.isnull()]
print(data1)

在这里插入图片描述
由此可以发现数据处理已经成功。

好了,我们开始进入试验了。下面每段代码段我都用# %%分隔开了



导入库和读取数据

先引入一些库并且更改路径:

# %%
from sklearn.model_selection import train_test_split
from sklearn import metrics
from sklearn import svm
import os
import pandas as pd
import pickle
import matplotlib.pyplot as plt

cwd = os.getcwd().replace('\\', '/')
if cwd.split('/')[-1] != 'lab':
    # 这里要更改到你文件所在的目录下
    os.chdir('D:/project/pyCharmProject/data_mining/lab')
print(os.getcwd())

在这里插入图片描述

为了大家不迷糊,我给大家看看我的路径, 本文的代码在svm_grid_find.py中
在这里插入图片描述

读取一下数据:

data = pd.read_csv('data/train.csv')
data.head()

在这里插入图片描述

数据预处理

激动人心的数据预处理部分:

# 数据预处理
data['Age_band'] = 0
data.loc[data['Age'] <= 16, 'Age_band'] = 0
data.loc[(data['Age'] > 16) & (data['Age'] <= 32), 'Age_band'] = 1
data.loc[(data['Age'] > 32) & (data['Age'] <= 48), 'Age_band'] = 2
data.loc[(data['Age'] > 48) & (data['Age'] <= 64), 'Age_band'] = 3
data.loc[data['Age'] > 64, 'Age_band'] = 4

data['Family_Size'] = 0
data['Family_Size'] = data['Parch'] + data['SibSp']
data['Alone'] = 0
data.loc[data.Family_Size == 0, 'Alone'] = 1

# 抽取出称呼
data['Initial'] = 0
for i in data:
    data['Initial'] = data.Name.str.extract('([A-Za-z]+)\.')

# 统一称呼
data['Initial'].replace(
    ['Mlle', 'Mme', 'Ms', 'Dr', 'Major', 'Lady', 'Countess', 'Jonkheer', 'Col', 'Rev', 'Capt', 'Sir', 'Don'],
    ['Miss', 'Miss', 'Miss', 'Mr', 'Mr', 'Mrs', 'Mrs', 'Other', 'Other', 'Other', 'Mr', 'Mr', 'Mr'], inplace=True)

# 填充Age的单元格
data.loc[(data.Age.isnull()) & (data.Initial == 'Mr'), 'Age'] = 33
data.loc[(data.Age.isnull()) & (data.Initial == 'Mrs'), 'Age'] = 36
data.loc[(data.Age.isnull()) & (data.Initial == 'Master'), 'Age'] = 5
data.loc[(data.Age.isnull()) & (data.Initial == 'Miss'), 'Age'] = 22
data.loc[(data.Age.isnull()) & (data.Initial == 'Other'), 'Age'] = 46

# 将Initial这一列用数字的分类标签代替, 因为字符串类型无法参与训练或测试
data['Initial'].replace(['Mr', 'Mrs', 'Miss', 'Master', 'Other'], [0, 1, 2, 3, 4], inplace=True)

data['Fare_Cat'] = 0
data.loc[data['Fare'] <= 7.91, 'Fare_Cat'] = 0
data.loc[(data['Fare'] > 7.91) & (data['Fare'] <= 14.454), 'Fare_Cat'] = 1
data.loc[(data['Fare'] > 14.454) & (data['Fare'] <= 31.0), 'Fare_Cat'] = 2
data.loc[(data['Fare'] > 31.0) & (data['Fare'] <= 513), 'Fare_Cat'] = 3

data['Embarked'].fillna('S', inplace=True)
data['Embarked'].replace(['S', 'C', 'Q'], [0, 1, 2], inplace=True)

data.info()

在这里插入图片描述

划分数据集

划分训练集合测试集:

train, test = train_test_split(data, test_size=0.3, random_state=0, stratify=data['Survived'])
# 字符串信息的不能要,后者可以用分类标签代替, PassengerId也不要了
train_X = train[['Pclass', 'Age', 'SibSp', 'Parch', 'Fare',
                 'Embarked', 'Initial', 'Age_band', 'Family_Size', 'Alone',
                 'Fare_Cat']]

# 字符串信息的不能要,后者可以用分类标签代替
test_X = test[['Pclass', 'Age', 'SibSp', 'Parch', 'Fare',
               'Embarked', 'Initial', 'Age_band', 'Family_Size', 'Alone',
               'Fare_Cat']]
train_Y = train[['Survived']]
test_Y = test[['Survived']]

输出一下训练集:

print(train_X.info())
print(train_Y)

在这里插入图片描述
在这里插入图片描述
可以看到训练集有623个数据.

我们再来输出一下测试集

print(test_X.info())
print(test_Y)

在这里插入图片描述在这里插入图片描述
相信聪明的读者早就发现这个数据是泰坦尼克号那个数据了吧。



训练模型

我们知道有两个参数特别重要,一个是C, 一个是gamma。这里我们写个函数搜索一下。这里插一句:网格搜索 大家可以去看看sklearn中的GridSearchCV这个类的用法。这里我们用accuracy来搜索不一定好,还可以用其他指标比如: roc_auc (F1 score)。

def svm_grid_find(kernel, c_lt, gamma_lt):
    """
    网格搜索svm最优时的参数
    :param kernel: 核函数
    :param c_lt: 乘法系数列表
    :param gamma_lt: 方差列表
    :return: 最优时的准确率,最优时的参数组合, 所有组合下运算出来的结果
    """
    best_acc = 0
    best_parameter = {
    
    'c': -1, 'gamma': -1}
    all_result = []
    for c in c_lt:
        for gamma in gamma_lt:
            model = svm.SVC(kernel=kernel, C=c, gamma=gamma)
            model.fit(train_X, train_Y)
            prediction1 = model.predict(test_X)
            acc = metrics.accuracy_score(prediction1, test_Y)
            print("c_{} and g_{} is {}".format(c, gamma, acc))
            all_result.append((c, gamma, acc))
            if acc > best_acc:
                best_acc = acc
                best_parameter = {
    
    'c': c, 'gamma': gamma}
    print('best_acc: {}, best_parameter: {}'.format(best_acc, best_parameter))
    return best_acc, best_parameter, all_result

写一个参数列表并调用一下函数

c_lt1 = [10 ** i for i in range(-5, 5)]
gamma_lt1 = [10 ** i for i in range(-8, 8)]
svm_grid_find('rbf', c_lt1, gamma_lt1)

在这个过程中间输出了一大堆数,其中我们关注最后一个(下图all_result中的数组我只截取了一部分)

在这里插入图片描述

可以看到这里accuracy性能并不是很好,后期还要看怎么提高准确率。我们这里先不管,那我们拿这个参数
c = 10000(这个真有点夸张,我记得一般都是1或者小于1的) 和 gamma = 10-5来训练一个模型。并保存。

这里我先在lab目录下新建一个叫model的文件夹
在这里插入图片描述

运行下面这段代码

c2, gamma2 = 10000, 10**(-5)
model2 = svm.SVC(kernel='rbf', C=c2, gamma=gamma2)
# 训练模型
model2.fit(train_X, train_Y)
# 保存模型
with open('model/svc1.pkl', 'wb') as f:
    pickle.dump(model2, f)

可以看见model文件夹下多了个svc1.pkl的文件,这就是训练好的模型。(pycharm的文件夹组件有点奇怪,可能要刷新一两下才能看到新生成的文件)
我们下一次使用的时候只需要加载这个文件即可,不需要重新训练了。这对于一些训练时间比较长的模型来说是非常有用的!
在这里插入图片描述


然后我们加载一下模型试试:

# 加载模型
with open('model/svc1.pkl', 'rb') as f:
    model3 = pickle.load(f)
prediction3 = model3.predict(test_X)
acc3 = metrics.accuracy_score(prediction3, test_Y)
print('accuracy: {}, 预测结果: \n'.format(acc3))
# 输出一下预测结构看看
print(prediction3)

在这里插入图片描述


绘制ROC曲线

然后我们来绘制一下ROC曲线并计算AUC。

# 绘制一下ROC曲线
fpr, tpr, thresholds = metrics.roc_curve(test_Y, prediction3, pos_label=1)
print('fpr: {}\n tpr: {}'.format(fpr, tpr))

在这里插入图片描述

# 计算AUC
auc = metrics.auc(fpr, tpr)
print('auc: ', auc)
plt.figure()

lw = 2
plt.plot(fpr, tpr, color='darkorange',
         lw=lw, label='ROC curve (area = {:.2f})'.format(auc))
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()

在这里插入图片描述在这里插入图片描述


输出混淆矩阵

# 输出混淆矩阵
confusion_matrix = metrics.confusion_matrix(test_Y, prediction3)
print(confusion_matrix)

在这里插入图片描述



结语

我们通过一个小案例,实现了对一个真实案例的数据进行预处理,到建立模型,训练,预测的过程。其中我们还学会了如何保存模型。本文适合入门的初学者,案例简单易懂。更多案例可以参考 :

猜你喜欢

转载自blog.csdn.net/weixin_43850253/article/details/109713755
今日推荐