龙空技术网

机器学习:多标签分类的Python之旅

林小婵的店 558

前言:

此时同学们对“html两种标签分类方法”大概比较珍视,姐妹们都想要了解一些“html两种标签分类方法”的相关文章。那么小编也在网摘上收集了一些有关“html两种标签分类方法””的相关文章,希望咱们能喜欢,各位老铁们快快来了解一下吧!

第1部分:多标签分类概述:

多标签分类起源于对文本分类问题的调查,其中每个文档可能同时属于多个预定义主题。

文本数据的多标签分类是机器学习中一个重要的问题。范例从新闻文章到电子邮件。例如,这可以用于基于其情节的总结来找到电影所属的类型。

图1:根据情节汇总查找流派的多标签分类

或基于电影海报的流派的多标签分类。(这进入了计算机视觉领域。)

图2:多标签分类根据电影海报查找流派

多类分类和多标签分类之间的区别在于,在多类问题中,类是相互排斥的,而对于多标签问题,每个标签表示不同的分类任务,但是任务有某种相关性。

例如,多类分类假设每个样品都被分配到一个且仅有一个标签:水果可以是苹果或梨,但不能同时存在。然而,多标签分类的一个例子可能是文本可能是关于宗教,政治,金融或教育的任何一个,或者都不是这些。

第2部分:问题定义和评估指标:

问题定义:

恶意评论分类是具有高度不平衡数据集的多标签文本分类问题。

我们面临着构建多标签模型的挑战,该模型能够检测威胁,淫秽,侮辱和身份仇恨等不同类型的恶意。我们需要创建一个模型来预测每个评论的每种恶意的可能性。

可以在这里找到Kaggle链接到这个问题()。

评估指标:

注意:最初Kaggle挑战中的评估指标是Log-Loss,后来更改为AUC。但是在这篇文章中,我们也会对其他评估指标进行评估。

单标签的评估措施通常与多标签不同。在单标签分类中,我们使用简单的度量标准,如精度,召回率,准确度等。比如,在单标签分类中,准确度只是:

图-3:单标签分类的准确度

在多标签分类中,错误分类不再是一个严重的错误或正确的分类。包含实际类别的子集的预测应该被认为比不包含它们的预测更好,即,正确地预测三个标签中的两个,这比完全不预测标签更好。

微平均和宏平均(基于标签的度量):

为了测量多类分类器,我们必须以某种方式平均分类。有两种不同的方法称为微平均和宏平均。

在微平均所有TP中,总结每个类的TN,FP和FN,然后取平均值。

Fig-4: Micro-Averaging

在微平均法中,您可以总结系统对于不同集合的个体真实肯定,误报和误报,并应用它们。而微平均F1分数将仅仅是上述两个方程的调和平均值。

宏平均是直截了当的。我们只是将系统的精度和召回的平均值放在不同的集合上。

图-5:宏平均

当您想知道系统如何在整个数据集上执行整体操作时,可以使用宏平均方法。你不应该拿这个平均数作出任何具体的决定。另一方面,当数据集大小不一时,微平均可能是一个有用的衡量指标。

Hamming-Loss(基于实例的度量):

用最简单的术语来说,Hamming-Loss是错误预测的标签部分,即错误标签的一小部分与标签总数的比例。

完全匹配率(子集精度):

它是最严格的度量标准,指示标签分类正确的样本的百分比。

的缺点是多类分类问题有部分正确的可能性,但在这里我们忽略了那些部分正确的匹配。

scikit-learn中有一个实现子集精度的函数,称为precision_score 。

第3部分:探索性数据分析(EDA):

探索性数据分析是数据分析过程中的重要步骤之一。在这里,重点是掌握手中的数据 - 诸如制定正确的问题以询问数据集,如何操作数据源以获取所需的答案等。

首先让我们导入必要的库。

import os

import csv

import pandas as pd

import numpy as np

import matplotlib.pyplot as plt

import seaborn as sns

接下来,我们将来自csv文件的数据加载到pandas dataframe中并检查其属性。

data_path = "/Users/kartik/Desktop/AAIC/Projects/jigsaw-toxic-comment-classification-challenge/data/train.csv"

data_raw = pd.read_csv(data_path)

print("Number of rows in data =",data_raw.shape[0])

print("Number of columns in data =",data_raw.shape[1])

print("\n")

print("**Sample data:**")

