一、監(jiān)督式分類:建立在訓練語料基礎上的分類

訓練過程中,特征提取器將輸入轉化為特征集,并且記錄對應的正確分類。生成模型。預測過程中,未見過的輸入被轉換特征集,通過模型產(chǎn)生預測標簽。

特征提取器和樸素貝葉斯分類器

特征提取器返回字典,這個字典被稱為特征集。然后利用
nltk自帶的樸素貝葉斯分類器 NaiveBayesClassifier 生成分類器。并且可以用nltk.classify.accuracy(分類器,測試集) 測試準確度。

import nltkfrom nltk.corpus import namesimport randomdef gender_features(word): #特征提取器
    return {'last_letter':word[-1]} #特征集就是最后一個字母names = [(name,'male') for name in names.words('male.txt')]+[(name,'female') for name in names.words('female.txt')]
random.shuffle(names)#將序列打亂features = [(gender_features(n),g) for (n,g) in names]#返回對應的特征和標簽train,test = features[500:],features[:500] #訓練集和測試集classifier = nltk.NaiveBayesClassifier.train(train) #生成分類器print('Neo is a',classifier.classify(gender_features('Neo')))#分類print(nltk.classify.accuracy(classifier,test)) #測試準確度classifier.show_most_informative_features(5)#得到似然比,檢測對于哪些特征有用

當然,當我們訓練大的語料庫的時候,鏈表會占用很大內存。這時候nltk提供了:apply_features,會生成鏈表,但是不會在內存中存儲所有對象。

from nltk.classify import apply_features
train_set = apply_features(gender_features,names[500:])
test_set = apply_features(gender_features,names[:500])

過擬合:當特征過多

當特征過多的時候(特征集的鍵值過多),會對一般化的新例子不起作用,稱為過擬合。如果抉擇特征集的大小,需要不停的測試,找到最吻合的特征集。

錯誤分析

為了使特征提取器準確度更高,一般將源數(shù)據(jù)分為兩大部分,三小部分:

  • 開發(fā)集:

    • 訓練集:負責開發(fā)

    • 開發(fā)測試集:負責錯誤分析

  • 測試集:負責最終評估

下面是查找報錯信息的案例:

import nltkfrom nltk.corpus import namesimport randomdef gender_features(word): #特征提取器
    return {'last_letter':word[-1]} #特征集就是最后一個字母names = [(name,'male') for name in names.words('male.txt')]+[(name,'female') for name in names.words('female.txt')]

train_names = names[1500:]
devtest_names = names[500:1500]
test_names = names[:500]

train_set = [(gender_features(n),g) for (n,g) in train_names]
devtest_set = [(gender_features(n),g) for (n,g) in devtest_names]
test_set = [(gender_features(n),g) for (n,g) in test_names]

classifier = nltk.NaiveBayesClassifier.train(train_set)print(nltk.classify.accuracy(classifier,devtest_set))######################記錄報錯的案例###############################errors = []for (name,tag) in devtest_names:
    guess = classifier.classify(gender_features(name))    if guess!=tag:
        errors.append((tag,guess,name))##################################################################

我們發(fā)現(xiàn)準確度低,因為倒數(shù)第二個字母也很有關聯(lián)。所以我們可以改進特征提取器:

def gender_features(word): #特征提取器
    return {'last_letter':word[-1],'last__letter':word[-2]} #特征集就是最后一個字母和倒數(shù)第二個字母

觀察結果,發(fā)現(xiàn),準確度提高了12%。重復這個過程,使得特征提取器更加完善。


二、實例:文本分類和詞性標注

文本分類

這里的分類標簽選成詞匯,通過對文本前N個詞的觀察,得到預測標簽。

import nltkfrom nltk.corpus import movie_reviews

all_words = nltk.FreqDist(w.lower() for w in movie_reviews.words())
word_features = all_words.most_common(2) #前兩千個最常出現(xiàn)的單詞def document_features(document):
    document_words = set(document)
    features = {}    for (word,freq) in word_features:
        features['contains(%s)'%word] = (word in document_words) #參數(shù)文檔中是否包含word:True/False
    return features

documents = [(list(movie_reviews.words(fileid)),category) for category in movie_reviews.categories() for fileid in movie_reviews.fileids(category)]
random.shuffle(documents)

features = [(document_features(d),c)for (d,c) in documents]
train_set,test_set = features[100:],features[:100]

classifier = nltk.NaiveBayesClassifier.train(train_set)print(nltk.classify.accuracy(classifier,test_set))

詞性標注:“決策樹”分類器

這里的分類器是決策樹分類器:DecisionTreeClassifier??梢酝ㄟ^classifier.pseudocode(depth = ?) 這查詢深度為depth的樹,并且打印出來。順便表示,我再走下面的程序的時候,電腦炸了。建議在集群上運行。

from nltk.corpus import brownimport nltk

suffix_fdist = nltk.FreqDist()for word in brown.words():
    word = word.lower()    #suffix_fdist.inc(word[-1:]) python2
    suffix_fdist[word[-1:]] += 1 #python3
    suffix_fdist[word[-2:]] += 1
    suffix_fdist[word[-3:]] += 1common_suffixes = suffix_fdist.most_common(100) #獲得常見特征鏈表#定義特征提取器:def pos_features(word):
    features = {}    for (suffix,times) in common_suffixes:
        features['endswith(%s)' % suffix] = word.lower().endswith(suffix)    return features

tagged_words = brown.tagged_words(categories='news')
featuresets = [(pos_features(n),g)for (n,g) in tagged_words]
size = int(len(featuresets)*0.1)

