首页 > 其他分享 >基于机器学习的文本分类!

基于机器学习的文本分类!

时间:2023-01-01 10:02:57浏览次数:55  
标签:f1 基于 机器 val pred clf train test 文本


 Datawhale干货 

作者:李露,西北工业大学,Datawhale优秀学习者

据不完全统计,网民们平均每人每周收到的垃圾邮件高达10封左右。垃圾邮件浪费网络资源的同时,还消耗了我们大量的时间。大家对此深恶痛绝,于是识别垃圾邮件并对其进行过滤成为各邮件服务商的重要工作之一。

垃圾邮件识别问题本质上是一个文本分类问题,给定文档p(可能含有标题t),将文档分类为n个类别中的一个或多个。文本分类一般有两种处理思路:基于机器学习的方法和基于深度学习的方法。

本文主要基于机器学习的方法,介绍了特征提取+分类模型在文本分类中的应用。具体目录如下:

基于机器学习的文本分类!_垃圾邮件

一、数据及背景

​https://tianchi.aliyun.com/competition/entrance/531810/information(阿里天池-零基础入门NLP赛事)​

二、文本表示方法

在机器学习算法的训练过程中,假设给定个样本,每个样本有个特征,这样就组成了的样本矩阵。在计算机视觉中可以把图片的像素看作特征,每张图片都可以视为的特征图,然后用一个三维矩阵带入计算。

但是在自然语言领域,上述方法却不可行,因为文本的长度是不固定的。文本分类的第一步就是将不定长的文本转换到定长的空间内,即词嵌入。

2.1 One-hot

One-hot方法将每一个单词使用一个离散的向量表示,将每个字/词编码成一个索引,然后根据索引进行赋值。One-hot表示法的一个例子如下:

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海

首先对句子中的所有字进行索引

{'我': 1, '爱': 2, '北': 3, '京': 4, '天': 5, '安': 6, '门': 7, '喜': 8, '欢': 9, '上': 10, '海': 11}

一共11个字,因此每个字可以转换为一个11维的稀疏向量:

我:[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
爱:[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
...
海:[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]

2.2 Bags of Words

Bags of Words,也称为Count Vectors,每个文档的字/词可以使用其出现次数来进行表示。例如对于:

句子1:我 爱 北 京 天 安 门
句子2:我 喜 欢 上 海

直接统计每个字出现的次数,并进行赋值:

句子1:我 爱 北 京 天 安 门
转换为 [1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
句子2:我 喜 欢 上 海
转换为 [1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1]

可以利用sklearn的CountVectorizer来实现这一步骤。

from sklearn.feature_extraction.text import CountVectorizer
corpus = [
'This is the first document.',
'This document is the second document.',
'And this is the third one.',
'Is this the first document?',
]
vectorizer = CountVectorizer()
vectorizer.fit_transform(corpus).toarray()

输出为:

[[0, 1, 1, 1, 0, 0, 1, 0, 1],
[0, 2, 0, 1, 0, 1, 1, 0, 1],
[1, 0, 0, 1, 1, 0, 1, 1, 1],
[0, 1, 1, 1, 0, 0, 1, 0, 1]]

2.3 N-gram

N-gram与Count Vectors类似,不过加入了相邻单词组合为新的单词,并进行计数。如果N取值为2,则句子1和句子2就变为:

句子1:我爱 爱北 北京 京天 天安 安门
句子2:我喜 喜欢 欢上 上海

2.4 TF-IDF

TF-IDF分数由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)

基于机器学习的文本分类!_特征提取_02

基于机器学习的文本分类!_文本分类_03

三、基于机器学习的文本分类

接下来我们将研究文本表示对算法精度的影响,对比同一分类算法在不同文本表示下的算法精度,通过本地构建验证集计算F1得分。

3.1 导入相关的包

import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
import matplotlib.pyplot as plt
from sklearn.metrics import f1_score

3.2 读取数据

train_df = pd.read_csv('./data/train_set.csv', sep='\t', nrows=15000)

3.3 文本分类对比

3.3.1 Count Vectors + RidgeClassifier

vectorizer = CountVectorizer(max_features=3000)
train_test = vectorizer.fit_transform(train_df['text'])


clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])


