篇首语
相信大家都知道下面的图片是啥意思,每个无论在啥公司、无论哪个行业都有自己的KPI评价指标,公司会根据公司情况设定公司战略KPI、部门KPI、以及每个人的指标,对于员工也是比较关心自己的KPI因为关系着你能拿多少年终奖,公司处在不同发展阶段相应的评价指标细则也会有所区别。
正如我们的学习模型,在设计阶段、部署阶段等都有每个阶段的衡量指标,下面让我们来看看究竟有哪些指标。
模型评估指标
模型评估其实在各行各业都有自己的评价标准,相当于对一件事情结果好坏的评价,假如没有评价标准那么如何来区分好与坏呢,在学校中评价学生的一个重要指标是学习成绩、在医学中有红细胞数量、血小板数量等指标来分析一个人的健康状况、衡量网站响应速度有TPS等,由此看来,机器学习模型也有自己的评价标准,下图是我画的常见的评价指标:
不同的书籍中对各个指标翻译的中文可能稍有区别,干脆还不如直接写英文,也显得高大上点。
指标分析
分类
数据集
这个数据集是训练数据集,咱们把它分为训练集和验证集两部分。
数据集说明 在这个数据集中有三列数据 admit 表示目标列 意思是提交是否通过,gpa(grade point average)平均绩点值是表示学生平时学习成绩的一种表示方法,中国一般是100分制,60分及格,如果转化为gpa评分值 ,大概0-60 为0,60-70为1,70-80为2,80-90为3,90-100为4;gre(Graduate Record Examination) 称为美国研究生入学考试,看数据集中数据这么大应该是2011年以前的算分方法,在2011年以后改革了分值计算,数学177分、语文166分,改前为800分标准。
其实理解了每个字段含义也就大概懂了这两个字段和目标变量的关系,可见对数据的认识很重要,这让我想起了 数据和特征决定了机器学习的上限,而模型和算法只是逼近这个上限而已。
代码
首先引入sklearn库 并且导入数据
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LogisticRegression
admissions = pd.read_csv("admissions.csv")
print admissions.head(2)
admit gpa gre
0 0 3.177277 594.102992
1 0 3.412655 631.528607
# permutation 返回打乱后的新数组 ;shuffed 将原数组打乱
shuffed_admissions_index = np.random.permutation(admissions.index)
shuffed_admissions = admissions.loc[shuffed_admissions_index]
# 简单二分 0-500 样本为训练集 ;500以后为验证集
train_set = shuffed_admissions.iloc[0:500]
test_set = shuffed_admissions.iloc[500:len(shuffed_admissions)]
有了训练数据之后就可以训练模型了,在实际项目中不会直接有这么好的数据,中间过程需要对数据格式处理,由于数据是处理好的就都省略了,一般情况下特征还需要自己去寻找,并不能这么轻松获得,为简单计算只把我们数据拆分为训练集和验证集,逻辑回归模型训练训练集样本。
model = LogisticRegression()
# 训练模型
model.fit(train_set[["gpa"]], train_set["admit"])
labels = model.predict(test_set[["gpa"]])
print labels
# 新增一列预测结果
test_set['predicted_label'] = labels
print test_set['predicted_label'].value_counts()
# 新增一个目标列
test_set['actual_label'] = test_set['admit']
# 预测正确的样本情况
matches = test_set['actual_label'] == test_set['predicted_label']
# 预测正确的样本个数
correct_predictions = test_set[matches]
# 准确率计算
accuracy = len(correct_predictions) / float(len(test_set))
print "提交审核通过的准确率accuracy = %s" % (accuracy)
提交审核通过的准确率accuracy = 0.645833333333
接下来有预测模型和结果了,我们可以开始计算各个样本预测情况,通常用一个2*2的混淆矩阵来表示,当然对于多类别预测也是通用的,可以非A即其它类别,A为正,其它为负。
true_positive_filter = (test_set['actual_label']==1) & (test_set['predicted_label'] == 1)
true_positives = len(test_set[true_positive_filter])
print "TP = %s" % true_positives
true_nagative_filter = (test_set['actual_label']==0) & (test_set['predicted_label'] == 0)
true_nagatives = len(test_set[true_nagative_filter])
print "TN = %s" % true_nagatives
false_nagatives_filter = (test_set['actual_label']==1) & (test_set['predicted_label'] == 0)
false_nagatives = len(test_set[false_nagatives_filter])
print "FN = %s" % false_nagatives
false_positive_filter = (test_set['actual_label']==0) & (test_set['predicted_label'] == 1)
false_positives = len(test_set[false_positive_filter])
print "FP = %s" % false_positives
TP = 10
TN = 83
FN = 42
FP = 9
指标计算
逻辑回归预测结果,2*2混淆矩阵 如下
真实\预测 | 预测(正) | 预测(负) |
---|---|---|
真实(正) | TP(10) | FN(42) |
真实(负) | FP(9) | TN(83) |
- accuracy (准确率)= ( TP+TN ) / ( TP+FN+FP+TN ) = (10+83) / (10+83+9+42) = 0.57
- precision (精确率、查找率) = TP/(TP+FP) = 10 /(10+9)= 0.53
- recall (召回率、查全率) = TP / (TP+FN) = 10 / (10+42) = 0.19
从结果来看 准确率不到60%模型整体效果较差,而召回率还要小说明我们真正想要预测的正类别预测错了很多,精确率高于召回率说明负类样本预测对了很多,精确率和召回率唯一不同点即样本中是否都是真正的正样本,召回率都是真正的样本,而精确率含有把负样本预测为正样本的情况,他们两个的大小比较可以说明是把正样本预测错了的多还是把负样本预测错了的多,这两个值都是越大越好,越大说明各自预测错了的越少。
我们来继续画ROC 接受者特征曲线,学习者即我们的学习模型,sklearn有提供好了函数思路是通过预测出来每个样本属于哪个类别的概率值,然后不断调整概率阈值来得到不同的点坐标 Ai(TPR, FPR) 的值 , i一般等于样本个数,将i个坐标连接起来即得到ROC曲线,如下代码所示:
TPR = TP / (TP+FN) = TP / C(真实)正
FPR = FP / (FP+TN) = FP / C(真实)负
从公式上可以看出来 TPR是把真实正样本预测对了的概率,即真阳
FPR是把真实负样本预测错了的概率即假阳
ROC曲线即以真阳为纵坐标,以假阳为横坐标,画出来一条曲线
from sklearn import metrics
# 样本属于0-1分类的概率值 两列属于两类各自的概率
probabilities = model.predict_proba(test_set[["gpa"]])
# 真正例、假正例、概率阈值
fpr, tpr, thresholds = metrics.roc_curve(test_set["actual_label"], probabilities[:,1])
plt.plot(fpr, tpr)
plt.show()
ROC曲线
上图即我们画出来的曲线,可以看见这条曲线效果并不好,有点接近一条直线了,研究一下图上几个特殊点的含义,就会读懂整个图,ABCD四点含义留给大家自己思考?
结果是曲线距离A点越近模型效果越好。
AUC 面积
from sklearn.metrics import roc_auc_score
probabilities = model.predict_proba(test_set[["gpa"]])
auc_score = roc_auc_score(test_set["actual_label"], probabilities[:,1])
print(auc_score)
0.627299331104
求出来AUC面积为0.627和我们猜想的差不多,还需要继续优化模型才行。
细节
- np.random.permutation() 与 np.random.shuffle()
# 不改变原有数组顺序permutation
permutation_a = np.arange(12)
print "原始 permutation_a= %s" % permutation_a
permutation_b = np.random.permutation(permutation_a)
print "经permutation处理后permutation_a = %s" % permutation_a
print "经permutation处理后permutation_b = %s" % permutation_b
# shuffle 改变原有数据顺序
shuffle_a = np.arange(12)
print "shuffle处理前shuffle_a = %s" % shuffle_a
np.random.shuffle(shuffle_a)
print "shuffle处理后shuffle_a = %s" % shuffle_a
打印结果:
shuffle处理前shuffle_a = [ 0 1 2 3 4 5 6 7 8 9 10 11]
shuffle处理后shuffle_a = [ 2 10 0 4 6 5 11 3 9 1 7 8]
- iloc 与 loc
loc在于对pd对象根据索引号是否相等来取出行记录,而iloc在于从索引为0开始取 每次自增+1 方式 - model.predict_proba 与 model.predict 区别
predict_proba 方法返回每个样本属于哪个类别的概率,有时会需要比如画ROC曲线,predic直接返回样本属于哪个类别的结果,具体要根据我们结果来分析。
总结
当然除了分类任务还有回归、聚类、推荐等其它很多指标,不再一一阐述,毕竟指标太多学习应用时还需要抓住关键点,总结是一个抽象和找共同点的过程,找到共同点编结知识网才不会让我们忘记,知识不应该是越学习越多,应该将已有的知识变成我们的动力,学的越多动力越足,这样才能学的快理解深刻。
有时还有些问题没想太明白,比如L0 L1 L2 正则化函数 同闵可夫斯基距离啥的一样,他们为什么能拿过来作为正则化惩罚项,知识之间的关联关系还需要多多思考。
指标分析完可能发现模型存在的这样活那样的问题,一般是过拟合或欠拟合,出现这些问题后要有响应的解决方法,不断去尝试终会找到优化模型的方法。和开头提到的KPI一样,会以公司的结果不断调整KPI规则,模型训练、调优都是一个不断学习反复的过程。
题外思考
德国大学与剑桥大学?
在评价一个大学厉害不厉害时经常看大学里面出来了多少厉害人物,在历史上德国还是出了很多杰出人物的,像伟大的任务如马克思、恩格斯都是出自德国,目前大家认为德国最好的大学是慕尼黑大学,不过排名在我们的清华、北大之后,谈论起德国大家都会想到德国汽车如奔驰、宝马、大众等汽车,质量和安全系数都是不错的,德国的这类次高新行业还是比较发达的,GDP相比其周边国家也是领先地位,但是其大学没有周边国家出名,比如英国剑桥、牛津,究其原因主要有如下几点:
1.公平性与精英教育的侧重
2.大学资金关注少
3.大学制度对于优秀人才的吸引力小