Python大数据分析——SVM模型(支持向量机)

Python大数据分析——SVM模型(支持向量机)

  • 认知模型
  • 介绍
  • 距离计算
  • 模型思想
  • 目标函数
  • 函数与几何间隔
  • 线性可分SVM模型
  • 目标函数
  • 函数代码
  • 非线性可分SVM模型
  • 目标函数
  • 函数代码
  • 示例
  • 手写体字母识别
  • 森林火灾面积预测
  • 认知模型

    介绍

    超平面的理解:在一维空间中,如需将数据切分为两段,只需要一个点即可;在二维空间中,对于线性可分的样本点,将其切分为两类,只需一条直线即可;在三维空间中,将样本点切分开来,就需要一个平面。

    距离计算


    点到线的距离:

    平行线间的距离:

    模型思想

    绘制了两条分割直线,利用这两条直线,可以方便地将样本点所属的类别判断出来。虽然从直观上来看这两条分割线都没有问题,但是哪一条直线的分类效果更佳呢(训练样本点的分类效果一致,并不代表测试样本点的分类效果也一样)?甚至于在直线和之间还存在无数多个分割直线,那么在这么多的分割线中是否存在一条最优的“超平面”呢?

    假设直线Li是L1和L2以之间的某条直线(分割面),为了能够寻找到最优的分割面山Li,需要做三件事,首先计算两个类别中的样本点到直线的Li距离;然后从两组距离中各挑选出一个最短的(如图中所示的距离d1和d2),继续比较d1和d2,再选出最短的距离(如图中的d1),并以该距离构造“分割带”(如图中经平移后的两条虚线);最后利用无穷多个分割直线Li,构造无穷多个“分割带”,并从这些“分割带”中挑选出带宽最大的Li。

    “分割带”代表了模型划分样本点的能力或可信度,“分割带”越宽,说明模型能够将样本点划分得越清晰,进而保证模型泛化能力越强,分类的可信度越高;反之,“分割带”越窄,说明模型的准确率越容易受到异常点的响,进而理解为模型的预测能力越弱,分类的可信度越低。

    目标函数

    函数与几何间隔

    指的就是我们的分隔带

    将图中五角星所代表的正例样本用1表示,将实心圆所代表的负例样本用-1表示;实体加粗直线表示某条分割面;两条虚线分别表示因变量y取值为+1和-1时的情况,它们与分割面平行。
    不管是五角星代表的样本点,还是实心圆代表的样本点,这些点均落在两条虚线以及虚线之外,则说明这些点带入到方程w’x+b所得的绝对值一定大于等于1。
    进而可以说明如果点对应的取值越小于-1,该样本为负例的可能性越高;点对应的取值越大于+1,样本为正例的可能性越高。

    对于几何间隔,就是对于距离的公式是如何来的。

    ||w||二范式也就是平方开根,也就是距离公式。

    线性可分SVM模型

    目标函数

    通过函数间隔、距离公式可得

    拉格朗日乘子法:

    我们通过拉格朗日乘子法,来简化,得到基于拉格朗日乘子法的目标函数。




    紧接着我们对目标函数求解:

    1. 首先求偏导,令为0
    2. 将导函数反代之目标函数
      将上面得出的w=Σαiyixi带入

      最后得

    函数代码

    LinearSVC(tol=0.0001, C=1.0, multi_class=‘ovr’, fit_intercept=True, intercept_scaling=1, class_weight=None, max_iter=1000)
    tol:用于指定SVM模型迭代的收敛条件,默认为0.0001
    C:用于指定目标函数中松弛因子的惩罚系数值,默认为1
    fit_intercept:bool类型参数,是否拟合线性“超平面”的截距项,默认为True
    intercept_scaling:当参数fit_intercept为True时,该参数有效,通过给参数传递一个浮点值,就相当于在自变量X矩阵中添加一常数列,默认该参数值为1
    class_weight:用于指定因变量类别的权重,如果为字典,则通过字典的形式{class_label:weight}传递每个类别的权重;如果为字符串’balanced’,则每个分类的权重与实际样本中的比例成反比,当各分类存在严重不平衡时,设置为’balanced’会比较好;如果为None,则表示每个分类的权重相等
    max_iter:指定模型求解过程中的最大迭代次数,默认为1000

    非线性可分SVM模型


    我们在三维空间去找超平面

    目标函数

    对于非线性SVM模型而言,需要经过两个步骤,一个是将原始空间中的样本点映射到高维的新空间中,另一个是在新空间中寻找一个用于识别各类别样本点线性“超平面”。
    假设原始空间中的样本点为x,将样本通过某种转换fai(x)映射到高维空间中,则非线性SVM模型的目标函数可以表示为:

    对其求解:

    其中核函数是:

    线性核函数:

    多项式核函数:

    高斯核函数:

    Sigmoid核函数:

    函数代码

    SVC(C=1.0, kernel=‘rbf’, degree=3, gamma=‘auto’, coef0=0.0, tol=0.001, class_weight=None, verbose=False, max_iter=-1, random_state=None)
    C:用于指定目标函数中松弛因子的惩罚系数值,默认为1(惩罚系数越大,模型越精准,但是需要消耗得运算成本会加高)
    kernel:用于指定SVM模型的核函数,该参数如果为’linear’,就表示线性核函数;如果为’poly’,就表示多项式核函数,核函数中的r和p值分别使用degree参数和gamma参数指定;如果为’rbf’,表示径向基核函数(也叫高斯核函数),核函数中的r参数值仍然通过gamma参数指定;如果为’sigmoid’,表示Sigmoid核函数,核函数中的r参数值需要通过gamma参数指定;如果为’precomputed’,表示计算一个核矩阵
    degree:用于指定多项式核函数中的p参数值
    gamma:用于指定多项式核函数或径向基核函数或Sigmoid核函数中的r参数值
    coef0:用于指定多项式核函数或Sigmoid核函数中的r参数值
    tol:用于指定SVM模型迭代的收敛条件,默认为0.001
    class_weight:用于指定因变量类别的权重,如果为字典,则通过字典的形式{class_label:weight}传递每个类别的权重;如果为字符串’balanced’,则每个分类的权重与实际样本中的比例成反比,当各分类存在严重不平衡时,设置为’balanced’会比较好;如果为None,则表示每个分类的权重相等
    max_iter:指定模型求解过程中的最大迭代次数,默认为-1,表示不限制迭代次数

    示例

    手写体字母识别

    1. 导入功能包
    # 导入第三方模块
    from sklearn import svm
    import pandas as pd
    from sklearn import model_selection
    from sklearn import metrics # 模型度量方法
    
    1. 查看数据
    # 读取外部数据
    letters = pd.read_csv(r'D:\pythonProject\data\letterdata.csv')
    # 数据前5行
    letters.head()
    

    1. 处理数据
      拆分数据集
    # 将数据拆分为训练集和测试集
    predictors = letters.columns[1:]
    X_train,X_test,y_train,y_test = model_selection.train_test_split(letters[predictors], letters.letter, test_size = 0.25, random_state = 1234)
    
    1. 模型拟合与预测
      首先来看看线性SVM,SVM有个缺点就是计算特别慢,对于大数据来说现在是不合适用此模型的。
    # 选择线性可分SVM模型
    linear_svc = svm.LinearSVC()
    # 模型在训练数据集上的拟合
    linear_svc.fit(X_train,y_train)
    # 模型在测试集上的预测
    pred_linear_svc = linear_svc.predict(X_test)
    # 模型的预测准确率
    metrics.accuracy_score(y_test, pred_linear_svc)
    

    输出:0.4412
    能看到准确率是很低的,紧接着我们用高斯SVM

    # 选择非线性SVM模型
    nolinear_svc = svm.SVC(kernel='rbf')
    # 模型在训练数据集上的拟合
    nolinear_svc.fit(X_train,y_train)
    # 模型在测试集上的预测
    pred_svc = nolinear_svc.predict(X_test)
    # 模型的预测准确率
    metrics.accuracy_score(y_test,pred_svc)
    

    输出:0.9238
    可以看到效果好了很多。

    森林火灾面积预测

    1. 导入功能包
    # 导入第三方模块
    from sklearn import svm
    import pandas as pd
    from sklearn import model_selection
    from sklearn import metrics # 模型度量方法
    
    1. 查看数据
    # 读取外部数据
    forestfires = pd.read_csv(r'D:\pythonProject\data\forestfires.csv')
    # 数据前5行
    forestfires.head()
    

    1. 处理数据
    # 我们认为天不是影响因素所以删除day变量
    forestfires.drop('day',axis = 1, inplace = True)
    # 将月份作数值化处理
    forestfires.month = pd.factorize(forestfires.month)[0]
    # 预览数据前5行
    forestfires.head()
    


    紧接着查看数据分布,是否有什么规律

    # 导入第三方模块
    import seaborn as sns
    import matplotlib.pyplot as plt
    from scipy.stats import norm
    # 绘制森林烧毁面积的直方图
    sns.distplot(forestfires.area, bins = 50, kde = True, fit = norm, hist_kws = {'color':'steelblue'}, 
                 kde_kws = {'color':'red', 'label':'Kernel Density'}, 
                 fit_kws = {'color':'black','label':'Nomal', 'linestyle':'--'})
    # 显示图例
    plt.legend()
    # 显示图形
    plt.show()
    

    发现数据是极端右偏,偏态式分布,那么我们就要对其进行一个变化,然后计算

    1. 数学变换——对数变换,并作标准化处理
    # 导入第三方模块
    from sklearn import preprocessing
    import numpy as np
    from sklearn import neighbors
    # 对area变量作对数变换
    y = np.log1p(forestfires.area)
    # 将X变量作标准化处理
    predictors = forestfires.columns[:-1]
    X = preprocessing.scale(forestfires[predictors])
    
    # 将数据拆分为训练集和测试集
    X_train,X_test,y_train,y_test = model_selection.train_test_split(X, y, test_size = 0.25, random_state = 1234)
    
    1. 拟合与预测
    # 构建默认参数的SVM回归模型
    svr = svm.SVR()
    # 模型在训练数据集上的拟合
    svr.fit(X_train,y_train)
    # 模型在测试上的预测
    pred_svr = svr.predict(X_test)
    # 计算模型的MSE
    metrics.mean_squared_error(y_test,pred_svr)	
    

    误差项得:1.9268192310372871

    但这不一定是最好的,我们可以采用网格搜索法,通过自己给定的不同的参数,通过各种组合自己找到最佳的

    # 使用网格搜索法,选择SVM回归中的最佳C值、epsilon值和gamma值
    epsilon = np.arange(0.1,1.5,0.2)
    C= np.arange(100,1000,200)  
    gamma = np.arange(0.001,0.01,0.002)
    parameters = {'epsilon':epsilon,'C':C,'gamma':gamma}
    grid_svr = model_selection.GridSearchCV(estimator = svm.SVR(max_iter=10000),param_grid =parameters, scoring='neg_mean_squared_error',cv=5,verbose =1, n_jobs=2)
    # 模型在训练数据集上的拟合
    grid_svr.fit(X_train,y_train)
    # 返回交叉验证后的最佳参数值
    print(grid_svr.best_params_, grid_svr.best_score_)
    

    输出:
    Fitting 5 folds for each of 175 candidates, totalling 875 fits
    {‘C’: 300, ‘epsilon’: 1.1000000000000003, ‘gamma’: 0.001} -1.9946668196316562
    也就是拟合5重,有175种组合,总计完成875次流程计算,得到最佳组合
    对比下我们改变后的预测

    # 模型在测试集上的预测
    pred_grid_svr = grid_svr.predict(X_test)
    # 计算模型在测试集上的MSE值
    metrics.mean_squared_error(y_test,pred_grid_svr)
    

    输出:
    1.745501223882639

    作者:啥都鼓捣的小yao

    物联沃分享整理
    物联沃-IOTWORD物联网 » Python大数据分析——SVM模型(支持向量机)

    发表回复