本文学习自这篇文章
import spacyfrom sklearn.datasets
import fetch_20newsgroupsfrom sklearn.pipeline
import Pipeline
import numpy as np
# 下载数据集,20个类别
twenty_train = fetch_20newsgroups(subset='train', shuffle=True, download_if_missing=True)
twenty_test = fetch_20newsgroups(subset='test', shuffle=True, download_if_missing=True)
from sklearn.feature_extraction.text import CountVectorizer
count_vect = CountVectorizer()
X_train_counts = count_vect.fit_transform(twenty_train.data) # 创建词袋模型
print(f'Shape of Term Frequency Matrix: {X_train_counts.shape}') # 输出词频矩阵
# Shape of Term Frequency Matrix: (11314, 130107)
关于词袋模型的解释:
首先给出两个句子:1.“The cat sat on the hat”
2.“The dog ate the cat and the hat”
然后提取出词汇表:{ the, cat, sat, on, hat, dog, ate, and }
于是第一个句子的词袋模型就是:{ 2, 1, 1, 1, 1, 0, 0, 0 },它的意义是词汇表中的每个单词在句子中出现的次数,例如the在第一个句子中出现了2次,所以词袋模型的第一个位置就是2。类似可以得到第二个句子的词袋模型。
from sklearn.feature_extraction.text import TfidfTransformer
tfidf_transformer = TfidfTransformer()
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts) # TF-IDF算法对词进行加权
print(f'Shape of TFIDF Matrix: {X_train_tfidf.shape}')
# Shape of TFIDF Matrix: (11314, 130107)
TF-IDF算法:
在一个大型的文本语料库中,一些单词会非常常见(例如英语中的“the”、“a”、“is”),而对于文档的实际内容来说,它们几乎没有什么有意义的信息。这样的词在上面是描述的词袋模型中,出现次数多,所占比重就多,所以TF-IDF算法就是要尽可能降低这些词的比重。以下结合TfidfTransformer()方法描述该算法,首先我们知道了通过CountVectorizer()方法得出一个词频矩阵,行代表文本个数
d
d
d,列代表词的个数
t
t
t,则,
t
f
i
d
f
(
t
,
d
)
=
t
f
(
t
,
d
)
×
i
d
f
(
t
)
tfidf(t,d)=tf(t,d)\times idf(t)
tfidf(t,d)=tf(t,d)×idf(t)
其中,
t
f
(
t
,
d
)
tf(t,d)
tf(t,d)是第
t
t
t个词在第
d
d
d个文本中出现的次数,也即词频矩阵中的某个数。
i
d
f
(
t
)
idf(t)
idf(t)计算如下,当TfidfTransformer(norm=‘l2’, use_idf=True, smooth_idf=True, sublinear_tf=False)时,
i
d
f
(
t
)
=
l
o
g
n
1
+
d
f
(
t
)
idf(t)=log\frac{n}{1+df(t)}
idf(t)=log1+df(t)n
其中
d
f
(
t
)
df(t)
df(t)是第t个词在整个语料库中出现的次数,比如上面的两个句子(给出的语料库只有两个句子)中,以the为例,它在两个句子中都出现了(不考虑它在某个句子中出现的次数),则
d
f
(
t
)
=
2
df(t)=2
df(t)=2。
当smooth_idf=False时,
i
d
f
(
t
)
=
l
o
g
n
d
f
(
t
)
+
1
idf(t)=log\frac{n}{df(t)}+1
idf(t)=logdf(t)n+1
最后计算完成后,要计算每个文本的L2范数,
v
n
o
r
m
=
[
v
1
,
v
2
,
.
.
.
,
v
t
]
v
1
2
+
v
2
2
+
.
.
.
+
v
t
2
v_{norm}=\frac{[v_1, v_2,...,v_t]}{\sqrt{v_1^2+v_2^2+...+v_t^2}}
vnorm=v12+v22+...+vt2[v1,v2,...,vt]
即把词频矩阵中每一行的词经过TF-IDF运算后在进行L2范数计算,最后求出最终的tf-idf矩阵。
from sklearn.naive_bayes import MultinomialNB
# 用朴素贝叶斯法训练模型
clf = MultinomialNB().fit(X_train_tfidf, twenty_train.target)
下面介绍一种方法可以将以上过程结合起来,
text_nb_clf = Pipeline([('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', MultinomialNB())])
text_nb_clf = text_nb_clf.fit(twenty_train.data, twenty_train.target)
测试模型
predicted = text_nb_clf.predict(twenty_test.data)
naivebayes_clf_accuracy = np.mean(predicted == twenty_test.target) * 100.
# Test Accuracy is 77.38980350504514 %
下面介绍一下spacy的一些使用方法,
nlp = spacy.load('en') # 加载语言模型'en'
from spacy.lang.en.stop_words import STOP_WORDS # 加载停用词
doc = nlp("I am learning the most important ideas Natural Language Processing ideas using Python") # 将字符串转换为文档
for token in doc: # 对文档进行分词
print(token)
# I
# am
# learning
# the
# most
# important
# ideas
# Natural
# Language
# Processing
# ideas
# using
# Python
simplified_doc = [token for token in doc if not token.is_punct | token.is_stop]
# 去除停用词和标点符号以后的词
# 构建分词器
from spacy.lang.en import English
tokenizer = English().Defaults.create_tokenizer(nlp)
def spacy_tokenizer(document):
return [token.orth_ for token in tokenizer(document)]
# token.orth_属性可以保留标点符号