目录
准备工作:
'''导入数据'''
# 使用的是iris数据,datas为(150,5),前四列均为特征,最后一列为标签y,其中y为三分类
path = "iris.data"
datas = pd.read_table(path, delimiter=',', header=None)
'''数据预处理'''
print(datas.isnull().sum()) # 检查缺失值
label = datas.iloc[:,-1] # 提取标签
data = datas.iloc[:,0:-1] # 提取特征
# 将原来的label对应的字符串标签转换成数字标签
label = label.apply(lambda x:x).replace('Iris-setosa',0)
label = label.apply(lambda x:x).replace('Iris-versicolor',1)
label = label.apply(lambda x:x).replace('Iris-virginica',2)
# 划分训练集与测试集
xtrain,xtest,ytrain,ytest = train_test_split(data,label, test_size=0.3, random_state=8)
# 标准化数据(这里使用的是minmax归一法)
transfer = MinMaxScaler()
xtrain_s = transfer.fit_transform(xtrain)
xtest_s = transfer.fit_transform(xtest)
'''建模'''
# 这里用随机森林建模
forest = RandomForestClassifier(n_estimators=100, criterion='gini', bootstrap=True,
max_depth=3, random_state=8)
forest = forest.fit(xtrain_s, ytrain)
score = forest.score(xtest_s, ytest)
ytest_proba = forest.predict_proba(xtest_s) # 获得每个类别对应的概率 (45,3)
# 将y标签转换成one-hot形式
ytest_l = list(np.array(ytest))
ytest_one = label_binarize(ytest_l, classes=[0,1,2]) (45,3)
宏平均大致思路:
宏平均本质上是将多分类问题转换成了n个二分类的问题(例如在本模型中预测值y的标签为3分类,那么n即为3,也就是将原标签转换成one-hot后,他的每一列代表一个相对于其他类,该样本是否属于该类的一个二分类问题) ,再分别对这n个二分类的问题求他对应的FPR、TPR(求法和二分类问题一样),再把所有计算出来的FPR放在一起去重、从小到大排序,然后对每一个FPR分别在这三个类中所对应的TPR相加求平均。最后ROC曲线的横坐标即为去重、排序过后的FPR,纵坐标为求完平均后的TPR
宏平均代码实现:
'''宏平均法'''
macro_AUC = {}
macro_FPR = {}
macro_TPR = {}
# 获的每一个类别对应的TPR、FPR、AUC
for i in range(ytest_one.shape[1]):
macro_FPR[i],macro_TPR[i],thresholds = metrics.roc_curve(ytest_one[:,i], ytest_proba[:,i])
macro_AUC[i] = metrics.auc(macro_FPR[i],macro_TPR[i])
print(macro_AUC)
# 把所有的FPR合并去重、排序
macro_FPR_final = np.unique(np.concatenate([macro_FPR[i] for i in range(ytest_one.shape[1])]))
# 在每个类别中计算macro_FPR_final对应的TPR 并相加求平均
macro_TPR_all = np.zeros_like(macro_FPR_final)
for i in range(ytest_one.shape[1]):
macro_TPR_all = macro_TPR_all + np.interp(macro_FPR_final, macro_FPR[i], macro_TPR[i])
macro_TPR_final = macro_TPR_all / ytest_one.shape[1] # 注:当FPR对应多个TPR时,interp会返回最大的那个TPR
macro_AUC_final = metrics.auc(macro_FPR_final, macro_TPR_final)
# 计算最终的AUC
AUC_final = metrics.auc(FPR_final, TPR_final)
微平均大致思路:
微平均法的本质可以视为是将多分类问题转换成一个二分类问题,通过将转换成one-hot以后的原始标签矩阵以及建模后得到的每个类别的预测概率同时拉平(下面的例子中没放每个类别的预测概率),拉平后的新的标签矩阵将每一个元素(A-1,A-2等)都视为一个样本(如下例中共6*3=18个),同时每个样本下面的所对应的1,0代表是与否(例如新标签矩阵中的A-3就表示A是属于第三类的),最后用得到的新的二分类的标签矩阵求FPR与TPR
样本 | 类别1 | 类别2 | 类别3 |
A | 0 | 0 | 1 |
B | 1 | 0 | 0 |
C | 0 | 1 | 0 |
D | 1 | 0 | 0 |
E | 0 | 1 | 1 |
F | 1 | 0 | 0 |
A-1 | A-2 | A-3 | B-1 | ... | F-3 |
0 | 0 | 1 | 1 | ... | 0 |
微平均的代码实现:
'''微平均法'''
# 将标签、以及建模后得到的每个样本分类的预测概率拉平
micro_ytest_one = np.ravel(ytest_one)
micro_ytest_proba = np.ravel(ytest_proba)
# 计算微平均法下的FPR、TPR
micro_FPR,micro_TPR,mic_thresholds = metrics.roc_curve(micro_ytest_one, micro_ytest_proba)
micro_AUC = metrics.auc(micro_FPR,micro_TPR)
最后结果:
'''画图'''
plt.figure(figsize=(8,6))
plt.plot(macro_FPR[0],macro_TPR[0],'b.-', label='类别1ROC AUC={:.2f}'.format(macro_AUC[0]), lw=2)
plt.plot(macro_FPR[1],macro_TPR[1],'y.-', label='类别2ROC AUC={:.2f}'.format(macro_AUC[1]), lw=2)
plt.plot(macro_FPR[2],macro_TPR[2],'r.-', label='类别3ROC AUC={:.2f}'.format(macro_AUC[2]), lw=2)
plt.plot(macro_FPR_final,macro_TPR_final,'kx-', label='宏平均法ROC AUC={:.2f}'.format(macro_AUC_final), lw=2)
plt.plot(micro_FPR,micro_TPR,'k|-', label='微平均法ROC AUC={:.2f}'.format(micro_AUC),lw=2)
plt.plot([0,1], [0,1], 'k--', label='45度参考线')
plt.xlabel('FPR',fontsize=13)
plt.ylabel('TPR',fontsize=13)
plt.title('鸢尾花数据随机森林分类后的ROC和AUC',fontsize=13)
plt.grid(linestyle='-.')
plt.legend(loc='lower right',framealpha=0.8, fontsize=8)
plt.show()
参考的文章:
多分类-- ROC曲线 - 静悟生慧 - 博客园 (cnblogs.com)
【多分类ROC曲线 (2) 微平均法-哔哩哔哩】 https://b23.tv/GgRqzUj
注:本人水平有限,主要写来以后复盘看,有理解错的地方还请大佬指正