前言:計算機讀不懂文本表述,該怎么辦? 回想一下我們是如何進行閱讀的?
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句話....
...
②統(tǒng)計詞頻
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 ...]
⑤提升信息的表達充分度:
- 把是否出現(xiàn)替換成頻次
- 不只記錄每個詞,我還記錄連續(xù)的n-gram
- ”李雷喜歡韓梅梅“ =>("李雷","喜歡","韓梅梅")
- "韓梅梅喜歡李雷" =>("李雷","喜歡","韓梅梅")
- "李雷喜歡韓梅梅" =>("李雷","喜歡","韓梅梅","李雷喜歡",”喜歡韓梅梅“)
- "韓梅梅喜歡李雷" =>("韓梅梅","喜歡","李雷","韓梅梅喜歡","喜歡李雷")
- 不只是使用頻次信息,需要知道詞對于句子的重要程度
- TF-IDF = TF(term frequency) + IDF(inverse document frequency)
⑥上述的表達都是獨立表達(沒有詞與詞在含義空間上的分布)
喜歡 = 在乎 = “稀罕” = “中意”
- word-net (把詞匯根據(jù)關系構成一張網(wǎng):近義詞、反義詞、上位詞、下位詞...)
- 怎么更新?
- 個體差異?
- 希望能夠基于海量數(shù)據(jù)的分布去學習到一種表示
- nnlm =>詞向量
- word2vec (周邊詞類似這樣一些詞,是可以互相替換的,相同的語境)
- 捕捉的是相關性的詞,不是近義詞
- 我 討厭 你
- 我 喜歡 你
- word2vec優(yōu)化...
- 用監(jiān)督學習去調整word2vec的結果(word embedding/詞嵌入)
- 捕捉的是相關性的詞,不是近義詞
- 文本預處理
- 時態(tài)語態(tài)Normalize
- 近義詞替換
- stemming
- ....
1.1.4 分類模型
對向量化的輸入去做建模
①NB/LR/SVM...建模
——可以接受特別高緯度的稀疏表示
②MLP/CNN/LSTM
——不適合稀疏高緯度數(shù)據(jù)輸入 => word2vec
1.2 樸素貝葉斯
我們試試用樸素貝葉斯完成一個中文文本分類器,一般在數(shù)據(jù)量足夠,數(shù)據(jù)豐富度夠的情況下,用樸素貝葉斯完成這個任務,準確度還是不錯的。
機器學習的算法要取得好的效果,離不開數(shù)據(jù)。
1.2.1 準備數(shù)據(jù)
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 去停用詞
我們對數(shù)據(jù)做一些預處理,并把處理過后的數(shù)據(jù)寫入新文件夾避免每次重復工作
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()
#生成訓練數(shù)據(jù)
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)
為了一會兒監(jiān)測一下分類器的效果如何,我們需要一份訓練集一份測試集
所以對原始數(shù)據(jù)進行切分
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)
下一步要做的就是在降噪數(shù)據(jù)上抽取出有用的特征,我們對文本抽取詞袋模型特征
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的統(tǒng)計特征,比如可以把詞庫放大一些
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'))