val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))

输出为.

3.3.2 TF-IDF + RidgeClassifier

tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])


clf = RidgeClassifier()
clf.fit(train_test[:10000], train_df['label'].values[:10000])


val_pred = clf.predict(train_test[10000:])
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))

输出为.

四、研究参数对模型的影响

4.1 正则化参数对模型的影响

取大小为5000的样本,保持其他参数不变,令从0.15增加至1.5,画出关于和的图像

sample = train_df[0:5000]
n = int(2*len(sample)/3)
tfidf = TfidfVectorizer(ngram_range=(2,3), max_features=2500)
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]


f1 = []
for i in range(10):
clf = RidgeClassifier(alpha = 0.15*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))


plt.plot([0.15*(i+1) for i in range(10)], f1)
plt.xlabel('alpha')
plt.ylabel('f1_score')
plt.show()

结果如下:

基于机器学习的文本分类!_垃圾邮件_04

可以看出不宜取的过大,也不宜过小。越小模型的拟合能力越强,泛化能力越弱,越大模型的拟合能力越差,泛化能力越强。​

4.2 max_features对模型的影响

分别取max_features的值为1000、2000、3000、4000,研究max_features对模型精度的影响

f1 = []
features = [1000,2000,3000,4000]
for i in range(4):
tfidf = TfidfVectorizer(ngram_range=(2,3), max_features=features[i])
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]
clf = RidgeClassifier(alpha = 0.1*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))


plt.plot(features, f1)
plt.xlabel('max_features')
plt.ylabel('f1_score')
plt.show()

结果如下:

基于机器学习的文本分类!_文本分类_05

可以看出max_features越大模型的精度越高,但是当max_features超过某个数之后,再增加max_features的值对模型精度的影响就不是很显著了。

4.3 ngram_range对模型的影响

n-gram提取词语字符数的下边界和上边界,考虑到中文的用词习惯,ngram_range可以在(1,4)之间选取

f1 = []
tfidf = TfidfVectorizer(ngram_range=(1,1), max_features=2000)
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]
clf = RidgeClassifier(alpha = 0.1*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))


tfidf = TfidfVectorizer(ngram_range=(2,2), max_features=2000)
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]
clf = RidgeClassifier(alpha = 0.1*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))


tfidf = TfidfVectorizer(ngram_range=(3,3), max_features=2000)
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]
clf = RidgeClassifier(alpha = 0.1*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))


tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=2000)
train_test = tfidf.fit_transform(sample['text'])
train_x = train_test[:n]
train_y = sample['label'].values[:n]
test_x = train_test[n:]
test_y = sample['label'].values[n:]
clf = RidgeClassifier(alpha = 0.1*(i+1), solver = 'sag')
clf.fit(train_x, train_y)
val_pred = clf.predict(test_x)
f1.append(f1_score(test_y, val_pred, average='macro'))

输出如下

基于机器学习的文本分类!_垃圾邮件_06

ngram_range取(1,3)的效果较好。

五、考虑其他分类模型

特征提取使用TF-IDF,与第三节中TF-IDF + RidgeClassifier的特征提取保持一致,再来看下其他几种分类算法的效果。

5.1 LogisticRegression

LogisticRegression的目标函数为:

from sklearn import linear_model


tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=5000)
train_test = tfidf.fit_transform(train_df['text']) # 词向量 15000*max_features


reg = linear_model.LogisticRegression(penalty='l2', C=1.0,solver='liblinear')
reg.fit(train_test[:10000], train_df['label'].values[:10000])


val_pred = reg.predict(train_test[10000:])
print('预测结果中各类新闻数目')
print(pd.Series(val_pred).value_counts())
print('\n F1 score为')
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))

输出为0.846470490043.

5.2 SGDClassifier

SGDClassifier使用mini-batch来做梯度下降,在处理大数据的情况下收敛更快

tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=5000)
train_test = tfidf.fit_transform(train_df['text']) # 词向量 15000*max_features


