前言:计算机读不懂文本表述,该怎么办? 回想一下我们是如何进行阅读的?
1.1 文本分类 = 文本表示 + 分类模型
1.1.1 文本表示: BOW 、N-Gram 、TF-IDF、word2vec、word embedding ELMo
分类模型:NB、LR、SVM、LSTM、CNN等
1.1.2 分类模型:NB/LR/SVM/LSTM(GRU)/CNN
语种判断:拉丁语系,字母组成的,甚至字母也一样 => 字母的使用(次序、频次)不一样
1.1.3 文本表示
词袋模型(中文)
①分词
第1句话[w1 w3 w5 w2 w1 ...]
第2句话[w11 w32 w51 w21 w15]
第3句话....
...
②统计词频
w3 count3
w7 count7
wi count_i
...
③构建词典
选出频率最高的N个词
开[1*n]这样的向量空间
(每个位置是哪个词)
④映射:把每句话共构建的词典进行映射
第1句话 [1 0 1 0 1 0 ...]
第2句话[0 0 0 0 0 0 ... 1 , 0 0 1 0 ...]
⑤提升信息的表达充分度:
- 把是否出现替换成频次
- 不只记录每个词,我还记录连续的n-gram
- ”李雷喜欢韩梅梅“ =>("李雷","喜欢","韩梅梅")
- "韩梅梅喜欢李雷" =>("李雷","喜欢","韩梅梅")
- "李雷喜欢韩梅梅" =>("李雷","喜欢","韩梅梅","李雷喜欢",”喜欢韩梅梅“)
- "韩梅梅喜欢李雷" =>("韩梅梅","喜欢","李雷","韩梅梅喜欢","喜欢李雷")
- 不只是使用频次信息,需要知道词对于句子的重要程度
- TF-IDF = TF(term frequency) + IDF(inverse document frequency)
⑥上述的表达都是独立表达(没有词与词在含义空间上的分布)
喜欢 = 在乎 = “稀罕” = “中意”
- word-net (把词汇根据关系构成一张网:近义词、反义词、上位词、下位词...)
- 怎么更新?
- 个体差异?
- 希望能够基于海量数据的分布去学习到一种表示
- nnlm =>词向量
- word2vec (周边词类似这样一些词,是可以互相替换的,相同的语境)
- 捕捉的是相关性的词,不是近义词
- 我 讨厌 你
- 我 喜欢 你
- word2vec优化...
- 用监督学习去调整word2vec的结果(word embedding/词嵌入)
- 捕捉的是相关性的词,不是近义词
- 文本预处理
- 时态语态Normalize
- 近义词替换
- stemming
- ....
1.1.4 分类模型
对向量化的输入去做建模
①NB/LR/SVM...建模
——可以接受特别高纬度的稀疏表示
②MLP/CNN/LSTM
——不适合稀疏高纬度数据输入 => word2vec
1.2 朴素贝叶斯
我们试试用朴素贝叶斯完成一个中文文本分类器,一般在数据量足够,数据丰富度够的情况下,用朴素贝叶斯完成这个任务,准确度还是不错的。
机器学习的算法要取得好的效果,离不开数据。
1.2.1 准备数据
import jieba
import panda as pd
df_technology = pd.read_csv('./origin_data/technology_news.csv',encoding = 'utf-8')
df_technology = df_technology.dropna()
df_car = pd.read_csv('./origrin_data/car_news.csv',encoding = 'utf-8')
df_car = df_car.dropna()
df_entertainment = pd.read_csv('./origin_data/entertainment_news.csv',encoding = 'utf-8')
df_entertainment.dropna()
df_military = pd.read_csv('./origin_data/military_news.csv',encoding = 'utf-8')
df_military.dropna()
df_sports = pd.read_csv('./origin_data/sport_news.csv',encoding = 'utf-8')
df_sports.dropna()
1.2.2 分词与中文文本处理
1.2.2.1 停用词梳理
stopwords = pd.read_csv('roigin_data/stopwords.txt',sep = '\t',index_col = False , quoting = 3 , name = ['stopword'],encoding = 'utf-8')
stopwords = stopwords['stopword'].values
1.2.2.2 去停用词
我们对数据做一些预处理,并把处理过后的数据写入新文件夹避免每次重复工作
def preprocess_tex(content_lines , sentence , category , target_path):
out_f = open(target_path +'/' + category + '.txt' , 'w')
for line in content_lines:
try:
seg = jieba.lcut(line)
segs = list(filter(lambda x: len(x) >1 ,segs))
segs = list(filter(lambda x: x not in stopwords , segs))
out_f.writer(" ".join(segs) + "\n")
except:
print(line)
continue
out_f.close()
#生成训练数据
sentence = []
preprocess_text(technology , sentence , 'technology','processed_data')
preprocess_text(car , sentence,'car','processed_data' )
preprocess_text(entertainment , sentence,'entertainment','processed_data')
preprocess_text(military , sentences , 'military' , 'processed_data')
preprocess_text(sports , sentences ,'sports','processed_data')
1.2.2.3 生成训练集
我们打乱一下顺序 生成更可靠的训练集
import random
random.shuffle(sentence)
为了一会儿监测一下分类器的效果如何,我们需要一份训练集一份测试集
所以对原始数据进行切分
from sklearn.model_selection import train_test_split
x , y = zip(*sentence)
x_train , x_test , y_train , y_test = train_test_split(x , y , random_state = 1234)
下一步要做的就是在降噪数据上抽取出有用的特征,我们对文本抽取词袋模型特征
from sklearn.feature_extraction.text import CountVectorizer
vec = CountVectorizer(
analyzer = 'word' ,
max_features = 4000
)
vec.fit(x_train)
def get_features(x):
vec.transform(x)
把分类器import 进来并训练
from sklearn.navie_bayes import MultinomialNB
classifier = MultinomialNB()
classifier.fit(vec.transfrom(x_train) , y_train)
准确率查看
classifier.score(vec.transfrom(x_test) , y_test)
有没有办法把准确率提高一些呢?
我们可以把特征做的更好一些,比如说:我们试试加入2-gram 或者3-gram的统计特征,比如可以把词库放大一些
vec = CountVectorizer(
analyzer = 'word',
ngram = range(1,4)
max_features = 20000
)
vec.fit(x_train)
def get_features(x):
vec.transform(x)
1.2.3 分类训练
from sklearn.naive_bayes import MultinomialNB
classifier = MultinomialNB
classifier.fit(vec.transform(x_train) , y_train)
classifier.score(vec.transform(x_test) , y_test)
1.2.3 交叉验证
from sklearn.model_selection import StraifiedKFlod
from sklearn.metrics import accuracy_score , precision_score
import numpy as np
def stratifiedkfold_cv(x , y , clf_class ,shuffle = True , n_folds = 5,**kwargs ):
stratifiedk_fold = StratifiedKFlod(n_splits = n_folds , shuffle = shuffle)
y_pred = y[:]
for train_index , test_index in stratifiedk_fold.split(x,y):
X_train , X_test = x[train_index] , x[test_index]
y_train = y[train_index]
clf = clf_class(**kwargs)
clf.fit(x_train , y_train)
y_pred[test_index] = clf.predict(X_test)
return y_pred
NB = MultinomialNB
print(precission_score(y , stratifiedkfold_cv(vec,transform(x) , np.array(y) , NB) , average = 'macro'))