• sklearn机器学习——day10


    支持向量机的基本原理

    支持向量机分类器,是在数据空间中找出一个超平面作为决策边界,利用这个决策边界来对数据进行分类,并使分 类误差尽量小的模型。

    以二维数据为例,图中的数据集有两个特征,标签有两类,一类为紫色,一类为红色。对于这 组数据,我们找出的决策边界被表达为 ,决策边界把平面分成了上下两部分,决策边界以上的样本 都分为一类,决策边界以下的样本被分为另一类。以我们的图像为例,绿色实线上部分为一类(全部都是紫色 点),下部分为另一类(全都是红色点)。

    支持向量机分类器,就是以找出最大化的边际d为目标来求解损失函数,以求解出参数w和b,以构建决策边界,然后用决策边界来分类的分类器。

    二分类SVC中的样本不均衡问题:重要参数class_weight

    分类模型天生会倾向于多数的类,让多数类更容易被判断正确,少数类被牺牲掉

    模型评估指标会失去意义

    标签的值1的C:权重1 * C,标签的值2的C:权重2*C 或者,可以使用“balanced”模式,这个模式使用y的值自动调整与输入数据中的类频率成反比的权重为 n_samples/(n_classes * np.bincount(y))

    如何使用这个参数:我们来自建一组样本不平衡的数据集。我们在这组数据集上建两个SVC模型,一个设置有class_weight参 数,一个不设置class_weight参数。我们对两个模型分别进行评估并画出他们的决策边界,以此来观察 class_weight带来的效果

    1. import numpy as np
    2. import matplotlib.pyplot as plt
    3. from sklearn import svm
    4. from sklearn.datasets import make_blobs
    5. #创建不均衡数据集
    6. class_1 = 500 #类别1有500个样本
    7. class_2 = 50 #类别2只有50个
    8. centers = [[0.0, 0.0], [2.0, 2.0]] #设定两个类别的中心
    9. clusters_std = [1.5, 0.5] #设定两个类别的方差,通常来说,样本量比较大的类别会更加松散
    10. X, y = make_blobs(n_samples=[class_1, class_2],
    11. centers=centers,
    12. cluster_std=clusters_std,
    13. random_state=0, shuffle=False)
    14. #看看数据集长什么样
    15. plt.scatter(X[:, 0], X[:, 1], c=y, cmap="rainbow",s=10)
    16. #其中红色点是少数类,紫色点是多数类
    17. #在数据集上分别建模
    18. #不设定class_weight
    19. clf = svm.SVC(kernel='linear', C=1.0)
    20. clf.fit(X, y)
    21. #设定class_weight
    22. wclf = svm.SVC(kernel='linear', class_weight={1: 10})
    23. wclf.fit(X, y)
    24. #给两个模型分别打分看看,这个分数是accuracy准确度
    25. clf.score(X,y)
    26. wclf.score(X,y)
    27. #绘制两个模型下数据的决策边界
    28. #首先要有数据分布
    29. plt.figure(figsize=(6,5))
    30. plt.scatter(X[:, 0], X[:, 1], c=y, cmap="rainbow",s=10)
    31. ax = plt.gca() #获取当前的子图,如果不存在,则创建新的子图
    32. #绘制决策边界的第一步:要有网格
    33. xlim = ax.get_xlim()
    34. ylim = ax.get_ylim()
    35. xx = np.linspace(xlim[0], xlim[1], 30)
    36. yy = np.linspace(ylim[0], ylim[1], 30)
    37. YY, XX = np.meshgrid(yy, xx)
    38. xy = np.vstack([XX.ravel(), YY.ravel()]).T
    39. #第二步:找出我们的样本点到决策边界的距离
    40. Z_clf = clf.decision_function(xy).reshape(XX.shape)
    41. a = ax.contour(XX, YY, Z_clf, colors='black', levels=[0], alpha=0.5, linestyles=['-'])
    42. Z_wclf = wclf.decision_function(xy).reshape(XX.shape)
    43. b = ax.contour(XX, YY, Z_wclf, colors='red', levels=[0], alpha=0.5, linestyles=['-'])
    44. #第三步:画图例
    45. plt.legend([a.collections[0], b.collections[0]], ["non weighted", "weighted"],
    46. loc="upper right")
    47. plt.show()

    SVC的模型评估指标

    目标是希望尽量捕获少数类

    寻找捕获少数类的能力和将多数类判错后需要付出的成本的平衡

    如果一个模型在能够尽量捕获少 数类的情况下,还能够尽量对多数类判断正确,则这个模型就非常优秀了。为了评估这样的能力,我们将引入新的模型评估指标:混淆矩阵和ROC曲线来帮助我们。

    混淆矩阵

    在混淆矩阵中,我们将少数类认为是正 例,多数类认为是负例。在决策树,随机森林这些普通的分类算法里,即是说少数类是1,多数类是0。在SVM里, 就是说少数类是1,多数类是-1。普通的混淆矩阵,一般使用{0,1}来表示。

    1. #所有判断正确并确实为1的样本 / 所有被判断为1的样本
    2. #对于没有class_weight,没有做样本平衡的灰色决策边界来说:
    3. (y[y == clf.predict(X)] == 1).sum()/(clf.predict(X) == 1).sum()
    4. #对于有class_weight,做了样本平衡的红色决策边界来说:
    5. (y[y == wclf.predict(X)] == 1).sum()/(wclf.predict(X) == 1).sum()

    召回率

    又被称为敏感度(sensitivity),真正率,查全率,表示所有真实为1的样本中,被我们预测正确的样 本所占的比例

    在支持向量机中,召回率可以被表示为,决策边界上方的所有红色点占全部样本中的红色点的比 例。召回率越高,代表我们尽量捕捉出了越多的少数类,召回率越低,代表我们没有捕捉出足够的少数类。

    1. #所有predict为1的点 / 全部为1的点的比例
    2. #对于没有class_weight,没有做样本平衡的灰色决策边界来说:
    3. (y[y == clf.predict(X)] == 1).sum()/(y == 1).sum()
    4. #对于有class_weight,做了样本平衡的红色决策边界来说:
    5. (y[y == wclf.predict(X)] == 1).sum()/(y == 1).sum()

    特异度

    表示所有真实为0的样本中,被正确预测为0的样本所占的比例。在支持向量机中,可以形象地 表示为,决策边界下方的点占所有紫色点的比例

    1. #所有被正确预测为0的样本 / 所有的0样本
    2. #对于没有class_weight,没有做样本平衡的灰色决策边界来说:
    3. (y[y == clf.predict(X)] == 0).sum()/(y == 0).sum()
    4. #对于有class_weight,做了样本平衡的红色决策边界来说:
    5. (y[y == wclf.predict(X)] == 0).sum()/(y == 0).sum()

    特异度衡量了一个模型将多数类判断正确的能力,而1 - specificity就是一个模型将多数类判断错误的能力,这种 能力被计算如下,并叫做假正率(False Positive Rate)

    sklearn中的混淆矩阵

    sklearn当中提供了大量的类来帮助我们了解和使用混淆矩阵。

    ROC曲线

    全称The Receiver Operating Characteristic Curve,译为受试者操作特性曲线。这是一条以不同阈值下的假正率FPR为横坐标,不同阈值下的召回率Recall为纵坐标的曲线。让我们先从概率和阈值开始讲起。 

    1 概率(probability)与阈值(threshold)例子

    1. #自建数据集
    2. class_1_ = 7
    3. class_2_ = 4
    4. centers_ = [[0.0, 0.0], [1,1]]
    5. clusters_std = [0.5, 1]
    6. X_, y_ = make_blobs(n_samples=[class_1_, class_2_],
    7. centers=centers_,
    8. cluster_std=clusters_std,
    9. random_state=0, shuffle=False)
    10. plt.scatter(X_[:, 0], X_[:, 1], c=y_, cmap="rainbow",s=30)
    11. #建模,调用概率
    12. from sklearn.linear_model import LogisticRegression as LogiR
    13. clf_lo = LogiR().fit(X_,y_)
    14. prob = clf_lo.predict_proba(X_)
    15. #将样本和概率放到一个DataFrame中
    16. import pandas as pd
    17. prob = pd.DataFrame(prob)
    18. prob.columns = ["0","1"]
    19. prob
    20. #使用阈值0.5,大于0.5的样本被预测为1,小于0.5的样本被预测为0
    21. #手动调节阈值,来改变我们的模型效果
    22. for i in range(prob.shape[0]):
    23. if prob.loc[i,"1"] > 0.5:
    24. prob.loc[i,"pred"] = 1
    25. else:
    26. prob.loc[i,"pred"] = 0
    27. prob["y_true"] = y_
    28. prob = prob.sort_values(by="1",ascending=False)
    29. prob
    30. #使用混淆矩阵查看结果
    31. from sklearn.metrics import confusion_matrix as CM, precision_score as P, recall_score
    32. as R
    33. CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    34. #试试看手动计算Precision和Recall?
    35. P(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    36. R(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    37. #假如我们使用0.4作为阈值呢?
    38. for i in range(prob.shape[0]):
    39. if prob.loc[i,"1"] > 0.4:
    40. prob.loc[i,"pred"] = 1
    41. else:
    42. prob.loc[i,"pred"] = 0
    43. prob
    44. CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    45. P(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    46. R(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    47. #注意,降低或者升高阈值并不一定能够让模型的效果变好,一切都基于我们要追求怎样的模型效果

    SVM实现概率预测

    在SVM中利用超平面来判断我们的样本,本质上来说,当两个点的距离 是相同的符号的时候,越远离超平面的样本点归属于某个标签类的概率就很大。

    比如说,一个距离超平面0.1的 点,和一个距离超平面100的点,明显是距离为0.1的点更有可能是负类别的点混入了边界。同理,一个距离超平面 距离为-0.1的点,和一个离超平面距离为-100的点,明显是-100的点的标签更有可能是负类。

    所以,到超平面的距 离一定程度上反应了样本归属于某个标签类的可能性。

    接口decision_function返回的值也因此被我们认为是SVM 中的置信度(confidence)。

    1. #使用最初的X和y,样本不均衡的这个模型
    2. class_1 = 500 #类别1有500个样本
    3. class_2 = 50 #类别2只有50个
    4. centers = [[0.0, 0.0], [2.0, 2.0]] #设定两个类别的中心
    5. clusters_std = [1.5, 0.5] #设定两个类别的方差,通常来说,样本量比较大的类别会更加松散
    6. X, y = make_blobs(n_samples=[class_1, class_2],
    7. centers=centers,
    8. cluster_std=clusters_std,
    9. random_state=0, shuffle=False)
    10. #看看数据集长什么样
    11. plt.scatter(X[:, 0], X[:, 1], c=y, cmap="rainbow",s=10)
    12. #其中红色点是少数类,紫色点是多数类
    13. clf_proba = svm.SVC(kernel="linear",C=1.0,probability=True).fit(X,y)
    14. clf_proba.predict_proba(X)
    15. clf_proba.predict_proba(X).shape
    16. clf_proba.decision_function(X)
    17. clf_proba.decision_function(X).shape

    绘制SVM的ROC曲线

    1. #首先来看看如何从混淆矩阵中获取FPR和Recall
    2. cm = CM(prob.loc[:,"y_true"],prob.loc[:,"pred"],labels=[1,0])
    3. cm
    4. #FPR
    5. cm[1,0]/cm[1,:].sum()
    6. #Recall
    7. cm[0,0]/cm[0,:].sum()
    8. #开始绘图
    9. recall = []
    10. FPR = []
    11. probrange = np.linspace(clf_proba.predict_proba(X)
    12. [:,1].min(),clf_proba.predict_proba(X)[:,1].max(),num=50,endpoint=False)
    13. from sklearn.metrics import confusion_matrix as CM, recall_score as R
    14. import matplotlib.pyplot as plot
    15. for i in probrange:
    16. y_predict = []
    17. for j in range(X.shape[0]):
    18. if clf_proba.predict_proba(X)[j,1] > i:
    19. y_predict.append(1)
    20. else:
    21. y_predict.append(0)
    22. cm = CM(y,y_predict,labels=[1,0])
    23. recall.append(cm[0,0]/cm[0,:].sum())
    24. FPR.append(cm[1,0]/cm[1,:].sum())
    25. recall.sort()
    26. FPR.sort()
    27. plt.plot(FPR,recall,c="red")
    28. plt.plot(probrange+0.05,probrange+0.05,c="black",linestyle="--")
    29. plt.show()

    sklearn中的ROC曲线和AUC面积

    帮助我们计算ROC曲线的横坐标假正率FPR,纵坐标Recall和对应的阈值的类 sklearn.metrics.roc_curve

    帮助我们计算AUC面积的类sklearn.metrics.roc_auc_score 

    1. from sklearn.metrics import roc_curve
    2. FPR, recall, thresholds = roc_curve(y,clf_proba.decision_function(X), pos_label=1)
    3. FPR
    4. recall
    5. thresholds #此时的threshold就不是一个概率值,而是距离值中的阈值了,所以它可以大于1,也可以为负
    6. from sklearn.metrics import roc_auc_score as AUC
    7. area = AUC(y,clf_proba.decision_function(X))
    8. plt.figure()
    9. plt.plot(FPR, recall, color='red',
    10. label='ROC curve (area = %0.2f)' % area)
    11. plt.plot([0, 1], [0, 1], color='black', linestyle='--')
    12. plt.xlim([-0.05, 1.05])
    13. plt.ylim([-0.05, 1.05])
    14. plt.xlabel('False Positive Rate')
    15. plt.ylabel('Recall')
    16. plt.title('Receiver operating characteristic example')
    17. plt.legend(loc="lower right")
    18. plt.show()

    利用ROC曲线找出最佳阈值

    Recall和FPR差距最大的点。又叫做约登指数

    1. maxindex = (recall - FPR).tolist().index(max(recall - FPR))
    2. thresholds[maxindex]
    3. #我们可以在图像上来看看这个点在哪里
    4. plt.scatter(FPR[maxindex],recall[maxindex],c="black",s=30)
    5. #把上述代码放入这段代码中:
    6. plt.figure()
    7. plt.plot(FPR, recall, color='red',
    8. label='ROC curve (area = %0.2f)' % area)
    9. plt.plot([0, 1], [0, 1], color='black', linestyle='--')
    10. plt.scatter(FPR[maxindex],recall[maxindex],c="black",s=30)
    11. plt.xlim([-0.05, 1.05])
    12. plt.ylim([-0.05, 1.05])
    13. plt.xlabel('False Positive Rate')
    14. plt.ylabel('Recall')
    15. plt.title('Receiver operating characteristic example')
    16. plt.legend(loc="lower right")
    17. plt.show()

  • 相关阅读:
    glTF-Transform处理gltf模型
    【STM32】锁存器
    js截取字符串中某个字符前后的内容
    FPGA设计时序约束二、输入延时与输出延时
    YOLO目标检测——红细胞数据集【(含对应voc、coco和yolo三种格式标签】
    元宇宙的气味体验有哪些可能?#共创招募
    Java工程师常见面试题集锦
    【Node.js】Node.js入门(八):express-jwt
    G1垃圾收集器中重要的配置参数及其默认值
    CSS总结——瀑布流布局
  • 原文地址:https://blog.csdn.net/weixin_44267765/article/details/126887969