机器学习第二周:如何评价模型的好坏
一、目标
数据拆分:训练数据集&测试数据集
评价分类结果:精准度、混淆矩阵、精准率、召回率、F1 Score、ROC曲线等
评价回归结果:MSE、RMSE、MAE、R Squared
二、学习资料参考
-
《机器学习的敲门砖:kNN算法(中)》(https://mp.weixin.qq.com/s/vvCM0vWH5kmRfrRWxqXT8Q)全文,学习数据拆分,划分训练数据集&测试数据集的方法。分类准确度。
-
阅读《评价分类结果(上):混淆矩阵、精准率、召回率》(https://mp.weixin.qq.com/s/Fi13jaEkM5EGjmS7Mm_Bjw)
-
《评价分类结果(下):F1 Score、ROC、AUC》**,全面了解评价分类结果
-
阅读《模型之母:线性回归的评价指标》(https://mp.weixin.qq.com/s/BEmMdQd2y1hMu9wT8QYCPg),学习评价回归结果:MSE、RMSE、MAE、R Squared
注:本文是上面这四篇文章的笔记,均来自与公众号 数据科学家联盟组织的学习小组,木东居士和饼干等分享的文章。
三、学习开始
-
数据拆分:
KNN算法中:对数据集进行划分,包括训练集和测试集,在划分过程中尽可能随机选择,训练集数据要足够多,可以采用随机后采集0.8比例的数据作为训练集,剩余0.2作为测试数据集的数据进行。
方法命名:https://mp.weixin.qq.com/s/vvCM0vWH5kmRfrRWxqXT8Q l来源: 数据科学家联盟 作者:Japson
def train_test_split(X, y, test_ratio = 0.2 , seed = None): if seed: np.random.seed(seed) shuffle_index = np.random.permutation(len(X)) test_size = int(len(X) * test_ratio) test_index = shuffle_index[:test_size] train_index = shuffle_index[test_size:] X_train = X[train_index] X_test = X[test_index] y_train = y[train_index] y_test = y[test_index] return X_train , X_test, y_train ,y_test
参考下面链接:sklearn在代码中引入model_selection.train_test_split,可以随机分割训练集和测试集(随机数种子)。如果该方法不加random_state可能会造成确定模型和初始参数后,每运行一次都可能得到不同的准确率。
from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
https://blog.csdn.net/Tony_Stark_Wang/article/details/80407923
-
分类准确度accuracy
在划分出测试数据集后,根据训练数据集训练出的模型,需要进行对模型验证,评价 其好坏。
accuracy_score 计算分类准确率,返回被正确分类的样本比例(默认)或者数量
在多标签分类问题中,该函数返回子集的准确率,对于一个给定的多标签样本,如果预测得到的标签集合与该样本真正的标签集严格吻合,则subset accuracy = 1.0 否则是0.0。但有些场合使用精度(查准率)和召回率(查全率)等更好些。
def accuracy_score(y_true, y_predict): """计算y_true和y_predict之间的准确率""" assert y_true.shape[0] == y_predict.shape[0],"the size of y_true must be equal to the size of y_predict" return sum(y_true == y_predict) / len(y_true)
有时只关心对应的测试结果,可以使用score,进一步进行分装
def score(self, X_test, y_test): """根据X_test进行预测, 给出预测的真值y_test,计算预测算法的准确度""" y_predict = self.predict(X_test) return accuracy_score(y_test, y_predict)
-
超参数
knn_clf = KNeighborsClassifier(n_neighbors=3)
这里的数值,是传递一个默认的k值,但是这个参数该如何选择。
超参数,在机器学习算法模型执行之前需要制定的参数。调参数理解调的就是超参数,如该处算法KNN中的k。
在对于KNN算法中,最容易想到的就是利用训练数据,通过循环1…k,选择其中得到的score最佳的一个结果对应的K
# 指定最佳值的分数,初始化为0.0;设置最佳值k,初始值为-1 best_score = 0.0 best_k = -1 for k in range(1, 11): # 暂且设定到1~11的范围内 knn_clf = KNeighborsClassifier(n_neighbors=k) knn_clf.fit(X_train, y_train) score = knn_clf.score(X_test, y_test) if score > best_score: best_k = k best_score = score print("best_k = ", best_k) print("best_score = ", best_score)
-
超参数:权重
在KNN算法中,我们是利用对应的k个邻近点,每个点的权重都是1,如果根据距离远近增加判断结果所起的作用,影响大的增加权重大点。可以使用f(x)=1/x,对每种分类点距离倒数求和,判断数值那个最大,然后该点所属对应分类。
感觉可以调整f(x)
在sklearn.neighbors的构造函数 KNeighborsClassifier中有一个参数:weights ,默认uniform 是不考虑距离,也可以写distance来考虑距离权重(默认是欧拉距离,如果要是曼哈顿距离,则可以写参数P?)
在找两个超参数,公众号介绍使用了双重循环,在每种距离运算下寻求k,最终寻求出一个最佳的两个参数
# 两种方式进行比较 best_method = "" best_score = 0.0 best_k = -1 for method in ["uniform","distance"]: for k in range(1, 11): knn_clf = KNeighborsClassifier(n_neighbors=k, weights=method, p=2) knn_clf.fit(X_train, y_train) score = knn_clf.score(X_test, y_test) if score > best_score: best_k = k best_score = score best_method = method print("best_method = ", method) print("best_k = ", best_k) print("best_score = ", best_score) 输出: best_method = distance best_k = 4 best_score = 0.9916666666666667
method循环uniform,distance ,每种循环里面嵌套子循环,子循环再遍历k,在寻找最佳的score过程中,通过遍历比较最终获得一个满意的k ,method
-
当有多个参数需要找寻最优时,是不是需要自己写多个循环去搜索最优参数
饼干说,超参数过多,超参数之间互相依赖等都是在具体超参数搜索过程中遇到的问题。如何一次性把想要的“最好”的超参数组合出来,sklearn中专门封装了一个参数网格搜索方法GridSearch。使用时需要首先定义一个参数param_search。他是一个数据,数组中的每个元素是一个字典,字典中是对应的一组网格搜索,每一组网格搜索是这一组网格搜索每个参数的取值范围。键是参数名称,值是键所对应的的参数列表。
param_search = [ { "weights":["uniform"], "n_neighbors":[i for i in range(1,11)] }, { "weights":["distance"], "n_neighbors":[i for i in range(1,11)], "p":[i for i in range(1,6)] } ]
knn_clf = KNeighborsClassifier() # 调用网格搜索方法 from sklearn.model_selection import GridSearchCV # 定义网格搜索的对象grid_search,其构造函数的第一个参数表示对哪一个分类器进行算法搜索, #第二个参数表示网格搜索相应的参数 grid_search = GridSearchCV(knn_clf, param_search)
%%time 在网格中寻找最佳参数组 grid_search.fit(X_train, y_train) 输出:CPU times: user 2min 21s, sys: 628 ms, total: 2min 21s Wall time: 2min 23s GridSearchCV(cv=None, error_score='raise', estimator=KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=5, p=2, weights='uniform'), fit_params=None, iid=True, n_jobs=1, param_grid=[{'weights': ['uniform'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]}, {'weights': ['distance'], 'n_neighbors': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'p': [1, 2, 3, 4, 5]}], pre_dispatch='2*n_jobs', refit=True, return_train_score='warn', scoring=None, verbose=0)
# 返回的是网格搜索搜索到的最佳的分类器对应的参数 grid_search.best_estimator_ 输出:KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski', metric_params=None, n_jobs=1, n_neighbors=3, p=3, weights='distance')
#best_score grid_search.best_score_ 输出:0.9853862212943633 grid_search.beat_params_ 输出:{'n_neighbors':3, 'p':3, 'weights':'distance'} knn_clf = grid_search.beat_estimator_ knn_clf.score(X_test, y_test) 输出:0.9833333333328
-
评价分类结果:混淆矩阵、精准率、召回率
在机器学习中如何评价一个算法的好坏,在回归问题中可以使用MSE/RMSE/MAE/R方。在使用分类精准度上,可能存在陷阱的,这是需要更加全面的信息。
在对于极度偏斜skewed data的数据,在使用分类准确度是不能衡量的,还需要使用混淆矩阵confusion matrix 做分析。
预测值0 预测值1 真实值0 TN FP 真实值1 FN TP TN:真实值是0,与测试值也是0,预测negative,预测正确
FP:真实值是0,预测值是1,预测positive,但预测错误了
FN:真实值是1,预测值是0,预测是negative,但预测错误了
TP:真实值是1,预测值是1,预测是positive,预测正确了
混淆矩阵的信息更多谢,提供更多一些指示的指标。
精准率和召回率
预测值0 预测值1 真实值0 9978(TN) 12(FP) 真实值1 2(FN) 8(TP) 所谓的精准率是:分母为所有预测为1的个数,分子是其中预测对了的个数。即预测值为1,且预测对了的比例。
现实情况中我们更关注“患病”、“有风险”,且在“有风险”中且判断正确的概率。如在100次结果为患病的预测中,平均有40次是预测对的。精准率是我们关注的那个事件,预测的有多准。
召回率:所有真实值为1的数据中,预测对了的个数。每当有100个癌症患者,算法可以成功的预测出8个。是在我们关注的那个事件真实的发生情况下,我们成功预测的比例是多少。举个例子在知道算法准确率的情况下,为什么需要精准率和召回率
预测值0 预测值1 真实值0 9978 12 真实值1 2 8 如果简单粗暴认为所有人都是健康的,那么算法准确率是99.78%,这个数据应该是毫无意义。如果算精准率则是40%,召回率是80%。也就是说在预测有病的人中预测准的概率是40%,在实际有病的人中成功预测的有80%。这两个指标在本次分类中才能看出比准确率要实用。
总之:
精准率:我们关注的那件事,预测的有多准。
召回率:我们关注的那个事件真实的发生情况下,我们成功预测的比例是。
-
评价分类结果(下):F1 Score、ROC、AUC
当精准率和召回率一个高一个低时该如何选择取舍那?适场景而定
在实际业务场景中,有很多没有明显的选择,该如何在精准率和召回率中平衡,可以使用一个新的指标:F1 SCORE
F1 SCORE: 是精准率和召回率的调和平均值:
调和平均值,当其中某一个值高、另一个值低时,得到的Fs1 score也低;只有而且都非常高,F1才会高。import numpy as np def f1_score(precision, recall): try: return 2*precision*recall /(precision + recall) except: return 0.0
0.9 0.1 --》 0.18…
ROC曲线
分类阈值、TPR和FPR
分类阈值:设置判断样本为正例的阈值threshold ?
如果某个逻辑回归模型预测得到一个分数,但是这个分数是不是归到一个类中,它需要一个判断的条件,或者说是一个阈值,大于它,或者是小于他。
sklearn中有一个方法:decision_function
decision_scores = log_reg.decision_function(X_test)
y_predict = np.array(decision_scores >=5, dtype = ‘int’)
TPR :预测为1,且预测对了的数量,占真实值为1的数据百分比。(召回率)
FPR:预测值为1,单预测错了的数量
ROC曲线:receiver operation characteristic Cureve,描述TPR和FPR之间的关系。x座标轴是FPR,y座标轴是TPR
TPR是所有真实值为1中被判断为1的比例;FPR是真实值为0中被错误判断为1的概率。理想情况下TPR=1 ,FPR=0。阈值取得最小正例预测值与最大负例预测值之间的值即可。
根据ROC曲线,x座标轴是FPR,y座标轴是TPR,我们想要真实值1中预测的越准确越好,即TPR越高越好,FPR是负例中错误的预测 成正确,这个值应该越少越好。因此也就是在左上角,说明效果越好。
当TPR=1,FPR=0,称为完美分类。当两个算法的ROC曲线中随便一点的TPR都要比两外一个算法好,此时可以任务好的那个算法是两个算法中我们想要的。
当两个算法有交叉,这时无法判断那个分类器较好时,按照饼干哥的文章中说的可以计算曲线显得面积AUC,作为性能度量。???如何计算,请看AUC
AUC,在ROC曲线中,曲线下面的面试称为area under curve 。这个面积是小于1的。
AUC可以看做是由多个梯形的面积的和。
AUC=1,完美分类器;(0.5,1)优于随机猜测。需要选取一个合适的阈值。AUC=0.5模型没有预测价值;AUC<0.5 比随机预测还差。
sklearn.metrics roc_auc_score
roc_auc_score(y_test,decision_scores)
-
线性回归的评价指标:MSE、RMSE、MAE、R Squared
线性回归模型,在使用最小二乘法,使训练集与预测值的差的平方和最小,求出截距和系数,之后使用测试集进行测试,以此来衡量算法的好坏。
均方误差MSE:在最小二乘法的计算过程中均方和往往在项数越多时,结果越相差很大。因此需要将测试的数据集的个数进行抵消,因此:mean squared error
均方根误差RMSE(解决量纲问题):root mean squarde error
平均绝对误差MAE: mean absolute error
R Square
R Square <=1,它越大越好,因为减数的分子这样就越小,即预测值和真实值之差的平方和越小,错误率低。其最大值是1.
当为0时,则是基准模型,什么叫做基准模型???
四、总结
本文中分别介绍了:数据拆分,将数据拆分为训练数据集&测试数据集。同时对于分类KNN,介绍了结果的评价指标,他们分别是精准度、混淆矩阵、精准率、召回率、F1 Score、ROC曲线等,各类指标都有其应用的场景。最后介绍了线性回归算法的评价,可以用MSE、RMSE、MAE、R Squared,其中效果最好的是R Squared。