multi-class分类模型评估指标的定义、原理及其Python实现 (1)

96 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 23 天,点击查看活动详情

诸神缄默不语-个人CSDN博文目录

本文介绍multi-class分类任务中的模型评估指标及其使用Python的实现方式(包括使用sklearn进行实现,以及使用原生Python函数进行实现的操作)。

本文使用的示例是在英文多标签文本分类数据集AAPD数据集上,使用fastText包运算得到的多标签分类结果,与真实标签之间计算对应的指标结果(原则上使用one-label标签应该也能这么算,我就不另写了)。本文第一节将介绍相应数据的处理方式,第二节及其后是各指标的原理和计算方式。 fastText的使用方式可参考我之前写的博文:fastText Python 教程_诸神缄默不语的博客-CSDN博客_python 安装fasttext

@[toc]

1. 数据获取、模型运算与结果的储存和加载

数据下载地址:git.uwaterloo.ca/jimmylin/he… 由于fastText包运行文本分类模型用不到验证集,所以我把训练集和验证集合并作为训练集。

原始数据长这样:000000000000000000001000000000000000000000000010000000 the relation between pearson 's correlation coefficient and salton 's cosine measure is revealed based on the different possible values of the division of the l1 norm and the l2 norm of a vector these different values yield a sheaf of increasingly straight lines which form together a cloud of points , being the investigated relation the theoretical results are tested against the author co citation relations among 24 informetricians for whom two matrices can be constructed , based on co citations the asymmetric occurrence matrix and the symmetric co citation matrix both examples completely confirm the theoretical results the results enable us to specify an algorithm which provides a threshold value for the cosine above which none of the corresponding pearson correlations would be negative using this threshold value can be expected to optimize the visualization of the vector space

将原始数据处理为fastText适用的文件格式(理论上应该做的步骤:①使用NLTK进行分词,用法可参考我之前写的博文:NLTK使用教程(持续更新ing...)_诸神缄默不语的博客-CSDN博客 ②lowercase ③去除标点符号 ④更改格式 但是事实上我看了一下数据本身就已经做过了处理,所以直接更改格式了): (注意在这里我把测试集也做了转换,但是这个格式的文件fastText仅支持直接使用test()得到测试指标,而不支持得到预测结果,因此后文我没有使用这个测试文件。如果必须要用的话可以用get_line()函数做转换,我觉得比直接用原始文件还麻烦)

import re

def convert2label(str_int:str):
    """将类似000000000000000000001000000000000000000000000010000000的值转换为label的格式"""
    iter1=re.finditer('1',str_int)
    s=''
    for obj in iter1:
        s+='__label__'+str(obj.start())+' '
        
    return s

folder_name=r'data/cls/AAPD'
name_map={'train':'train','dev':'train','test':'test'}
for k in name_map:
    original_file=open(folder_name+r'/'+k+'.tsv').readlines()
    destination_file=open(folder_name+r'/fasttext_'+name_map[k]+'.txt','a')
    data=[x.split('\t') for x in original_file]
    data=[convert2label(x[0])+x[1] for x in data]
    destination_file.writelines(data)

处理之后长这样: 在这里插入图片描述

用fastText运行文本分类模型,得到测试结果,并将预测结果与原始标签的独热编码格式都存储为json对象(存储为独热编码格式是因为这样更普适):

import fasttext,json

model=fasttext.train_supervised('data/cls/AAPD/fasttext_train.txt',loss='ova')
test_text_list=[x.split('\t') for x in open('data/cls/AAPD/test.tsv').readlines()]
length=len(test_text_list)
label_list=[[int(y) for y in list(x[0])] for x in test_text_list]
json.dump(label_list,open('data/cls/AAPD/label.json','w'))
test_text_list=[x[1].strip() for x in test_text_list]
predict_result=model.predict(test_text_list,k=-1,threshold=0.5)
#第一个元素是预测结果列表,第二个元素是概率列表。每个元素(列表)的每个元素是一个值
predict_result=predict_result[0]  #每个元素是一个样本的预测结果,每个元素是__label__xx的格式
write_result=[[int(x[9:]) for x in y] for y in predict_result]  #转换为int格式
predict_list=[[0 for _ in range(54)] for _ in range(1000)]  #空列表
for sample_index in range(1000):  #这个我实在是凑不出来了,直接遍历吧,反正也不多
    sample=write_result[sample_index]
    for factor in sample:
        predict_list[sample_index][factor]=1
json.dump(predict_list,open('data/cls/AAPD/prediction.json','w'))

输出:

Read 9M words
Number of words:  69400
Number of labels: 54
Progress: 100.0% words/sec/thread:  423066 lr:  0.000000 avg.loss:  5.440953 ETA:   0h 0m 0s

存储结果: 在这里插入图片描述

2. 准确率accuracy

预测正确的样本(所有标签都预测正确)占所有样本的比例。

使用Python原生函数实现:

import json

label=json.load(open('data/cls/AAPD/label.json'))
prediction=json.load(open('data/cls/AAPD/prediction.json'))

accuracy=[label[x]==prediction[x] for x in range(len(label))].count(True)/len(label)
print(accuracy)

使用sklearn实现:

import json
from sklearn.metrics import accuracy_score

label=json.load(open('whj_project2/data/cls/AAPD/label.json'))
prediction=json.load(open('whj_project2/data/cls/AAPD/prediction.json'))

accuracy=accuracy_score(label,prediction)
print(accuracy)

(对应的函数文档:sklearn.metrics.accuracy_score — scikit-learn 1.1.1 documentation

输出:0.276