文本分類是機器學習在自然語言處理中的最常用也是最基礎的應用,機器學習相關內容可以直接看我的有關scikit-learn相關教程,本節直接涉及nltk中的機器學習相關內容?
轉載自網站 www.shareditor.com以及原始鏈接地址
先來一段前戲機器學習的過程是訓練模型和使用模型的過程,訓練就是基于已知數據做統計學習,使用就是用統計學習好的模型來計算未知的數據。
機器學習分為有監督學習和無監督學習,文本分類也分為有監督的分類和無監督的分類。有監督就是訓練的樣本數據有了確定的判斷,基于這些已有的判斷來斷定新的數據,無監督就是訓練的樣本數據沒有什么判斷,完全自發的生成結論。
無論監督學習還是無監督學習,都是通過某種算法來實現,而這種算法可以有多重選擇,貝葉斯就是其中一種。在多種算法中如何選擇最適合的,這才是機器學習最難的事情,也是最高境界。
?
nltk中的貝葉斯分類器 ?
貝葉斯是概率論的鼻祖,貝葉斯定理是關于隨機事件的條件概率的一則定理,貝葉斯公式是:
P(B|A)=P(A|B)P(B)/P(A);即,已知P(A|B),P(A)和P(B)可以計算出P(B|A)。
貝葉斯分類器就是基于貝葉斯概率理論設計的分類器算法,nltk庫中已經實現,具體用法如下:
import sys
reload(sys)
sys.setdefaultencoding(
"utf-8" )
import nltkmy_train_set = [({
'feature1' :
u'a' },
'1' ),({
'feature1' :
u'a' },
'2' ),({
'feature1' :
u'a' },
'3' ),({
'feature1' :
u'a' },
'3' ),({
'feature1' :
u'b' },
'2' ),({
'feature1' :
u'b' },
'2' ),({
'feature1' :
u'b' },
'2' ),({
'feature1' :
u'b' },
'2' ),({
'feature1' :
u'b' },
'2' ),({
'feature1' :
u'b' },
'2' ),]
classifier = nltk.NaiveBayesClassifier.train(my_train_set)
print classifier.classify({
'feature1' :
u'a' })
print classifier.classify({
'feature1' :
u'b' })
?
執行后判斷特征a和特征b的分類分別是3和2
因為訓練集中特征是a的分類是3的最多,所以會歸類為3
當然實際中訓練樣本的數量要多的多,特征要多的多
請尊重原創,轉載請注明來源網站www.shareditor.com以及原始鏈接地址
文檔分類 不管是什么分類,最重要的是要知道哪些特征是最能反映這個分類的特點,也就是特征選取。文檔分類使用的特征就是最能代表這個分類的詞。
因為對文檔分類要經過訓練和預測兩個過程,而特征的提取是這兩個過程都需要的,所以,習慣上我們會把特征提取單獨抽象出來作為一個公共方法,比如:
from nltk.corpus
import movie_reviews
all_words = nltk.FreqDist(w.lower()
for w
in movie_reviews.words())
word_features = all_words.keys()[:
2000 ]
def document_features (document) : for word
in word_features: features[
'contains(%s)' % word] = (word
in document_words)
return features
這是一個簡單的特征提取過程,前兩行找到movie_reviews語料庫中出現詞頻最高的2000個詞作為特征,下面定義的函數就是特征提取函數,每個特征都是形如contains(***)的key,value就是True或False,表示這個詞是否在文檔中出現
那么我們訓練的過程就是:
featuresets = [(document_features(d), c)
for (d,c)
in documents]
classifier = nltk.NaiveBayesClassifier.train(featuresets)
?
要預測一個新的文檔時:
classifier.classify(document_features(d))
?
通過
classifier.show_most_informative_features(
5 )
可以找到最優信息量的特征,這對我們選取特征是非常有幫助的
?
其他文本分類 文本分類除了文檔分類外還有許多其他類型的分類,比如:
詞性標注 :屬于一種文本分類,一般是基于上下文語境的文本分類
句子分割 :屬于標點符號的分類任務,它的特征一般選取為單獨句子標識符的合并鏈表、數據特征(下一個詞是否大寫、前一個詞是什么、前一個詞長度……)
識別對話行為類型 :對話行為類型是指問候、問題、回答、斷言、說明等
識別文字蘊含 :即一個句子是否能得出另外一個句子的結論,這可以認為是真假標簽的分類任務。這是一個有挑戰的事情
從一句話里提取出十句話的信息,擴充訓練樣本 按照之前理解的內容,對一句話做處理,最多是切成一個一個的詞,再標注上詞性,僅此而已,然而事實并非如此,一句話還可以做更多的文章,如下:
什么?還能結構化? 任何語言的每一句話之所以稱為“話”,是因為它有一定的句子結構,除了一個個獨立的詞之外,他們之間還存在著某種關系。如果任何一句話可以由任何詞構成,可長可短,那么這是一個非結構化的信息,計算機是很難理解并做計算的,但是如果能夠以某種方式把句子轉化成結構化的形式,計算機就可以理解了。而如果建立結構化的知識之間的關系圖,則所謂的知識圖譜 。
實事上,人腦在理解一句話的時候也暗暗地在做著由非結構化到結構化的工作。
比如說:“我下午要和小明在公司討論一個技術問題”。這是一片非結構化的詞語拼成的一句話,但是這里面有很多隱含信息:
1)小明是一個實體
2)參與者有兩個:我和小明
3)地點設定是:公司
4)要做的事情是:討論
5)討論的內容是:問題
6)這個問題是一個技術問題
7)公司是一個地點
8)討論是一種行為
9)我和小明有某種關系
10)下午是一個時間
上面這些信息有一些是專門針對這個句子的,有一些是常理性的,對于針對句子的信息有利于理解這句話,對于常理性的信息可以積累下來用來以后理解其他句子。
那么怎么才能把非結構化的句子轉成結構化的信息呢?要做的工作除了斷句、分詞、詞性標注 之外,還要做的一個關鍵事情就是分塊 。
?
分塊 分塊就是根據句子中的詞和詞性,按照某種規則組合在一起形成一個個分塊,每個分塊代表一個實體 。常見的實體包括:組織、人員、地點、日期、時間 等
以上面的例子為例,首先我們做名詞短語分塊(NP-chunking),比如:技術問題。名詞短語分塊通過詞性標記和一些規則就可以識別出來,也可以通過機器學習的方法識別
除了名詞短語分塊還有很多其他分塊:介詞短語(PP,比如:以我……)、動詞短語(VP,比如:打人)、句子(S,我是人)
?
分塊如何標記和存儲呢? 可以采用IOB標記,I(inside,內部)、O(outside,外部)、B(begin, 開始),一個塊的開始標記為B,塊內的標識符序列標注為I,所有其他標識符標注為O
也可以用樹結構來存儲分塊,用樹結構可以解決IOB無法標注的另一類分塊,那就是多級分塊 。多級分塊就是一句話可以有多重分塊方法,比如:我以我的最高權利懲罰你。這里面“最高權利”、“我的最高權利”、“以我的最高權利”是不同類型分塊形成一種多級分塊,這是無法通過IOB標記的,但是用樹結構可以。這也叫做級聯分塊 。具體樹結構舉個例子:
(S(NP 小明) (VP(V 追趕) (NP(Det 一只) (N 兔子))))
這是不是讓你想到了語法樹?
?
關系抽取 通過上面的分塊 可以很容易識別出實體 ,那么關系抽取 實際就是找出實體和實體 之間的關系 ,這是自然語言處理一個質的跨越 ,實體識別 讓機器認知了一種事物,關系識別 讓機器掌握了一個真相。
關系抽取的第一個方法就是找到(X, a, Y)這種三元組 ,其中X和Y都是實體,a是表達關系的字符串,這完全可以通過正則來識別,因為不同語言有這不同的語法規則,所以方法都是不同的,比如中文里的“愛”可以作為這里的a,但是“和”、“因為”等就不能作為這里的a
?
編程實現 下面介紹部分有關分塊的代碼,因為中文標注好分塊的語料沒有找到,所以只能沿用英文語料來說明,但是原理是一樣的
conll2000語料中已經有標注好的分塊信息,如下:
>>> from nltk.corpus
import conll2000
>>> print conll2000.chunked_sents(
'train.txt' )[
99 ]
(S(PP Over/IN)(NP a/DT cup/NN)(PP of/IN)(NP coffee/NN),/,(NP Mr./NNP Stone/NNP)(VP told/VBD)(NP his/PRP$ story/NN)./.)
我們可以基于這些標注數據做訓練,由于這種存儲結構比較特殊,所以就不單獨基于這種結構實現parser了,只說下跟前面講的機器學習一樣,只要基于這部分數據做訓練,然后再用來標注新的語料就行了
這里介紹一下?sklearn?庫中的的一個文本分類?demo? 以下為筆者自己編輯:?
# -*- coding:utf-8 -*-import numpy as np
from sklearn.naive_bayes import MultinomialNB, BernoulliNB
from sklearn.datasets import fetch_20newsgroups
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.linear_model import RidgeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from sklearn import metrics
from time import time
from pprint import pprint
import matplotlib.pyplot as plt
import matplotlib as mpldef test_clf(clf):print u'分類器:', clfalpha_can = np.logspace(-3, 2, 10)model = GridSearchCV(clf, param_grid={'alpha': alpha_can}, cv=5)m = alpha_can.sizeif hasattr(clf, 'alpha'):model.set_params(param_grid={'alpha': alpha_can})m = alpha_can.sizeif hasattr(clf, 'n_neighbors'):neighbors_can = np.arange(1, 15)model.set_params(param_grid={'n_neighbors': neighbors_can})m = neighbors_can.sizeif hasattr(clf, 'C'):C_can = np.logspace(1, 3, 3)gamma_can = np.logspace(-3, 0, 3)model.set_params(param_grid={'C':C_can, 'gamma':gamma_can})m = C_can.size * gamma_can.sizeif hasattr(clf, 'max_depth'):max_depth_can = np.arange(4, 10)model.set_params(param_grid={'max_depth': max_depth_can})m = max_depth_can.sizet_start = time()model.fit(x_train, y_train)t_end = time()t_train = (t_end - t_start) / (5*m)print u'5折交叉驗證的訓練時間為:%.3f秒/(5*%d)=%.3f秒' % ((t_end - t_start), m, t_train)print u'最優超參數為:', model.best_params_t_start = time()y_hat = model.predict(x_test)t_end = time()t_test = t_end - t_startprint u'測試時間:%.3f秒' % t_testacc = metrics.accuracy_score(y_test, y_hat)print u'測試集準確率:%.2f%%' % (100 * acc)name = str(clf).split('(')[0]index = name.find('Classifier')if index != -1:name = name[:index] # 去掉末尾的Classifierif name == 'SVC':name = 'SVM'return t_train, t_test, 1-acc, nameif __name__ == "__main__":print u'開始下載/加載數據...'t_start = time()# remove = ('headers', 'footers', 'quotes')remove = ()categories = 'alt.atheism', 'talk.religion.misc', 'comp.graphics', 'sci.space'# categories = None # 若分類所有類別,請注意內存是否夠用data_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=0, remove=remove)data_test = fetch_20newsgroups(subset='test', categories=categories, shuffle=True, random_state=0, remove=remove)t_end = time()print u'下載/加載數據完成,耗時%.3f秒' % (t_end - t_start)print u'數據類型:', type(data_train)print u'訓練集包含的文本數目:', len(data_train.data)print u'測試集包含的文本數目:', len(data_test.data)print u'訓練集和測試集使用的%d個類別的名稱:' % len(categories)categories = data_train.target_namespprint(categories)y_train = data_train.targety_test = data_test.targetprint u' -- 前10個文本 -- 'for i in np.arange(10):print u'文本%d(屬于類別 - %s):' % (i+1, categories[y_train[i]])print data_train.data[i]print '\n\n'vectorizer = TfidfVectorizer(input='content', stop_words='english', max_df=0.5, sublinear_tf=True)x_train = vectorizer.fit_transform(data_train.data) # x_train是稀疏的,scipy.sparse.csr.csr_matrixx_test = vectorizer.transform(data_test.data)print u'訓練集樣本個數:%d,特征個數:%d' % x_train.shapeprint u'停止詞:\n',pprint(vectorizer.get_stop_words())feature_names = np.asarray(vectorizer.get_feature_names())print u'\n\n===================\n分類器的比較:\n'clfs = (MultinomialNB(), # 0.87(0.017), 0.002, 90.39%BernoulliNB(), # 1.592(0.032), 0.010, 88.54%KNeighborsClassifier(), # 19.737(0.282), 0.208, 86.03%RidgeClassifier(), # 25.6(0.512), 0.003, 89.73%RandomForestClassifier(n_estimators=200), # 59.319(1.977), 0.248, 77.01%SVC() # 236.59(5.258), 1.574, 90.10%)result = []for clf in clfs:a = test_clf(clf)result.append(a)print '\n'result = np.array(result)time_train, time_test, err, names = result.Ttime_train = time_train.astype(np.float)time_test = time_test.astype(np.float)err = err.astype(np.float)x = np.arange(len(time_train))mpl.rcParams['font.sans-serif'] = [u'simHei']mpl.rcParams['axes.unicode_minus'] = Falseplt.figure(figsize=(10, 7), facecolor='w')ax = plt.axes()b1 = ax.bar(x, err, width=0.25, color='#77E0A0')ax_t = ax.twinx()b2 = ax_t.bar(x+0.25, time_train, width=0.25, color='#FFA0A0')b3 = ax_t.bar(x+0.5, time_test, width=0.25, color='#FF8080')plt.xticks(x+0.5, names)plt.legend([b1[0], b2[0], b3[0]], (u'錯誤率', u'訓練時間', u'測試時間'), loc='upper left', shadow=True)plt.title(u'新聞組文本數據不同分類器間的比較', fontsize=18)plt.xlabel(u'分類器名稱')plt.grid(True)plt.tight_layout(2)plt.show()
創作挑戰賽 新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔 為你收集整理的NLP 中的文本分类 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。