train_set , test_set= featuresets[size:], featuresets[:size]
classifier = nltk.DecisionTreeClassifier.train(train_set) #“決策樹分類器”print(nltk.classify.accuracy(classifier,test_set))

三、更近一步的連續(xù)分類或貪婪序列分類:在樸素貝葉斯和“決策樹”之后

這種分類模型是為了獲取相關分類之間的依賴關系。為第一個輸入找到最佳標簽,然后再次基礎上找到對應的下一個輸入的最佳標簽。不斷重復,以至所有輸入都被貼上標簽。所以,我們需要提供一個參數(shù)history,用來擴展特征。

事實證明,我的電腦又炸了。

利用聯(lián)合分類器模型進行詞性標注:

import nltkfrom nltk.corpus import brown#帶有歷史的特征提取器def pos_features(sentence,i,history):
    features = {'suffix(1)':sentence[i][-1:],\
               'suffix(2)':sentence[i][-2:],\
               'suffix(3)':sentence[i][-3:]}    if i==0:#當它在分界線的時候,沒有前置word 和 word-tag
        features['prev-word'] = '<START>'
        features['prev-tag'] = '<START>'
    else:#記錄前面的history
        features['prev-word'] = sentence[i-1]
        features['prev-tag'] = history[i-1]    return features''' ###########流程式###############tagged_sents = brown.tagged_sents(categories="news")size = int(len(tagged_sents)*0.1)train_sents,test_sents = tagged_sents[size:],tagged_sents[:size]train_set = []for tagged_sent in train_sents:    untagged_set = nltk.tag.untag(tagged_sent)     history = []    for i,(word,tag) in enumerate(tagged_sent):        featureset = pos_features(untagged_set,i,history)        history.append(tag)        train_set.append((featureset,tag))    classifier = nltk.NaiveBayesClassifier.train(train_set)'''#########類思想重寫##################class ConsecutivePosTagger(nltk.TaggerI): #這里定義新的選擇器類,繼承nltk.TaggerI
    def __init__(self,train_sents):
        train_set = []        for tagged_sent in train_sents:
            untagged_set = nltk.tag.untag(tagged_sent) #去標簽化
            history = []            for i,(word,tag) in enumerate(tagged_sent):
                featureset = pos_features(untagged_set,i,history)
                history.append(tag) #將tag添加進去
                train_set.append((featureset,tag)) #拿到了訓練集
            self.classifier = nltk.NaiveBayesClassifier.train(train_set) #創(chuàng)建訓練模型

    def tag(self,sentence): #必須定義tag方法
        history = []        for i,word in enumerate(sentence):
            featureset = pos_features(sentence,i,history)
            tag = self.classifier.classify(featureset)
            history.append(tag)        return zip(sentence,history)
        
tagged_sents = brown.tagged_sents(categories="news")
size = int(len(tagged_sents)*0.1)
train_sents,test_sents = tagged_sents[size:],tagged_sents[:size]#print(train_sents)tagger = ConsecutivePosTagger(train_sents)print(tagger.evaluate(test_sents))

四、評估

之前我們選擇測試集和開發(fā)集,都是在一個原有集合下。這樣,示例相似程度很大,不利于推廣到其他數(shù)據(jù)集。而評估最簡單的度量就是準確度,即:accuracy()函數(shù)。除了這個,精確度、召回率和F-度量值也確實影響了準確度。

- 精確度:發(fā)現(xiàn)項目中多少是相關的。TP/(TP+FP)
- 召回率:表示相關項目發(fā)現(xiàn)了多少。TP(TP+FN)
- F-度量值:精確度和召回率的調和平均數(shù)。
其中,T:true;P:Positive;F:false;N:negative。組合即可。例如TP:真陽性(正確識別為相關的),TN:真陰性(相關項目中錯誤識別為不想關的)


五、三種分類器的總結

之前我們發(fā)現(xiàn)。同樣的特征集,樸素貝葉斯分類器就可以輕松跑完,但是決策樹分類器不行。除了過擬合的因素外,還是因為樹結構強迫特征按照特定的順序檢查,即便他是重復的,而在回溯的過程中,又有重復運算,導致時間和空間的雙重浪費。

樸素貝葉斯分類器允許所有恩正“并行”起作用,從計算每個標簽的先驗概率開始。并且建立樸素貝葉斯的時候采用了平滑技術(在給定的貝葉斯模型上)。

最后的最大熵分類器,使用搜索技術找出一組能最大限度的提高分類器性能的參數(shù)。由于他會用迭代優(yōu)化技術選擇參數(shù),花費時間很長。


六、后記

努力地看書了,然而還是沒有看懂。感覺是因為相應的數(shù)學知識和算法知識沒到位。以后積累充足會重看。
當然,對于現(xiàn)在用的層面來說,較深入的了解原理,基本可以解決大多數(shù)問題。但是要是做到算法優(yōu)化,還是要自己去調參,或者改進算法。
由于博主水平有限,希望各路大牛不li賜教。


歡迎進一步交流本博文相關內容:

博客園地址 : http://www.cnblogs.com/AsuraDong/

CSDN地址 : http://blog.csdn.net/asuradong

也可以致信進行交流 : xiaochiyijiu@163.com 

歡迎轉載 , 但請指明出處  :  )


Name:不告訴你   :)
E-mail:xiaochiyijiu@163.com
Github:AsuraDong

http://www.cnblogs.com/AsuraDong/p/7020304.html