data_raw.head()

现在我们计算每个标签下的评论数量(Python代码如下)

categories = list(data_raw.columns.values)

sns.set(font_scale = 2)

plt.figure(figsize=(15,8))

ax= sns.barplot(categories, data_raw.iloc[:,2:].sum().values)

plt.title("Comments in each category", fontsize=24)

plt.ylabel('Number of comments', fontsize=18)

plt.xlabel('Comment Type ', fontsize=18)

#adding the text labels

rects = ax.patches

labels = data_raw.iloc[:,2:].sum().values

for rect, label in zip(rects, labels):

height = rect.get_height()

ax.text(rect.get_x() + rect.get_width()/2, height + 5, label, ha='center', va='bottom', fontsize=18)

plt.show()

图-9:每个标签下的评论数量

计算具有多个标签的评论数量(Python代码如下)

rowSums = data_raw.iloc[:,2:].sum(axis=1)

multiLabel_counts = rowSums.value_counts()

multiLabel_counts = multiLabel_counts.iloc[1:]

sns.set(font_scale = 2)

plt.figure(figsize=(15,8))

ax = sns.barplot(multiLabel_counts.index, multiLabel_counts.values)

plt.title("Comments having multiple labels ")

plt.ylabel('Number of comments', fontsize=18)

plt.xlabel('Number of labels', fontsize=18)

#adding the text labels

rects = ax.patches

labels = multiLabel_counts.values

for rect, label in zip(rects, labels):

height = rect.get_height()

ax.text(rect.get_x() + rect.get_width()/2, height + 5, label, ha='center', va='bottom')

plt.show()

图10:具有多个标签的评论数量

在每个评论类别中使用最多的词的WordCloud表示

from wordcloud import WordCloud,STOPWORDS

plt.figure(figsize=(40,25))

# toxic

subset = data_raw[data_raw.toxic==1]

text = subset.comment_text.values

cloud_toxic = WordCloud(

stopwords=STOPWORDS,

background_color='black',

collocations=False,

width=2500,

height=1800

).generate(" ".join(text))

plt.subplot(2, 3, 1)

plt.axis('off')

plt.title("Toxic",fontsize=40)

plt.imshow(cloud_toxic)

# Same code can be used to generate wordclouds of other categories.

第4部分:数据预处理:

我们首先将注释转换为小写,然后使用自定义功能从注释中删除html标签,标点符号和非字母字符。(Python代码如下)

import nltk

from nltk.corpus import stopwords

from nltk.stem.snowball import SnowballStemmer

import re

import sys

import warnings

data = data_raw

if not sys.warnoptions:

warnings.simplefilter("ignore")

def cleanHtml(sentence):

cleanr = re.compile('<.*?>')

cleantext = re.sub(cleanr, ' ', str(sentence))

return cleantext

def cleanPunc(sentence): #function to clean the word of any punctuation or special characters

cleaned = re.sub(r'[?|!|\'|"|#]',r'',sentence)

cleaned = re.sub(r'[.|,|)|(|\|/]',r' ',cleaned)

cleaned = cleaned.strip()

cleaned = cleaned.replace("\n"," ")

return cleaned

def keepAlpha(sentence):

alpha_sent = ""

for word in sentence.split():

alpha_word = re.sub('[^a-z A-Z]+', ' ', word)

alpha_sent += alpha_word

alpha_sent += " "

alpha_sent = alpha_sent.strip()

return alpha_sent

data['comment_text'] = data['comment_text'].str.lower()

data['comment_text'] = data['comment_text'].apply(cleanHtml)

data['comment_text'] = data['comment_text'].apply(cleanPunc)

data['comment_text'] = data['comment_text'].apply(keepAlpha)

使用可以从NLTK库下载的默认停止词集删除注释中出现的所有停止词。我们还在标准列表中添加了一些停止的词。

Stop words基本上是任何语言中常用的一组单词,而不仅仅是英语。停止单词对许多应用程序来说至关重要的原因是,如果我们删除在给定语言中非常常用的单词,我们可以将重点放在重要的单词上。

stop_words = set(stopwords.words('english'))

stop_words.update(['zero','one','two','three','four','five','six','seven','eight','nine','ten','may','also','across','among','beside','however','yet','within'])

re_stop_words = re.compile(r"\b(" + "|".join(stop_words) + ")\\W", re.I)

def removeStopWords(sentence):

