筆者邀請您,先思考:
1 您理解Word2Vec和Doc2Vec嗎?
2 您如何做文本分類?
Doc2vec是一個NLP工具,用於將文檔表示爲向量,是word2vec方法的推廣。爲了理解doc2vec,最好理解word2vec方法。
Doc2vec是一個NLP工具,用於將文檔表示爲向量,是word2vec方法的推廣。 爲了理解doc2vec,最好理解word2vec方法。但是,完整的數學細節超出了本文的範圍。如果您是word2vec和doc2vec的新手,以下資源可以幫助您入門:
- 單詞和短語的分佈式表示及其組合
- 句子和文檔的分佈式表示
- Doc2Vec的簡介
- 關於IMDB情感數據集的Gensim Doc2Vec教程
- word嵌入的文檔分類教程
在使用Scikit-Learn進行多類文本分類時使用相同的數據集,在本文中,我們將使用Gensim中的doc2vec技術對產品的投訴進行分類。讓我們開始吧!
數據
目標是將消費者金融投訴分爲預先定義好的12類。這些數據可以從data.gov下載。
1import pandas as pd 2import numpy as np 3from tqdm import tqdm 4tqdm.pandas(desc="progress-bar") 5from gensim.models import Doc2Vec 6from sklearn import utils 7from sklearn.model_selection import train_test_split 8import gensim 9from sklearn.linear_model import LogisticRegression 10from gensim.models.doc2vec import TaggedDocument 11import re 12import seaborn as sns 13import matplotlib.pyplot as plt 14 15df = pd.read_csv('Consumer_Complaints.csv') 16df = df[['Consumer complaint narrative','Product']] 17df = df[pd.notnull(df['Consumer complaint narrative'])] 18df.rename(columns = {'Consumer complaint narrative':'narrative'}, inplace = True) 19df.head(10)
在刪除敘述性列中的null值之後,我們需要重新索引數據框架。
1df.shape
(318718, 2)
1df.index = range(318718) 2df['narrative'].apply(lambda x: len(x.split(' '))).sum()
我們有超過6300萬字,這是一個比較大的數據集。
探索
1cnt_pro = df['Product'].value_counts() 2 3plt.figure(figsize=(12,4)) 4sns.barplot(cnt_pro.index, cnt_pro.values, alpha=0.8) 5plt.ylabel('Number of Occurrences', fontsize=12) 6plt.xlabel('Product', fontsize=12) 7plt.xticks(rotation=90) 8plt.show();
然而,這些類是不平衡的,一個樸素分類器預測所有要收債的東西只會達到20%以上的準確率。 讓我們看幾個投訴敘述及其相關產品的例子。
1def print_complaint(index): 2 example = df[df.index == index][['narrative', 'Product']].values[0] 3 if len(example) > 0: 4 print(example[0]) 5 print('Product:', example[1]) 6 7print_complaint(12) 8print_complaint(20)
文本預處理
下面我們定義了一個函數,用於將文本轉換爲小寫,並從單詞中刪除標點/符號等等。
1from bs4 import BeautifulSoup 2def cleanText(text): 3 text = BeautifulSoup(text, "lxml").text 4 text = re.sub(r'\|\|\|', r' ', text) 5 text = re.sub(r'http\S+', r'<URL>', text) 6 text = text.lower() 7 text = text.replace('x', '') 8 return text 9df['narrative'] = df['narrative'].apply(cleanText)
下面的步驟包括訓練測試分離爲70/30,使用NLTK標記器刪除停止字和標記文字。在我們的第一次嘗試中,我們給每一個投訴故事都貼上了產品標籤。
1train, test = train_test_split(df, test_size=0.3, random_state=42) 2 3import nltk 4from nltk.corpus import stopwords 5def tokenize_text(text): 6 tokens = [] 7 for sent in nltk.sent_tokenize(text): 8 for word in nltk.word_tokenize(sent): 9 if len(word) < 2: 10 continue 11 tokens.append(word.lower()) 12 return tokens 13 14train_tagged = train.apply( 15 lambda r: TaggedDocument(words=tokenize_text(r['narrative']), tags=[r.Product]), axis=1) 16test_tagged = test.apply( 17 lambda r: TaggedDocument(words=tokenize_text(r['narrative']), tags=[r.Product]), axis=1)
這就是培訓條目的樣子——一個以“信用報告”爲標籤的投訴敘述示例。
1train_tagged.values[30]
建立Doc2Vec訓練/評估模型
首先,我們實例化一個doc2vec模型——分佈式詞袋(DBOW)。在word2vec體系結構中,兩個算法名稱分別爲“連續詞袋”(CBOW)和“skip-gram”(SG);在doc2vec架構中,相應的算法有“分佈式內存”(DM)和“分佈式詞袋”(DBOW)。
分佈式詞袋(DBOW)
DBOW是doc2vec模型,類似於word2vec中的Skip-gram模型。通過訓練神經網絡來預測段落中隨機抽取的單詞的概率分佈,得到段落向量。 我們會更改以下參數:
- 如果dm=0,則使用分佈式詞袋包(PV-DBOW);如果dm=1,則使用“分佈式內存”(PV-DM)。
- 300維特徵向量。
- min_count=2,忽略總頻率低於這個值的所有單詞。
- negative = 5, 指定應該繪製多少個“噪聲字”。
- hs=0,負是非零,用負抽樣。
- sample=0,用於配置哪些高頻率單詞是隨機向下採樣的閾值。
- workers=cores,使用這些工人線程來訓練模型(=用多核機器進行更快的訓練)。
1import multiprocessing 2 3cores = multiprocessing.cpu_count()
建立詞彙
1model_dbow = Doc2Vec(dm=0, vector_size=300, negative=5, hs=0, min_count=2, sample = 0, workers=cores) 2model_dbow.build_vocab([x for x in tqdm(train_tagged.values)])
在Gensim中,doc2vec模型的訓練相當簡單,我們對模型進行了初始化,並對其進行了30次的訓練。
1%%time 2for epoch in range(30): 3 model_dbow.train(utils.shuffle([x for x in tqdm(train_tagged.values)]), total_examples=len(train_tagged.values), epochs=1) 4 model_dbow.alpha -= 0.002 5 model_dbow.min_alpha = model_dbow.alpha
爲分類器構建最終的向量特徵
1def vec_for_learning(model, tagged_docs): 2 sents = tagged_docs.values 3 targets, regressors = zip(*[(doc.tags[0], model.infer_vector(doc.words, steps=20)) for doc in sents]) 4 return targets, regressorsdef vec_for_learning(model, tagged_docs): 5 sents = tagged_docs.values 6 targets, regressors = zip(*[(doc.tags[0], model.infer_vector(doc.words, steps=20)) for doc in sents]) 7 return targets, regressors
訓練邏輯迴歸分類器。
1y_train, X_train = vec_for_learning(model_dbow, train_tagged) 2y_test, X_test = vec_for_learning(model_dbow, test_tagged) 3 4logreg = LogisticRegression(n_jobs=1, C=1e5) 5logreg.fit(X_train, y_train) 6y_pred = logreg.predict(X_test) 7 8from sklearn.metrics import accuracy_score, f1_score 9 10print('Testing accuracy %s' % accuracy_score(y_test, y_pred)) 11print('Testing F1 score: {}'.format(f1_score(y_test, y_pred, average='weighted')))
Testing accuracy 0.6683609437751004 Testing F1 score: 0.651646431211616
分佈式內存(DM)
分佈式內存(DM)充當的是一種內存,它可以記住當前上下文中缺少的內容——或者作爲段落的主題。雖然單詞向量表示單詞的概念,但是文檔向量打算表示文檔的概念。我們再次實例化一個向量大小爲300字的Doc2Vec模型,並在訓練語料庫中迭代30次。
1model_dmm = Doc2Vec(dm=1, dm_mean=1, vector_size=300, window=10, negative=5, min_count=1, workers=5, alpha=0.065, min_alpha=0.065) 2model_dmm.build_vocab([x for x in tqdm(train_tagged.values)])
1%%time 2for epoch in range(30): 3 model_dmm.train(utils.shuffle([x for x in tqdm(train_tagged.values)]), total_examples=len(train_tagged.values), epochs=1) 4 model_dmm.alpha -= 0.002 5 model_dmm.min_alpha = model_dmm.alpha
訓練邏輯回顧分類器
1y_train, X_train = vec_for_learning(model_dmm, train_tagged) 2y_test, X_test = vec_for_learning(model_dmm, test_tagged) 3 4logreg.fit(X_train, y_train) 5y_pred = logreg.predict(X_test) 6 7print('Testing accuracy %s' % accuracy_score(y_test, y_pred)) 8print('Testing F1 score: {}'.format(f1_score(y_test, y_pred, average='weighted')))
Testing accuracy 0.47498326639892907 Testing F1 score: 0.4445833078167434
模型匹配
根據Gensim doc2vec教程關於IMDB情緒數據集的介紹,將分佈式詞彙包(DBOW)和分佈式內存(DM)中的段落向量組合在一起可以提高性能。接下來,我們將把這些模型組合在一起進行評估。
首先,我們刪除臨時的訓練數據來釋放RAM。
1model_dbow.delete_temporary_training_data(keep_doctags_vectors=True, keep_inference=True) 2model_dmm.delete_temporary_training_data(keep_doctags_vectors=True, keep_inference=True)
連接兩個模型
1from gensim.test.test_doc2vec import ConcatenatedDoc2Vec 2new_model = ConcatenatedDoc2Vec([model_dbow, model_dmm])
構建特徵向量
1def get_vectors(model, tagged_docs): 2 sents = tagged_docs.values 3 targets, regressors = zip(*[(doc.tags[0], model.infer_vector(doc.words, steps=20)) for doc in sents]) 4 return targets, regressors
訓練邏輯迴歸模型
1y_train, X_train = get_vectors(new_model, train_tagged) 2y_test, X_test = get_vectors(new_model, test_tagged) 3 4logreg.fit(X_train, y_train) 5y_pred = logreg.predict(X_test) 6 7print('Testing accuracy %s' % accuracy_score(y_test, y_pred)) 8print('Testing F1 score: {}'.format(f1_score(y_test, y_pred, average='weighted')))
Testing accuracy 0.6778572623828648 Testing F1 score: 0.664561533967402
結果提高了1%。 在本文中,我使用訓練集對doc2vec進行訓練,但是在Gensim的教程中,使用整個數據集進行訓練,我嘗試了這種方法,使用整個數據集對doc2vec分類器進行訓練,用於我們的消費者投訴分類,我的準確率達到了70%。你可以在這裏找到Notebook,這是一個不同的方法。
上面分析的Jupyter筆記本可以在Github上找到。我期待着聽到任何問題。
作者:Susan Li 原文鏈接: https://www.kdnuggets.com/2018/11/multi-class-text-classification-doc2vec-logistic-regression.html 版權聲明:作者保留權利。文章爲作者獨立觀點,不代表數據人網立場。 數據人網:數據人學習,交流和分享的平臺,誠邀您創造和分享數據知識,共建和共享數據智庫。