用Scikit-MultiLearn进行多标签分类
多标签分类允许我们对具有多个目标变量的数据集进行分类。在多标签分类中,我们有几个标签是给定预测的输出。在进行预测时,一个给定的输入可能属于一个以上的标签。
例如,当预测一个给定的电影类别时,它可能属于恐怖、浪漫、冒险、动作,或同时属于所有类别。在这个例子中,我们有多个标签可以分配给一个特定的电影。
在多类分类中,一个输入只属于一个标签。例如,当预测一个给定的图像是属于猫还是狗时,输出可以是猫或狗,但不能同时是猫和狗。
在本教程中,我们将处理多标签文本分类,我们将建立一个模型,将给定的文本输入分类为不同的类别。我们的文本输入可以同时属于多个类别或标签。
我们将使用scikit-multilearn来建立我们的模型。Scikit-multilearn是一个建立在scikit-learn之上的python库,最适合于多标签分类。
前提条件
读者必须具备。
- 对[Python]有良好的理解。
- 对[机器学习建模]有良好的理解。
- 下载数据集。
- 对[Pandas]和[Numpy]有一定了解。
注意:为了方便跟读,请使用Google Colab来建立你的模型。
多标签分类起源于对文本分类问题的研究,其中每个文档可能同时属于几个预定义的主题。
文本数据的多标签分类是一个重要的问题,需要先进的方法和专门的机器学习算法来预测多标签的类别。
在多标签问题中,一个文本可以被分配到多少个标签并没有约束,标签越多,问题就越复杂。为了解决这些问题,我们有专门针对多标签分类的不同方法和技术。
这些方法和技术如下。
- 问题转换。
- 适应性的算法。
- 集合方法。
问题转换
它指的是将多标签数据集转换为单标签数据集。
单标签数据集和问题是机器可读的,并使其易于建立模型。问题转换是通过以下技术完成的。
- 二元相关性
- 分类器链
- 标签权力集
二元相关性
这种技术将每个标签独立处理,然后将多标签分开作为单类分类。
让我们来看看这个例子,如下图所示。
我们有独立的特征X1,X2 和X3, 而目标变量或标签是Class1,Class2, 和Class3 。
在二元相关性中,多标签问题被分割成三个独特的单类分类问题,如下图所示。

当使用这种技术时,标签的相关性可能会丢失,因此我们引入了第二种技术。
分类器链
在这种技术中,我们有多个分类器以链的形式连接。第一个分类器是用输入数据建立的。下面的分类器是使用综合输入和给定链中的前一个分类器进行训练。
这是一个连续的过程,一个分类器的输出被用作链中下一个分类器的输入。
这个过程显示在下面的图片中。

为了更详细地了解,让我们使用这个图片中的例子。

在上面的图片中,绿色的方框是组合的输入,其余部分代表目标变量或标签。正如所见,它形成了一个链条,一个分类器的输出被用作下一个分类器的输入。所有这些都是按顺序进行的。
这种技术保留了标签的相关性,从而解决了二元相关性技术所遇到的问题。然而,它的准确性较低,因此,我们引入了第三种技术。
标签幂集
它将问题转化为一个多类问题。然后用数据中发现的独特标签组合来训练每个多类分类器。
标签幂集的目标是找到独特标签的组合,并给它们分配不同的值。让我们看一个例子。

在这个例子中,我们有三个独特的标签组合,然后将其赋值为:1,2 和3 。然后在所有三个独特的标签组合上训练多类分类器。
这种技术倾向于提供更高的准确性。
适应性算法
这种技术使用自适应算法,用来进行多标签分类,而不是直接进行问题转换。在Scikit-multilearn中,我们有多标签-k-近邻(MLkNN),它被用来处理多标签分类。
集合方法
这是一种混合技术,它结合了上述两种技术的功能以产生更好的结果。集合方法倾向于给出一个具有较高准确度的模型。
注意:在本教程中,我们将重点讨论第一种技术,即问题转换,以建立我们的模型。
在我们开始建立模型之前,让我们看看我们将要使用的数据集。
数据集
如前所述,我们将建立一个多标签文本分类,该模型将能够把给定的文本分类到不同的类别。
我们的数据集中的类别是:mysql 、python 、php 。一个文本可以属于一个或多个给定的类别。如果一个文本属于某个类别,它将被分配到1 ;如果不属于,它将被分配到0 ,如下图所示。

