1 IMDB数据集探索
见链接:IMDB数据集探索
2 THUCNews数据集探索
2.1 参考博客学习
参考博客链接:CNN字符级中文分类-基于Tensorflow实现
rnn_cnn.py运行结果:
rnn_rnn.py运行结果:
代码还在运行中。。。
学习感受:首先是根据训练数据建立词典,生成字词对应数字的词典;然后是将文本转化为数据,对每一个训练样本数据进行填充(截长补短,使样本的维度一样);接着是构建模型,输入数据,训练model,预测结果;最后是model的评估。
对于cnn_model.py:embedding层-->卷积层-->全连接层-->model评估层;需要特别注意的是写层时候维度的变化
对于rnn_model.py:embedding层-->rnn层-->drop层-->全连接层-->model评估层;需要特别注意的是写层时候维度的变化
感受最大的是博主的demo写的真的很漂亮,每一个.py文件功能很明确,里面的模块定义也十分明确。
(2.2 BiGRU+attention探索学习)
3 召回率、准确率、ROC曲线、AUC、PR曲线概念学习
在机器学习、数据挖掘、推荐系统完成建模之后,需要对模型的效果做评价。业内常用的评价指标有准确率(precision)、召回率(recall)、F值(F-Measure)等。
3.1 机器学习中分类类别平衡时
在机器学习中,被分类的样本的类别比例相对平衡,Accuracy、Precision、Recall、F1-score可以用来被作为对模型的评价指标。
混淆矩阵:
True Positive(真正,TP):将正类预测为正类数
True Negative(真负,TN):将负类预测为负类数
False Positive(假正,FP):将负类预测为正类数
False Negative(假负,FN):将正类预测为负类数
实际类别 | 预测类别 | |||
| Yes | No | 总计 | |
Yes | TP | FN | P(实际Yes) | |
No | FP | TN | N(实际No) | |
总计 |
|
| P+N |
1) 准确率(accuracy)
准确率(accuracy)计算公式:
准确率是指被分对的样本与所有样本之比,因此,一般来说,准确率越高,分类器越好。但对于样本的类别数不平衡的情况准确率并不适用,举例:假设有1000个样本,正类有990,负类为10,model预测结果全部为正类,得到acc=0.99,虽然model的准确率很高,但实际上model对负类的判断几乎没有任何意义。因此,对于样本类别不均衡的数据,准确率通常没有很大的意义。
2)召回率(recall)
召回率计算公式:
召回率是指预测正确的正类数与实际的正类数之比。可理解为被正确预测的正类数比例。也被称为灵敏性。recall高意味着正类被错误预测为负类的情况低。
3)查准率
查准率计算公式:
查准率是指被预测正确的正类数与所有被预测为正类数之比。是衡量所有被预测为正例的样本中有多少时真正例。precision高意味着负类数预测为正类数的情况低。
4)F1-score
F1-score计算公式:
F1-score是一个综合指标,为precision和recall的调和平均,数值一般接近于二者中的较小值,因此如果f1-score较高的话,意味着precision和recall都较高。
相应的代码:
from sklearn import metrics
y_true = [1,1,0,0,1,0,1,0,0,1] # 实际样本类别
y_pred = [1,1,0,1,1,0,0,1,0,1] # 预测样本类别
# 输出预测结果的混淆矩阵
print(metrics.confusion_matrix(y_true,y_pred))
# 计算预测的accuracy、precision、recall、f1_score
accuracy = metrics.accuracy_score(y_true,y_pred)
precision = metrics.precision_score(y_true,y_pred)
recall = metrics.recall_score(y_true,y_pred)
f1_score = metrics.f1_score(y_true,y_pred)
参考博客:机器学习之类别不平衡问题 (1) —— 各种评估指标
机器学习算法中的准确率(Precision)、召回率(Recall)、F值(F-Measure)
3.2 机器学习中分类类别不平衡时
ROC曲线和PR曲线皆为类别不平衡问题中常用的评估方法,二者既有相同也有不同。
TPR(真正例率):
FPR(假正例率):
1)ROC曲线
ROC曲线常用于二分类问题中的模型比较,主要表现为一种真正例率(TPR)和假正例率(FPR)的权衡。具体方法:在不同的分类阈值设定下分别以TPR和FPR为纵、横轴作图。
由ROC曲线的两个指标可以看出,正类被正确预测的样本越多,TPR越大;负类被错误预测为正类的样本越多,FPR越大,也即负类被正确预测的样本越少,FPR越大。也可以这样解释:当一个样本被分类器判为正例,若其本身是正例,则TPR增加;若其本身是负例,则FPR增加,因此ROC曲线可以看作是随着阈值的不断移动,所有样本中正例与负例之间的“对抗”。曲线越靠近左上角,意味着越多的正例优先于负例,模型的整体表现也就越好。
2)AUC
ROC曲线中的随机线,图中[0,0]到[1,1]的虚线即为随机线,该线上所有的点都表示该阈值下TPR=FPR,根据定义,TPR=TP/P,表示所有正例中被预测为正例的概率;FPR=FP/N,表示所有负例中被被预测为正例的概率。若二者相等,意味着无论一个样本本身是正例还是负例,分类器预测其为正例的概率是一样的,这等同于随机猜测(注意这里的“随机”不是像抛硬币那样50%正面50%反面的那种随机)。
上图中B点是一个随机点,意味着无论样本数量和类别如何变化,始终将75%的样本分为正例(相当于模型的预测能力形同随即猜测)。
ROC曲线围成的面积(即AUC)可以解读为:从所有正例中随机选取一个样本A,再从所有负例中随机选取一个样本A,再从所有负例中随机选取一个样本B,分类器将A判为正例的概率比将B判为正例的概率可能性要大。可以看到位于随机线上方的点(如图中的A点)被认为好于随机猜测。在这样的点上TPR总大于FPR,意为正例被判为正例的概率大于负例被判为正例的概率。
从另一个角度看,由于画ROC曲线时都是先将所有样本按分类器的预测概率排序,所以AUC反映的是分类器对样本的排序能力,依照上面的例子就是A排在B前面的概率。AUC越大,自然排序能力越好,即分类器将越多的正例排在负例之前。
3)ROC曲线的绘制
方法:假设有P个正例,N个反例,首先拿到分类器对于每个样本预测为正例的概率,根据概率对所有样本进行逆序排列,然后将分类阈值设为最大,即把所有样本均预测为反例,此时图上的点为 (0,0)。然后将分类阈值依次设为每个样本的预测概率,即依次将每个样本划分为正例,如果该样本为真正例,则TP+1,即TPR+1/P ; 如果该样本为负例,则FP+1,即FPR+1/N。最后的到所有样本点的TPR和FPR值,用线段相连。
from sklearn.datasets import make_classification
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.decomposition import PCA
from sklearn.model_selection import train_test_split
from sklearn.model_selection import StratifiedKFold
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns
X,y = make_classification(n_samples=2000,n_features=10,n_informative=4,n_redundant=1,n_classes=2,n_clusters_per_class=1,weights=[0.9,0.1],flip_y=0.1,random_state=2018)
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X)
X_pca = pd.DataFrame(X_pca)
X_pca.columns=['pca_a','pca_b']
X_pca['y'] = y
X_pca[:3]
sns.set()
sns.lmplot('pca_a','pca_b',data=X_pca,hue='y',fit_reg=False,markers=['o','x'],size=8,aspect=1.5,legend=False)
plt.legend(fontsize=20,bbox_to_anchor=(0.98,0.6),edgecolor='r')
plt.xlabel('axis_1',fontsize=17)
plt.ylabel('axis_2',fontsize=17)
kf = StratifiedKFold(n_splits=2,random_state=42)
for train_index,test_index in kf.split(X,y):
X_train,X_test = X[train_index],X[test_index]
y_train,y_test = y[train_index],y[test_index]
lr = LogisticRegression()
lr.fit(X_train,y_train)
lr.score(X_test,y_test)
pos_prob_lr = lr.predict_proba(X_test)[:,1]
rf = RandomForestClasssifier(random_state=42)
rf = RandomForestClassifier(random_state=42)
rf.fit(X_train,y_train)
rf.score(X_test,y_tesgt)
pos_prob_rf = rf.predict_proba(X_test)[:,1]
def get_roc(pos_prob,y_true):
pos = y_true[y_true==1]
neg = y_true[y_true==0]
threshold = np.sort(pos_prob)[::-1]
y = y_true[pos_prob.argsort()[::-1]]
tpr_all = [0] ; fpr_all = [0]
tpr = 0 ; fpr = 0
x_step = 1/float(len(neg))
y_step = 1/float(len(pos))
y_sum = 0
for i in range(len(threshold)):
if y[i] == 1:
tpr += y_step
tpr_all.append(tpr)
fpr_all.append(fpr)
else:
fpr += x_step
fpr_all.append(fpr)
tpr_all.append(tpr)
y_sum += tpr
return tpr_all,fpr_all,y_sum*x_step
tpr_lr,fpr_lr,auc_lr = get_roc(pos_prob_lr,y_test)
tpr_rf,fpr_rf,auc_rf = get_roc(pos_prob_rf,y_test)
plt.figure(figsize=(10,6))
plt.plot(fpr_lr,tpr_lr,label="Logistic Regression (AUC: {:.3f})".format(auc_lr),linewidth=2)
plt.plot(fpr_rf,tpr_rf,'g',label="Random Forest (AUC: {:.3f})".format(auc_rf),linewidth=2)
plt.xlabel("False Positive Rate",fontsize=16)
plt.ylabel("True Positive Rate",fontsize=16)
plt.title("ROC Curve",fontsize=16)
plt.legend(loc="lower right",fontsize=16)
plt.show()
结果图:
代码见:链接
4)ROC曲线的优缺点
优点:
(1) 兼顾正例和负例的权衡。因为TPR聚焦于正例,FPR聚焦于与负例,使其成为一个比较均衡的评估方法。
(2) ROC曲线选用的两个指标,,都不依赖于具体的类别分布。
缺点:
(3) 上文提到ROC曲线的优点是不会随着类别分布的改变而改变,但这在某种程度上也是其缺点。因为负例N增加了很多,而曲线却没变,这等于产生了大量FP。像信息检索中如果主要关心正例的预测准确性的话,这就不可接受了。
(4) 在类别不平衡的背景下,负例的数目众多致使FPR的增长不明显,导致ROC曲线呈现一个过分乐观的效果估计。ROC曲线的横轴采用FPR,根据,当负例N的数量远超正例P时,FP的大幅增长只能换来FPR的微小改变。结果是虽然大量负例被错判成正例,在ROC曲线上却无法直观地看出来。(当然也可以只分析ROC曲线左边一小段)
举个例子,假设一个数据集有正例20,负例10000,开始时有20个负例被错判,FPR=20/(20+9980)=0.002,接着又有20个负例错判,FPR2=40/(40+9960)=0.004,在ROC曲线上这个变化是很细微的。而与此同时Precision则从原来的0.5下降到了0.33,在PR曲线上将会是一个大幅下降。
5) PR (Precision Recall) 曲线
PR曲线展示的是Precision vs Recall的曲线,PR曲线于ROC曲线的相同点是都采用了TPR(Recall),都可以用AUC来衡量分类器的效果。不同点是ROC曲线使用了FPR,而PR曲线使用了Precision,因此PR曲线的两个指标都聚焦于正例。类别不平衡问题中由于主要关心正例,所以再次情况下PR曲线被广泛认为优于ROC曲线。
PR曲线的绘制与ROC曲线类似,PR曲线的AUC面积计算公式为:
代码绘制(与ROC曲线绘制的代码连在一起):
def get_pr(pos_prob,y_true):
pos = y_true[y_true==1]
threshold = np.sort(pos_prob)[::-1]
y = y_true[pos_prob.argsort()[::-1]]
recall = [] ; precision = []
tp = 0 ; fp = 0
# y_step = 1/float(len(pos))
auc = 0
for i in range(len(threshold)):
if y[i] == 1:
tp += 1
recall.append(tp/len(pos))
precision.append(tp/(tp+fp))
auc += (recall[i]-recall[i-1])*precision[i]
else:
fp += 1
recall.append(tp/len(pos))
precision_lr,recall_lr,auc_lr = get_pr(pos_prob_lr,y_test)
precision_rf,recall_rf,auc_rf = get_pr(pos_prob_rf,y_test)
plt.figure(figsize=(10,6))
plt.plot(recall_lr,precision_lr,label="Logistic Regression (AUC: {:.3f})".format(auc_lr),linewidth=2)
plt.plot(recall_rf,precision_rf,label="Random Forest (AUC: {:.3f})".format(auc_rf),linewidth=2)
plt.xlabel("Recall",fontsize=16)
plt.ylabel("Precision",fontsize=16)
plt.title("Precision Recall Curve",fontsize=17)
plt.legend(fontsize=16)
plt.show()
结果如图:
从图中,可以看到上文中ROC曲线下的AUC面积在0.8左右,而PR曲线下的AUC面积在0.68左右,类别不平衡问题中ROC曲线确实会作出一个比较乐观的估计,而PR曲线则因为Precision的存在会不断显现FP的影响。
使用场景:
(1) ROC曲线由于兼顾正例与负例,所以适用于评估分类器的整体性能,相比而言PR曲线完全聚焦于正例。
(2) 如果有多分数据且存在不同的类别分布,比如信用卡欺诈问题中每个月正例和负例的比例可能都不相同,这时候如果只想单纯地比较分类器的性能且踢出类别分布改变的影响,则ROC曲线比较适合,因为类别分布改变可能使PR曲线发生变化时好时坏,这种时候难以进行模型的比较;繁殖,如果想测试不同类别分布下对分类器的性能的影响,则PR曲线比较合适。
(3) 如果想要评估相同类别分布下正例的预测情况,则宜选PR曲线;
(4) 类别不平衡问题中,ROC曲线通常会给出一个乐观的效果估计,所以大部分时候还是PR曲线更好。
(5) 最后可以根据具体的应用,在曲线上找到最优的点,得到相应的precision,recall,f1_score等指标,去调整模型的阈值,从而得到一个符合具体应用的模型。