global re_stop_words

return re_stop_words.sub(" ", sentence)

data['comment_text'] = data['comment_text'].apply(removeStopWords)

接下来我们会stemming。存在不同类型的词干,基本上将具有大致相同语义的词语转换成一种标准格式。例如,amusing, amusement, and amused,词干将是amus。

stemmer = SnowballStemmer("english")

def stemming(sentence):

stemSentence = ""

for word in sentence.split():

stem = stemmer.stem(word)

stemSentence += stem

stemSentence += " "

stemSentence = stemSentence.strip()

return stemSentence

data['comment_text'] = data['comment_text'].apply(stemming)

将数据集分解为训练集和测试集后,我们要总结我们的评论并将它们转换为数值向量。

一种技术是挑选最频繁出现的词语(具有高频词或tf的词)。然而,最常用的词是一个不太有用的度量标准,因为像' this ',' a ' 这样的词在所有文档中出现得非常频繁。

因此,我们也希望衡量一个单词的独特性,例如,在所有文档中出现该单词的频率如何(反转文档频率或idf)。

因此,一个单词的tf&idf(TF-IDF)的乘积给出了该单词在文档中的频繁程度乘以单词与整个文档语料库的唯一性的乘积。

文档中具有高tfidf分数的文字经常出现在文档中,并提供有关该特定文档的大部分信息。

from sklearn.model_selection import train_test_split

train, test = train_test_split(data, random_state=42, test_size=0.30, shuffle=True)

from sklearn.feature_extraction.text import TfidfVectorizer

vectorizer = TfidfVectorizer(strip_accents='unicode', analyzer='word', ngram_range=(1,3), norm='l2')

vectorizer.fit(train_text)

vectorizer.fit(test_text)

x_train = vectorizer.transform(train_text)

y_train = train.drop(labels = ['id','comment_text'], axis=1)

x_test = vectorizer.transform(test_text)

y_test = test.drop(labels = ['id','comment_text'], axis=1)

TF-IDF易于计算,但缺点是它不能捕获文本中的位置,语义,不同文档中的共现等。

第5部分:多标签分类技术:

大多数传统学习算法都是针对单标签分类问题开发的。因此,文献中的很多方法将多标签问题转换为多个单标签问题,从而可以使用现有的单标签算法。

1、OneVsRest

传统的两类和多类问题都可以通过将每个实例限制为只有一个标签来投入多标签问题。另一方面,多标签问题的普遍性不可避免地使其更难以学习。解决多标签问题的直观方法是将其分解成多个独立的二元分类问题(每个类别一个)。

在“one-to-rest”策略中,可以构建多个独立的分类器,并且,对于不可见的实例,选择置信被最大化的类。

这里的主要假设是标签是互斥的。您不会考虑此方法中类之间的任何基础关联。

例如,它更像是提出简单的问题,比如说“ 评论是否有恶意 ”,“ 评论是否有威胁?“等等。此外,这里可能会出现大量过度配合的情况,因为大多数评论都是未标记的,即,大多数评论都是干净的评论。

from sklearn.linear_model import LogisticRegression

from sklearn.pipeline import Pipeline

from sklearn.metrics import accuracy_score

from sklearn.multiclass import OneVsRestClassifier

# Using pipeline for applying logistic regression and one vs rest classifier

LogReg_pipeline = Pipeline([

('clf', OneVsRestClassifier(LogisticRegression(solver='sag'), n_jobs=-1)),

])

for category in categories:

print('**Processing {} comments...**'.format(category))

# Training logistic regression model on train data

LogReg_pipeline.fit(x_train, train[category])

# calculating test accuracy

prediction = LogReg_pipeline.predict(x_test)

print('Test accuracy is {}'.format(accuracy_score(test[category], prediction)))

print("\n")

2.二元相关性

在这种情况下,单标签二进制分类器的集合被训练,每个类都有一个。每个分类器预测一个类的成员资格或非成员资格。预测的所有类的联合被视为多标签输出。这种方法很流行,因为它很容易实现,但它也忽略了类标签之间可能的相关性。

换句话说,如果有q个标签,则二元相关方法从图像中创建q个新的数据集,每个新的数据集上的每个标签和训练单标签分类器一个。一个分类器可以回答“是否包含树?”这个问题的是/否,因此是“二元相关性”中的“二元”。这是一种简单的方法,但在标签之间存在依赖关系时不起作用。

