基于 Python 的文本分类简介

欢迎关注 “小白玩转Python”,发现更多 “有趣”

机器学习在过去的几年中已经获得了它的影响力。通过使用它,有许多应用,从市场营销,生物信息学,城市规划,等等。机器学习是一种从数据中学习表示的方法,因此我们可以用它来提取知识或基于它来预测标签。其中的一个常见应用是文本分类。

文本分类是将文本按照其所属类别进行分类的一项工作。在机器学习成为一种趋势之前,这项工作大多是由几个注释者手工完成的。这在将来会成为一个问题,因为数据会变得更大,而且仅仅因为这样做就会花费大量的时间。因此,我们应该自动化的任务,同时也获得更高的准确性。

在本文中,我将向您展示如何使用 Python 进行文本分类。对于数据集,我们将使用 Kaggle 竞赛的数据集,名为真实与否?NLP with Disaster Tweets。我还在 Google Colab 上制作了这个笔记本,你可以在这里访问它:https://colab.research.google.com/drive/1nIJDAhMHeBrOtkyicQW1Z7Iykb2kB6mA?usp=sharing。

目录

本文将分为几个部分:

  • 文本预处理

  • 建立一个 TF-IDF 加权的文档术语矩阵

  • 朴素贝叶斯的概念

  • 使用 Python 进行实现

过程

文本预处理

我们要做的第一步是准备和清理数据集。清理数据集是移除任何无意义的单词或无用的术语,比如 # 号标签、提及、标点等等的关键步骤。

为了清理文本,我们可以使用类似 re 的库来删除带有模式的术语,使用 NLTK 来删除单词,例如:停顿词。我还解释了如何使用 Python 一步一步地清理文本,我们在之前的文章中已有介绍,大家可以点击《使用Python清洗文本数据》进行查看。

以下是一些文本在预处理之前的样子,

Our Deeds are the Reason of this #earthquake May ALLAH Forgive us allForest fire near La Ronge Sask. CanadaAll residents asked to 'shelter in place' are being notified by officers. No other evacuation or shelter in place orders are expected13,000 people receive #wildfires evacuation orders in California Just got sent this photo from Ruby #Alaska as smoke from #wildfires pours into a school #RockyFire Update => California Hwy. 20 closed in both directions due to Lake County fire - #CAfire #wildfires#flood #disaster Heavy rain causes flash flooding of streets in Manitou, Colorado Springs areasI'm on top of the hill and I can see a fire in the woods...There's an emergency evacuation happening now in the building across the streetI'm afraid that the tornado is coming to our area...

执行任务的代码如下所示:

# # In case of import errors
# ! pip install nltk
# ! pip install textblobimport re
from textblob import TextBlob
import nltk
from nltk.stem import WordNetLemmatizer
from nltk.corpus import stopwords# # In case of any corpus are missing 
# download all-nltk
nltk.download()df = pd.read_csv('train.csv')
test = pd.read_csv('test.csv')stop_words = stopwords.words("english")def text_preproc(x):
  x = x.lower()
  # x = ' '.join(wordnet.lemmatize(word, 'v') for word in x.split())
  x = ' '.join([word for word in x.split(' ') if word not in stop_words])
  x = x.encode('ascii', 'ignore').decode()
  x = re.sub(r'https*\S+', ' ', x)
  x = re.sub(r'@\S+', ' ', x)
  x = re.sub(r'#\S+', ' ', x)
  x = re.sub(r'\'\w+', '', x)
  x = re.sub('[%s]' % re.escape(string.punctuation), ' ', x)
  x = re.sub(r'\w*\d+\w*', '', x)
  x = re.sub(r'\s{2,}', ' ', x)
  return xdf['clean_text'] = df.text.apply(text_preproc)
test['clean_text'] = test.text.apply(text_preproc)

这是清洗步骤后的结果:

deeds reason may allah forgive usforest fire near la ronge sask canadaresidents asked place notified officers evacuation shelter place orders expectedpeople receive evacuation orders californiagot sent photo ruby smoke pours schoolupdate california hwy closed directions due lake county fireheavy rain causes flash flooding streets manitou colorado springs areasi top hill see fire woodsthere emergency evacuation happening building across streeti afraid tornado coming area

还有,记笔记!确保您从 NLTK 下载了所有的软件包和语料库(基本上是一组单词)。

建立一个 TF-IDF 加权的术语文档矩阵

在我们清理完数据之后,现在我们可以建立一个文本表示,这样计算机就可以轻松地读取数据。我们将使用术语文档矩阵作为文本的表示形式。

词项 - 文档矩阵(TDM)是一个矩阵,行表示每个文档,列表示每个术语(word) ,单元格填充一个数字。

单元格由每个文档上的字数组成。其中一种可以用来填充的方法叫做词频 - 逆向文件频率(TF-IDF)。

词频 - 逆向文件频率(TF-IDF)是词频(TF)与所有逆向文件频率(IDF)之间的乘积。

词频(TF)是计算文档中术语数量的公式。因为每个单词的数量不同,所以我们使用以10为基数的日志对其进行重新排序。看起来是这样的,

逆向文件频率(IDF)是一个计算所有文档文字稀有性的公式。如果这个数字很小,那么这个词就是频繁的。但是如果它更大,这个词就不那么频繁了。这个公式将用作 TF 的权重,它看起来像这样,

为了创建一个词项 - 文档矩阵(TDM) ,我们可以使用 sklearn 库中的一个名为 TfidfVectorizer 的函数。代码是这样的:

vectorizer = TfidfVectorizer()