加载探索性数据分析包
探索性数据分析(EDA)包用于数据分析和数据处理。我们将使用pandas来读取我们的数据集,使用numpy来进行数学计算。
import pandas as pd
import numpy as np
我们使用pandas来加载我们的数据集。
df = pd.read_csv("dataset-tags.csv")
检查数据结构
我们检查结构,以便能够看到我们的数据集中的可用列。
df.head()
其输出结果如图所示。

上面的图片显示了我们数据集中的列。这些列是如下的。
title列包含在训练期间作为我们模型输入的文本。tags列包含分配给我们输入文本的各种标签。这些标签是:php,mysql和python。mysql列用于对属于mysql类别的文本进行分类。如果是mysql,它就会被分配到1,如果没有关系,就分配到0。php列用于对属于php类的文本进行分类。如果它是php,它将被分配到1.0,如果不相关,则分配到0.0。php列用于对属于python类的文本进行分类。如果它是python,它将被分配到1.0,如果不相关,则分配到0.0。
从上面的图片中,我们可以看到,有些文本同时属于不同的类。第一行的文本同时属于mysql 和python 。
我们的标签的数据类型
我们检查我们的标签的数据类型,因为它们需要有统一的数据类型。
df.dtypes
输出结果如图所示。
title object
tags object
mysql int64
python float64
php float64
dtype: object
如图所示,mysql 标签是一个整数。我们需要将数据类型从整数转换为浮点数,以便所有标签都有统一的数据类型。
我们使用astype(float) 方法将整数转换成浮点数。
df['mysql'] = df['mysql'].astype(float)
现在我们的数据集已经干净了,让我们导入机器学习包。
加载机器学习包
from sklearn.naive_bayes import GaussianNB,MultinomialNB
from sklearn.metrics import accuracy_score,hamming_loss
from sklearn.model_selection import train_test_split
from sklearn.feature_extraction.text import TfidfVectorizer
在上面的代码片段中,我们已经导入了以下内容。
MultinomialNB是在建立我们的模型时使用的Naive Bayes算法中发现的一种方法,它最适合于包含离散特征的分类,如文本。accuracy_score用于计算我们的模型在进行预测时的准确性。准确率分数通常以百分比表示。hamming_loss是用来确定一个给定模型的错误预测的比例。train_test_split是一种用于将我们的数据集分成两组的方法;训练集和测试集。TfidfVectorizer是一种统计措施,用于评估一个词与文档集合中的一个文档的相关程度。它通过检查单词在某个文档中出现的频率来实现这一目的。如果一个词经常出现在一个文件中,它的相关性就比一个文件中罕见的词要低。
安装Scikit-Multilearn
由于我们使用的是Google Colab,所以我们使用以下命令来安装这个库。
!pip install scikit-multilearn
这是我们将用来进行多标签文本分类的库。如前所述,本教程的重点是在建立我们的模型时进行问题转换。
我们需要导入所需的包来处理三种问题转换技术。正如前面所解释的,这三种问题转换技术是二进制相关性、分类器链和标签权力集。
导入问题转换包
我们将使用问题转换包来处理这三种技术。
from skmultilearn.problem_transform import BinaryRelevance
from skmultilearn.problem_transform import ClassifierChain
from skmultilearn.problem_transform import LabelPowerset
文本预处理
文本预处理包括去除停止词和去除噪声数据。停顿词是一个由特定语言中常见的所有单词组成的列表。
由于在预测分析过程中,停顿词的分类能力不高,因此被删除。在建立分类器时,它们往往会带来偏差。
我们删除那些在训练过程中影响我们的模型并给我们的模型带来错误的噪音数据。
为了进行文本预处理,我们需要安装neattext包。Neattext是一个用于文本数据清理和文本预处理的Python包。
让我们用下面的命令来安装它。
!pip install neattext
让我们加载这个包。
import neattext as nt
import neattext.functions as nfx
探索数据集中的噪声
噪声是我们的数据集中不需要的字符,在训练过程中可能影响我们的模型。
df['title'].apply(lambda x:nt.TextFrame(x).noise_scan())
其输出结果如图所示。
df['title'].apply(lambda x:nt.TextFrame(x).noise_scan())
0 {'text_noise': 11.267605633802818, 'text_lengt...
1 {'text_noise': 4.651162790697675, 'text_length...
2 {'text_noise': 9.90990990990991, 'text_length'...
3 {'text_noise': 8.47457627118644, 'text_length'...
4 {'text_noise': 2.631578947368421, 'text_length...
...
139 {'text_noise': 26.41509433962264, 'text_length...
140 {'text_noise': 3.8461538461538463, 'text_lengt...
141 {'text_noise': 6.666666666666667, 'text_length...
142 {'text_noise': 13.636363636363635, 'text_lengt...
143 {'text_noise': 7.142857142857142, 'text_length...
Name: title, Length: 144, dtype: object
我们从title 栏中探索噪声数据。它显示了从第一行0 到143 的所有包含噪声词的行以及这些行中的噪声数据。第一个值是11, ,最后一个是7 。我们现在可以从这些噪声数据中提取停止词。
提取停顿词
我们使用TextExtractor() 和extract_stopwords() 方法来提取我们的title 列中所有的停止词。
df['title'].apply(lambda x:nt.TextExtractor(x).extract_stopwords())
停止词的输出结果如图所示。
0 [when, are, the, and]
1 [two, for]
2 [the, of, that, a, and, the, and]
3 [in, a, and, and]
4 [using]
...
139 [where, in, using]
140 [to]
141 [and, get, using]
142 [how, to, the, of, a, with, a, back, into, the]
143 [in, if]
Name: title, Length: 144, dtype: object
我们现在可以删除这些停顿词。
删除停顿词
我们使用nfx.remove_stopwords 函数删除停顿词,如图所示。
df['title'].apply(nfx.remove_stopwords)
其输出结果如图所示。
df['title'].apply(nfx.remove_stopwords)
0 Flask-SQLAlchemy - tables/databases created de...
1 Combining PHP variables MySQL query
2 'Counting' number records match certain criteria...
3 Insert new row table auto-id number. Php MySQL
4 Create Multiple MySQL tables PHP
...
139 Executing "SELECT ... ... ..." MySQLdb
140 SQLAlchemy reconnect DB
141 MySQL Count Distinct result PHP
142 store result radio button database value, data...
143 Use SQL count result statement - PHP
Name: title, Length: 144, dtype: object
输出结果给出了一个新的数据集,所有的停止词都被删除了。
现在我们可以将干净的数据集保存在一个变量中。
corpus = df['title'].apply(nfx.remove_stopwords)
特征工程
特征工程包括从我们的数据中提取特征和属性。特征是用于预测分析的独立单元,可以影响输出。
我们将使用TfidfVectorizer() 包来进行特征提取,我们之前已经导入了这个包。
让我们初始化TfidfVectorizer() 。我们将使用它来从数据集中的文本中提取单词。它根据每个词在整个文本中出现的频率,将这些词转化为数值。
数字值将是我们模型的特征,并被用作模型的输入。数值比文本更容易被机器阅读;这就是为什么我们要将文本转换成数值。
tfidf = TfidfVectorizer()
在初始化之后,我们现在可以开始提取特征了。
提取特征
如上所述,这些特征将是数字值。在训练和预测分析中,这些特征将被用作模型的输入。
Xfeatures = tfidf.fit_transform(corpus).toarray()
我们从corpus 中提取特征。corpus 是包含我们删除了所有停顿词的干净数据集的变量。
tfidf.fit_transform 我们使用了 "数据 "来提取文本中的单词(特征),并将其转化为我们的模型能够理解的数值。
我们最后将我们的特征转换成一个数组,使其成为机器可读的。数组可以很容易地被加载到我们的模型中。
要查看我们的特征数组,请使用这个命令。
Xfeatures
输出如图所示。
array([[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],])
获取标签
标签是我们试图预测的输出。我们的标签是。mysql,python 和php 。
y = df[['mysql', 'python', 'php']]
数据集分割
我们把数据集分成训练集和测试集。
我们将使用训练集来建立我们的模型,而测试集则是衡量模型的性能。我们使用train_test_split ,将我们的数据集分成两部分。数据集的70%被用作训练集,30%被用作测试集。
X_train,X_test,y_train,y_test = train_test_split(Xfeatures,y,test_size=0.3,random_state=42)
建立模型
我们将使用问题转换技术建立我们的模型。
让我们从第一个技术开始。
二元相关性技术
这是用来将我们的多标签问题转换为多类问题。让我们来初始化这个技术。
binary_rel_clf = BinaryRelevance(MultinomialNB())
我们还添加了MultinomialNB() 方法。MultinomialNB() 是用于分类的Naive Bayes算法方法。
这很重要,因为通过将我们的多标签问题转换为多类问题,我们需要一个算法来处理这个多类问题。
模型拟合
我们将模型拟合到数据集中,从数据集中识别模式,并自行学习。
binary_rel_clf.fit(X_train,y_train)
训练之后,这就是输出。
BinaryRelevance(classifier=MultinomialNB(alpha=1.0, class_prior=None,
fit_prior=True),
require_dense=[True, True])
如图所示,它使用MultinomialNB() ,处理转换后的多类问题。
测试我们的模型
我们使用测试数据来测试我们的模型。我们看看该模型是否能使用测试数据进行预测。
br_prediction = binary_rel_clf.predict(X_test)
使用这个命令,可以得到数组形式的预测输出。
br_prediction.toarray()
输出结果显示出来了。
array([[1., 0., 1.],
[1., 0., 1.],
[1., 1., 0.],
[1., 0., 1.],
[1., 0., 1.],
[1., 0., 1.],
[1., 0., 1.],
[1., 1., 0.],
[1., 1., 0.],
[1., 0., 1.],
[1., 0., 1.],
[1., 0., 1.],
[1., 0., 1.],])
上面的输出显示了我们的模型是如何将不同的文本分为三个类别的。如果一个文本属于那个特定的类别,它被分配到1 ,否则,它被分配到0 。
让我们计算一下准确率得分。
准确率得分
accuracy_score(y_test,br_prediction)
的输出。
0.9090909090909091
这表明我们的模型的准确度得分是90.91 。这对我们的模型来说是一个很好的准确度,我们的模型有更大的机会做出准确的预测。
获取汉明损失
汉明损失是用来确定一个给定模型的不正确预测的部分。汉明损失越低,我们的模型就越能做出预测。
hamming_loss(y_test,br_prediction)
其输出结果如图所示。
0.06060606060606061
汉明损失是指错误预测的标签的比例。在上面的输出中,我们的汉明损失是6.06% ,以百分比表示。这表明在所有的预测中,只有6.06% 是错误的。
这个百分比很低,表明我们的模型训练有素。持续的训练将减少这个百分比,使模型更加准确。
让我们来看看下一个技术。
分类器链技术
这种技术保留了标签相关性,即一个分类器的输出被用作链中下一个分类器的输入。这个过程按顺序发生。
让我们创建一个函数来帮助我们建立链中的第一个分类器。
def build_model(model,mlb_estimator,xtrain,ytrain,xtest,ytest):
clf = mlb_estimator(model)
clf.fit(xtrain,ytrain)
clf_predictions = clf.predict(xtest)
acc = accuracy_score(ytest,clf_predictions)
ham = hamming_loss(ytest,clf_predictions)
result = {"accuracy:":acc,"hamming_score":ham}
return result
上述函数使用多标签估计器算法来建立我们的模型。我们把多标签估计器算法命名为mlb_estimator 。我们还将我们的模型装入数据集,以便它能理解模式并从中学习。
在使用mlb_estimator 构建我们的第一个分类器实例并将其拟合到我们的训练集和测试集之后,我们使用accuracy_score 方法计算准确率分数,使用hamming_loss 方法计算hamming loss。
然后,我们的函数输出计算出的准确率和汉明分。
这就是第一个分类器。我们将使用这个分类器的结果作为下一个分类器的输入特征。
下一个分类器
上面创建的build_model 函数是这个分类器的输入。
clf_chain_model = build_model(MultinomialNB(),ClassifierChain,X_train,y_train,X_test,y_test)
在这个例子中,我们使用MultinomialNB() 作为分类算法。我们还需要初始化我们的ClassifierChain() 方法,以表明我们正在处理分类器链技术。
在这种情况下,我们将使用下面的命令,让两个分类器链在一起,以得到最终的准确率分数。
clf_chain_model
其输出结果如图所示。
{'accuracy:': 0.8409090909090909, 'hamming_score': 0.10606060606060606}
该技术的准确度得分略低于二元相关技术。以百分比表示的准确率约为84.09% 。Hamming损失是10.6% ;与之前的技术相比,这个百分比相对较高。这表明二元相关技术比分类器链技术要好。
让我们到最后一项技术来比较这三种技术,看看哪一种是最好的。
标签集技术
这项技术确保生成的多类分类器是在我们的数据中所有可能的标签组合上训练的。让我们看看它是如何工作的。
clf_labelP_model = build_model(MultinomialNB(),LabelPowerset,X_train,y_train,X_test,y_test)
我们使用MultinomialNB() 方法作为我们转化的多类分类器的分类算法。我们还初始化了LabelPowerset ,以表明我们正在处理labelPowerset技术。
最后,我们传递我们的训练集,和测试集数据,以便我们的模型可以使用它进行预测分析。
让我们得到这个技术的准确度分数和hamming loss。
clf_labelP_model
输出结果如图所示。
{'accuracy:': 0.9090909090909091, 'hamming_score': 0.06060606060606061}
这给出的准确率分数为90.9% ,这是一个不错的准确率分数。当我们比较这三种技术的准确度时,二元相关性和标签权力集技术由于其较高的准确度,将最适合于多标签分类。
本教程展示了如何使用问题转换技术来建立一个多标签文本分类模型。
做一个单一的预测
预测是用来评估一个模型,看它的学习效果如何。
获得一个样本文本
ex1 = df['title'].iloc[0]
这将从我们的数据集中的title 列中获得第一个文本:Flask-SQLAlchemy - When are the tables/databases created and destroyed? 。
向量化我们的样本文本
这将把我们的样本文本转换为数字表示,以便于我们的模型阅读。
我们使用tfidf.transform() 方法来转换我们的文本。
vec_example = tfidf.transform([ex1])
进行预测
我们使用二元相关性分类器来进行预测。
binary_rel_clf.predict(vec_example).toarray()
如图所示,使用toarray() 方法将输出转换为一个数组。
array([[1., 1., 0.]])
这是一个准确的预测,因为它与我们的数据集中的标签精确匹配。
总结
本教程对那些想学习多标签文本分类的人来说是有帮助的。我们从多类分类和多标签分类之间的区别开始。然后我们了解了用于多标签分类的三种不同方法。
最后,我们能够使用我们的模型进行预测。这就衡量了模型的好坏。如果一个模型能够准确地进行预测,那么这个模型就越好。使用这些步骤,读者应该可以轻松地用scikit-multi learn建立一个多标签文本分类模型。