OneVsRest和二进制相关性看起来非常相似。如果OneVsRest中的多个分类器回答“是”,那么您就回到了二元相关方案。

# using binary relevance

from skmultilearn.problem_transform import BinaryRelevance

from sklearn.naive_bayes import GaussianNB

# initialize binary relevance multi-label classifier

# with a gaussian naive bayes base classifier

classifier = BinaryRelevance(GaussianNB())

# train

classifier.fit(x_train, y_train)

# predict

predictions = classifier.predict(x_test)

# accuracy

print("Accuracy = ",accuracy_score(y_test,predictions))

Output:

Accuracy = 0.856666666667

3.分类链

一系列二进制分类器C0,C1,...。。。,Cn被构造,其中分类器Ci使用所有分类器Cj的预测,其中j <i。这种方法也被称为分类器链(CC),可以考虑标签相关性。

这种方法所需的分类器总数等于类的数量,但分类器的训练更多地涉及。

以下是按照该顺序链接三个类别{C1,C2,C3}的分类问题的示例。

# using classifier chains

from skmultilearn.problem_transform import ClassifierChain

from sklearn.linear_model import LogisticRegression

# initialize classifier chains multi-label classifier

classifier = ClassifierChain(LogisticRegression())

# Training logistic regression model on train data

classifier.fit(x_train, y_train)

# predict

predictions = classifier.predict(x_test)

# accuracy

print("Accuracy = ",accuracy_score(y_test,predictions))

print("\n")

Output:

Accuracy = 0.893333333333

4.Label Powerset

这种方法确实考虑了类别标签之间的可能相关性。更常见的是,这种方法被称为Label - powerset方法,因为它将训练集中标签的幂集合中的每个成员视为单个标签。

该方法需要最差情况(2 ^ | C |)分类器,并且计算复杂度高。

然而,当类别数量增加时,不同标签组合的数量可以呈指数增长。这很容易导致组合爆炸,从而导致计算不可行。此外,一些标签组合将只有很少的正面例子。

# using Label Powerset

from skmultilearn.problem_transform import LabelPowerset

# initialize label powerset multi-label classifier

classifier = LabelPowerset(LogisticRegression())

# train

classifier.fit(x_train, y_train)

# predict

predictions = classifier.predict(x_test)

# accuracy

print("Accuracy = ",accuracy_score(y_test,predictions))

print("\n")

Output:

Accuracy = 0.893333333333

5.Adapted 算法

用于多标签分类的算法适应方法通常通过改变成本/决策函数来集中于将单标签分类算法适配到多标签情况。

这里我们使用一个多标签的懒学习方法ML-KNN,它是从传统的K最近邻(KNN)算法中导出的。

该skmultilearn.adapt模块实现了多标签分类的算法适应方法,包括但不限于ML-KNN。

from skmultilearn.adapt import MLkNN

from scipy.sparse import csr_matrix, lil_matrix

classifier_new = MLkNN(k=10)

# Note that this classifier can throw up errors when handling sparse matrices.

x_train = lil_matrix(x_train).toarray()

y_train = lil_matrix(y_train).toarray()

x_test = lil_matrix(x_test).toarray()

# train

classifier_new.fit(x_train, y_train)

# predict

predictions_new = classifier_new.predict(x_test)

# accuracy

print("Accuracy = ",accuracy_score(y_test,predictions_new))

print("\n")

Output:

Accuracy = 0.88166666667

结果:

解决多标签分类问题的主要方法有两种:问题转换方法和算法适应方法。

问题转换方法将多标签问题转换为一组二进制分类问题,然后可以使用单类分类器处理这些问题。

而算法适应方法则是将算法直接进行多标签分类。换句话说,他们不是试图将问题转化为更简单的问题,而是试图以完整的形式来解决问题。

在与其他方法的广泛比较中,label-powerset方法得分最高,其次是one-against-all方法。

在这个数据集上运行时,ML-KNN和label-powerset都需要相当长的时间,所以在随机抽取的火车数据样本上进行了实验。

进一步的改进:

在深度学习中使用LSTMs可以解决同样的问题。

为了获得更高的速度,我们可以使用决策树,为了在速度和精度之间进行合理的权衡,我们也可以选择集成模型。

其他框架如MEKA可以用于处理多标签分类问题。

标签: #html两种标签分类方法