reg = linear_model.SGDClassifier(loss="log", penalty='l2', alpha=0.0001,l1_ratio=0.15)
reg.fit(train_test[:10000], train_df['label'].values[:10000])


val_pred = reg.predict(train_test[10000:])
print('预测结果中各类新闻数目')
print(pd.Series(val_pred).value_counts())
print('\n F1 score为')
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))

输出为0.847267047346

5.3 SVM

from sklearn import svm
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=5000)
train_test = tfidf.fit_transform(train_df['text']) # 词向量 15000*max_features


reg = svm.SVC(C=1.0, kernel='linear', degree=3, gamma='auto',decision_function_shape='ovr')
reg.fit(train_test[:10000], train_df['label'].values[:10000])


val_pred = reg.predict(train_test[10000:])
print('预测结果中各类新闻数目')
print(pd.Series(val_pred).value_counts())
print('\n F1 score为')
print(f1_score(train_df['label'].values[10000:], val_pred, average='macro'))

输出为0.884240695943.

对比几种机器学习算法可以看出,在相同的TF-IDF特征提取方法基础上,用SVM得到的分类效果最好。

本文电子版 后台回复 文本分类 获取

基于机器学习的文本分类!_特征提取_07

“整理不易,三连

标签:f1,基于,机器,val,pred,clf,train,test,文本
From: https://blog.51cto.com/u_15699042/5982740

相关文章

  • 机器学习中的优化算法!
     Datawhale干货 作者:李祖贤,Datawhale高校群成员,深圳大学在机器学习中,有很多的问题并没有解析形式的解,或者有解析形式的解但是计算量很大(譬如,超定问题的最小二乘解),对于此类......
  • 基于OpenCV的图像梯度与边缘检测!
     Datawhale干货 作者:姚童,Datawhale优秀学习者,华北电力大学严格的说,梯度计算需要求导数。但是图像梯度的计算,是通过计算像素值的差得到梯度的近似值。图像梯度表示的是图像......
  • 机器学习数学基础:常见分布与假设检验
     Datawhale干货 作者:吴忠强,Datawhale优秀学习者,东北大学所谓机器学习和深度学习,背后的逻辑都是数学,所以数学基础在这个领域非常关键,而统计学又是重中之重,机器学习从某......
  • 基于OpenCV的图像分割处理!
     Datawhale干货 作者:姚童,Datawhale优秀学习者,华北电力大学图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成为图像分割中最基本和......
  • [python] 基于paramiko库操作远程服务器
    SSH(SecureShell)是一种网络安全协议,能够使两台计算机安全地通信和共享数据。目前,SSH协议已在世界各地广泛使用,大多数设备都支持SSH功能。SSH的进一步说明见:深入了解SSH。SS......
  • Android笔记--文本输入
    编辑框EditText相关内部部件取下:inputType的类型如下:具体实现:不同边框的实现:焦点变更监听器具体实现:文本变化监听器具体实现:......
  • 基于局部直方图相关算法的近似优化和提速。
    基于局部直方图的算法有很多很多,比如中值模糊、表面模糊、选择性模糊等等,这类算法有个通病,就是即使选择使用SIMD指令加速,因为其内在的特性,速度还是不能很......
  • 基于局部直方图相关算法的近似优化和提速。
    基于局部直方图的算法有很多很多,比如中值模糊、表面模糊、选择性模糊等等,这类算法有个通病,就是即使选择使用SIMD指令加速,因为其内在的特性,速度还是不能很......
  • .NET 云原生架构师训练营(基于 OP Storming 和 Actor 的大型分布式架构二)--学习笔记
    目录为什么我们用OrleansDaprVSOrleansActor模型Orleans的核心概念结合OPStorming的实践结合OPStorming的实践业务模型设计模型代码实现业务模型我们可以把关键......
  • 基于Element-UI的el-table,input框输入实现排序功能
    http://t.zoukankan.com/usebtf-p-9525738.html实现要求:如果输入的内容不是非负整数,那么提示报错,并且将值变为输入前的内容;如果输入正确,则当输入的内容发生改......