X = vectorizer.fit_transform(df['clean_text']).toarray()
df_new = pd.DataFrame(X, columns=vectorizer.get_feature_names())


X_test = vectorizer.transform(test['clean_text']).toarray()
test_new = pd.DataFrame(X_test, columns=vectorizer.get_feature_names())

在编写代码时,必须非常小心为每个数据集使用哪个函数。对于训练数据,请确保使用 fit_transform 方法,因为它将根据训练数据中的词项数量进行匹配,并将其转换为矩阵。

同时,对于测试数据,请确保使用了转换方法,因为它将把文本转换为具有相同列数的列的矩阵。如果我们也对其使用 fit_transform,那么它将根据测试数据上的项数创建一个矩阵。因此,它在列上将不具有相同的维度,所以请确保检查将要使用的方法。

如果我们做得对的话,它会给矩阵相同的列的维数,还有一个像这样的矩阵:

朴素贝叶斯的概念

有了矩阵之后,现在我们可以将它应用到模型中。我们将使用的模型是朴素贝叶斯。

朴素贝叶斯是一个机器学习模型,它通过计算数据属于某个类的概率来解决监督式学习任务。

它基于贝叶斯原理,并假定文档中的每个术语都是相互独立的。计算这个的公式是这样的,

让我来解释一下

  •  P (c | d)表示一个文档属于一个类的概率,

  •  阿尔法符号对应两边的比例,

  • P(c)是类别的先验概率,计算类别数目占文件总数的比例。公式是这样的:

其中 Nc 是数据集上对应类的数量,n 是数据集上的文档数量。

  • P (tid | c)的乘积是文档(d)中属于类(c)的每个项的概率结果的乘积。公式是这样的:

如果 Tct 对应的是类内的术语数量,Tct’的和对应的是给定类的术语总数,B 代表训练数据集上不同的词汇数量,1代表避免零的平滑模型。

根据我们对问题的描述,P(tid | c)公式会有所不同。前面一个把它定义为一个多项式问题,我们计算一个类中确切的项数。我们有时把这个模型称为多项朴素贝叶斯模型。

还有一个叫做 Bernoulli Naive Bayes 的模型,其中 P(t id | c)的计算是不同的。它将计算包含该术语的文档数目占所有文档总数的比例。公式是这样的:

其中 Nct 对应于包含该类的术语的文档总数,而 Nc 对应于该类的文档总数。

在计算每个概率之后,我们将选择概率最高的最佳类。

使用 Python 实现

在我向您解释了这些概念之后,让我们继续讨论实现。对于这一步,我将使用 scikit-learn 库来完成。

当我们建立模型时,要知道的重要方面是模型是否能给出一个很好的结果,特别是对于看不见的数据,所以我们有信心使用它。我们可以通过一个叫做交叉验证的概念来做到这一点。代码是这样的:

from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.model_selection import KFold
from sklearn.metrics import f1_scoreX = df_new.values
y = df.target.valueskfold = KFold(n_splits=10)# Define the model
nb_multinomial = MultinomialNB()
nb_bernoulli = BernoulliNB()# As a storage of the model's performance
def calculate_f1(model):
 metrics = []
 
 for train_idx, test_idx in kfold.split(X):
   X_train, X_test = X[train_idx], X[test_idx]
   y_train, y_test = y[train_idx], y[test_idx]
   model.fit(X_train, y_train)
   y_pred = model.predict(X_test)
   metrics.append(f1_score(y_test, y_pred))
 
 # Retrieve the mean of the result
 print("%.3f" % np.array(metrics).mean())
calculate_f1(nb_multinomial)
>>> 0.681calculate_f1(nb_bernoulli)
>>> 0.704

计算 f1函数的过程是怎样的?

  • 首先,它将把模型作为输入

  • 然后,它将执行一个 k 次的交叉验证,在每个循环中,它将把数据集分成训练和测试数据集,然后模型适合训练数据并预测测试数据上的标签

  • 最后,我们计算每个交叉验证的平均值

在此基础上,得出贝努利朴素贝叶斯模型得分最高(0.704) ,多项式朴素贝叶斯模型得分最高(0.681)。

因此,我们将使用贝努利朴素贝叶斯作为我们的模型来预测真正的测试集数据。代码是这样的:

from sklearn.naive_bayes import BernoulliNBdef predict_to_csv(model, X, y):
  model.fit(X, y)
  X_test = test_new.values
  y_pred = model.predict(X_test)  # Preparing submission
  submission = pd.DataFrame()
  submission['id'] = test['id']
  submission['target'] = y_pred
  submission.to_csv('file_name.csv', index=False)  # Validate
  submission = pd.read_csv('file_name.csv')
  print(submission.head())
nb_bernoulli = BernoulliNB()
X = df_new.values
y = df.target.valuespredict_to_csv(nb_bernoulli, X, y)
>>> id  target
0   0        1
1   2        0
2   3        1
3   9        0
4  11        1

正如我们可以看到,我们拟合模型与实际训练数据和预测的标签的测试数据。然后,我们创建一个数据帧,并将结果保存为 CSV 格式。最后,你可以把它提交给 Kaggle,你就会知道结果是好是坏。

最后的想法

朴素贝叶斯是一个很好的机器学习模型,但是在这方面还有很多改进的空间。你可以使用任何其他模型,像支持向量机,决策树,循环神经网络等等。

此外,您可以做一些特性工程来删除数据上的无意义信息,或者您可以调整模型上的超参数。

·  END  ·

HAPPY LIFE

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值