文章目录
基于机器学习的文本分类
文本表示方法
step 1:one-hot
将每一个单词使用一个离散的向量表示。具体将每个字/词编码一个索引,然后根据索引进行赋值。
step 2:Bag of Words(词袋表示/Count Vectors)
每个文档的字/词可以使用其出现次数来进行表示。
则一段文本对应离散向量,长度和one-hot一样长,数字是出现次数
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)
step 3:N-gram
N-gram与Count Vectors类似,不过加入了相邻单词组合成为新的单词并进行计数。类似于CNN/LSTM里面步长从1变成N。
在Count Vector中作为参数进行设置。下面摘自:
example: 一句话’I like you’
(1)如果ngram_range = (2, 2)表示只选取前后的两个词构造词组合 :词向量组合为:’I like‘ 和 ’like you‘
(2)如果ngram_range = (1, 3) 表示选取1到3个词做为组合方式: 词向量组合为: ‘I’, ‘like’, ‘you’, ‘I like’, ‘like you’, ‘I like you’ 构成词频标签
vec = CountVectorizer(ngram_range=(1,3))
vec.fit_transform(corpus).toarray()
array([[0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 2, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1,
1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0],
[1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0,
0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0],
[0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1]], dtype=int64)
其它参数的设置详见
step* : 对中文文本的操作
ps:用jieba库(ananconda用pip install jieba 下载,用conda下载会报错)
下面例子的原文
import pandas as pd
import jieba
chin = ["他用报话机向上级呼喊:“为了祖国,为了胜利,向我开炮!向我开炮!",
"记者:你怎么会说出那番话?",
"韦昌进:我只是觉得,对准我自己打,才有可能把上了我哨位的这些敌人打死,或者打下去。"]
chin = [" ".join(jieba.lcut(e)) for e in chin] # 分词,并用" "连接
chin
['他 用 报话机 向 上级 呼喊 : “ 为了 祖国 , 为了 胜利 , 向 我 开炮 ! 向 我 开炮 !',
'记者 : 你 怎么 会 说出 那 番话 ?',
'韦昌进 : 我 只是 觉得 , 对准 我 自己 打 , 才 有 可能 把 上 了 我 哨位 的 这些 敌人 打死 , 或者 打 下去 。']
vecchin = CountVectorizer()
vecchin.fit_transform(chin).toarray()
array([[1, 0, 2, 0, 0, 1, 0, 0, 2, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0,
0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0,
0],
[0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1,
1]], dtype=int64)
step 4:TF-IDF
TF-IDF 分数由两部分组成:
第一部分是词语频率(Term Frequency)
第二部分是逆文档频率(Inverse Document Frequency)。其中计算语料库中文档总数除以含有该词语的文档数量,然后再取对数就是逆文档频率。
TF(t)= 该词语在当前文档出现的次数 / 当前文档中词语的总数
IDF(t)= log_e(文档总数 / 出现该词语的文档总数)
from sklearn.feature_extraction.text import TfidfVectorizer
tfidf = TfidfVectorizer()
tfidf.fit_transform(chin).toarray()#结果3*23:三句话,23个特征
array([[0.2773501 , 0. , 0.5547002 , 0. , 0. ,
0.2773501 , 0. , 0. , 0.5547002 , 0. ,
0. , 0. , 0.2773501 , 0. , 0. ,
0.2773501 , 0.2773501 , 0. , 0. , 0. ,
0. , 0. , 0. ],
[0. , 0. , 0. , 0. , 0. ,
0. , 0. , 0. , 0. , 0.5 ,
0. , 0. , 0. , 0. , 0.5 ,
0. , 0. , 0. , 0. , 0.5 ,
0.5 , 0. , 0. ],
[0. , 0.28867513, 0. , 0.28867513, 0.28867513,
0. , 0.28867513, 0.28867513, 0. , 0. ,
0.28867513, 0.28867513, 0. , 0.28867513, 0. ,
0. , 0. , 0.28867513, 0.28867513, 0. ,
0. , 0.28867513, 0.28867513]])
tfidf.get_feature_names()
['上级',
'下去',
'为了',
'只是',
'可能',
'呼喊',
'哨位',
'对准',
'开炮',
'怎么',
'或者',
'打死',
'报话机',
'敌人',
'番话',
'祖国',
'胜利',
'自己',
'觉得',
'记者',
'说出',
'这些',
'韦昌进']
example&practice
1.Bags of words& RidgeClassifier
from sklearn.linear_model import RidgeClassifier
from sklearn.metrics import f1_score
Path=r"C:/Users/10539/Desktop/nlp/"
train_df = pd.read_csv(Path+'train_set.csv', sep='\t', nrows=15000)
vectorizer = CountVectorizer(ngram_range=(1,3),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.7934314417439411
2.TF-IDF & SVM
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.svm import SVC
tfidf = TfidfVectorizer(ngram_range=(1,3), max_df=0.9,max_features=4000)
train_test = tfidf.fit_transform(train_df['text'])
clf = SVC()
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))
0.875646733138943