NLP入门——天池新闻文本分类(3)基于机器学习的文本分类
NLP入门——天池新闻文本分类(3)基于机器学习的文本分类
-
-
基于机器学习的文本分类
-
- 学习目标
- 机器学习模型
-
文本表示方法
-
- One-hot编码
- Bag of Words
- N-gram
- TF-IDF
-
基于机器学习的文本分类
-
- Count Vecters + RidgeClassifier
- TF-IDF + RidgeClassifier
- 本章小结
-
本章作业
-
基于机器学习的文本分类
这一次任务中会使用机器学习的模型来进行文本分类。机器学习的模型十分丰富,并且包括很多个分支。本次将使用一些传统机器学习进行文本分类。
学习目标
- 学会
TF-IDF的原理和使用 - 使用
sklearn的机器学习模型来进行文本分类
机器学习模型
机器学习中的分类模型有很多种,常见的分类器有K近邻、决策树、随机森林、支撑向量机、朴素贝叶斯、逻辑回归等等,本章中我们会用到RidgeClassifier
文本表示方法
机器学习算法的训练过程中,如果给定N 个样本,每个样本有M 个特征,这样就组成了N*M 的样本矩阵然后完成算法的训练和预测。同样的在计算机视觉中会将图片像素看作特征,每张图就相当于hight * width * 3 的特征图,一个三维矩阵。
但是由于在自然语言领域中,文本长度通常是不定的。将文本表示为计算机可以运算的数字或向量特征的方法称为词嵌入(Word Embedding)方法。词嵌入会将不定长文本转换到定长特征空间中,是文本分类的第一步。
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]
Bag of Words
Bag of Words(词袋表示),也称为Count Vectors,每个文档的字/词可以使用他出现的次数进行表示。
如上述两个句子直接统计每个字出现次数,并将每个句子对应索引位置处赋值为词频:
句子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()
# 输出
array([[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]], dtype=int64)
N-gram
N-gram也是统计单词词频,但是在语料库中加入了相邻单词组成的词语。如当N取值为2时,上述句子1和句子2就变为:
句句⼦子1:我爱 爱北 北京 京天 天安 安门
句句⼦子2:我喜 喜欢 欢上 上海
TF-IDF
TF-IDF分数是由两部分组成:第一部分是词语频率(Term Frequency),第二部分是逆文档频率(Inverse Document Frequency)。
字词的重要性会随着他在文件中出现次数成正比增加,但是会随着他在语料库中出现的频率中出现的频率成反比下降。
-
TF
TF表示关键字在文档中出现的频率。tf_{ij}表示单词i在第j个文件中的词频,n_{i,j}是该词出现在文件d_j中的次数。母是文件中单词出现次数综合。
tf_{ij}=\frac{n_{i,j}}{\sum_kn_{k,j}}
即:TF_w=\frac{在某一类中词条w出现的次数}{该类中所有的词条数目} -
IDF
IDF是逆向文件频率。由总文件数目初一包含盖茨与的文件的数目,如果包含该词条的文档越少,IDF越大,则说明词条有很好的类别区分能力。idf_i=log_2\frac{|D|}{|{j:t_i\in{d_j}}|}
|D|是语料库中文件总数,|{j:t_i\in{d_j}}|表示包含该词语t_i的文件数目,即:
IDF=log_2(\frac{语料库的文档总数}{包含该词条w的文档数+1})<分母+1的原因是避免分母为0>
最后:
TF-IDF=TF*IDF
基于机器学习的文本分类
我们对比不痛文本表示的算法的精度,通过构建验集计算F1分数
Count Vecters + RidgeClassifier
import pandas as pd
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
train_df = pd.read_csv('../input/train_set.csv', sep='\t', nrows=15000)
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'))
# 0.74
TF-IDF + RidgeClassifier
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
train_df = pd.read_csv('../input/train_set.csv', sep='\t', nrows=15000)
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'))
# 0.87
本章小结
本章使用了机器学习算法进行文本分类,并将Count Vectors与TF-IDF Vectors进行了对比
本章作业
- 尝试改变TF-IDF的参数,并验证精度
sklearn库中TfidfVectorizer的几个重要参数如下:
| Column 1 | Column 2 |
|---|---|
| ngram_range | 元组(min_n,max_n)的形式。表示提取n-grams的上下界。默认值为(1,1),表示提取词语的时候在范围min\_n\le n \le max\_n长度内的词语都会提取 |
| max_df | 浮点或者整形。表示最大文档频率,当是浮点数时,大于词文档频率的单词会被忽略;当是整形时,表示最大出现在多少个文档中,高于的忽略 |
| max_features | 整形。最大的特征词数,取词频最高的max_features个单词 |
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics import accuracy_score
train_df = pd.read_csv("./train_set.csv", sep='\t', nrows=15000)
train_test = vectorizer.fit_transform(train_df['text'])
for df in [0.75,0.77,0.78, 0.79,0.8]:
tfidf = TfidfVectorizer(ngram_range=(1, 3), max_df=df, max_features = 7000)
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('df:{}'.format(df), f1_score(train_df['label'].values[10000:], val_pred, average='macro'))
print(accuracy_score(train_df['label'].values[10000:], val_pred))
# 输出
df:0.77 0.8931458491540146
0.9158
df:0.78 0.8919163760078824
0.9154
df:0.79 0.8923133935002019
0.9158
df:0.8 0.8937502578052472
0.9162
2.使用其它模型,完成训练验证
使用svm训练结果
import pandas as pd
from sklearn.model_selection import KFold
from sklearn.model_selection import cross_val_score
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn import svm
train_df = pd.read_csv("./train_set.csv", sep='\t', nrows=15000)
tfidf = TfidfVectorizer(ngram_range=(1,3), max_features=3000)
train_test = tfidf.fit_transform(train_df['text'])
mean=[]
std=[]
kfold=KFold(n_splits=10,random_state=22)
C=[0.9,1.0]
gamma=[0.1,0.2]
kernel=['linear','rbf']
for i in C:
for j in gamma:
for k in kernel:
result=cross_val_score(svm.SVC(kernel=k,C=i,gamma=j),train_test[:10000], train_df['label'].values[:10000],cv=kfold,scoring='accuracy')
print(i,j,k,':')
print(result.mean())
mean.append(result.mean())
print(result.std())
std.append(result.std())
Frame=pd.DataFrame({'mean':mean,'std':std})
# 输出
0.9 0.1 linear :
0.9000999999999999
0.005204805471869247
0.9 0.1 rbf :
0.8669
0.007803204469959768
0.9 0.2 linear :
0.9000999999999999
0.005204805471869247
0.9 0.2 rbf :
0.8863
0.00787464284904402
1.0 0.1 linear :
0.901
0.004878524367060192
1.0 0.1 rbf :
0.8704000000000001
0.007045565981523421
1.0 0.2 linear :
0.901
0.004878524367060192
1.0 0.2 rbf :
0.889
0.007127411872482192
