1. 程式人生 > >[python] Kmeans文字聚類演算法+PAC降維+Matplotlib顯示聚類影象

[python] Kmeans文字聚類演算法+PAC降維+Matplotlib顯示聚類影象

0 前言

本文主要講述以下幾點:

        1.通過scikit-learn計算文字內容的tfidf並構造N*M矩陣(N個文件 M個特徵詞)
        2.呼叫scikit-learn中的K-means進行文字聚類;
        3.使用PAC進行降維處理,每行文字表示成兩維資料;
        4.最後呼叫Matplotlib顯示聚類效果圖。

文章更詳細的內容參考:http://blog.csdn.net/eastmount/article/details/50473675
由於涉及到了我的畢業設計,一些更深入的內容和詳細的資訊,我這裡就不再詳細敘述了,畢竟還要查重和未發表。但其中一些演算法的實現步驟是很清晰的。
最後希望文章對你有所幫助,

尤其是那些正在學習文字相似度計算或文字聚類的初學者。


1 輸入

文字輸入是讀取本地的01_All_BHSpider_Content_Result.txt檔案,裡面包括1000行資料,其中001~400行為景區、401~600為動物、601~800為人物明星、801~1000為國家地理文字內容(百度百科摘要資訊)。
該內容可以自定義爬蟲進行爬取,同時分詞采用Jieba進行。








2 原始碼

程式碼如下,詳見註釋和後面的學習筆記推薦:

# coding=utf-8  
""" 
Created on 2016-01-16 @author: Eastmount
輸入:開啟 All_BHSpider_Result.txt 對應1000個文字
     001~400 5A景區 401~600 動物 601~800 人物 801~1000 國家
輸出:BHTfidf_Result.txt tfidf值 聚類圖形 1000個類標
引數:weight權重 這是一個重要引數
"""  
  
import time          
import re          
import os  
import sys
import codecs
import shutil
import numpy as np
import matplotlib
import scipy
import matplotlib.pyplot as plt
from sklearn import feature_extraction  
from sklearn.feature_extraction.text import TfidfTransformer  
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.feature_extraction.text import HashingVectorizer 

if __name__ == "__main__":
    
    #########################################################################
    #                           第一步 計算TFIDF
    
    #文件預料 空格連線
    corpus = []
    
    #讀取預料 一行預料為一個文件
    for line in open('01_All_BHSpider_Content_Result.txt', 'r').readlines():
        #print line
        corpus.append(line.strip())
    #print corpus

    #參考: http://blog.csdn.net/abcjennifer/article/details/23615947
    #vectorizer = HashingVectorizer(n_features = 4000)
    
    #將文字中的詞語轉換為詞頻矩陣 矩陣元素a[i][j] 表示j詞在i類文字下的詞頻
    vectorizer = CountVectorizer()

    #該類會統計每個詞語的tf-idf權值
    transformer = TfidfTransformer()

    #第一個fit_transform是計算tf-idf 第二個fit_transform是將文字轉為詞頻矩陣
    tfidf = transformer.fit_transform(vectorizer.fit_transform(corpus))

    #獲取詞袋模型中的所有詞語  
    word = vectorizer.get_feature_names()
    
    #將tf-idf矩陣抽取出來,元素w[i][j]表示j詞在i類文字中的tf-idf權重
    weight = tfidf.toarray()

    #列印特徵向量文字內容
    print 'Features length: ' + str(len(word))
    resName = "BHTfidf_Result.txt"
    result = codecs.open(resName, 'w', 'utf-8')
    for j in range(len(word)):
        result.write(word[j] + ' ')
    result.write('\r\n\r\n')

    #列印每類文字的tf-idf詞語權重,第一個for遍歷所有文字,第二個for便利某一類文字下的詞語權重  
    for i in range(len(weight)):
        #print u"-------這裡輸出第", i, u"類文字的詞語tf-idf權重------"  
        for j in range(len(word)):
            #print weight[i][j],
            result.write(str(weight[i][j]) + ' ')
        result.write('\r\n\r\n')

    result.close()


    ########################################################################
    #                               第二步 聚類Kmeans

    print 'Start Kmeans:'
    from sklearn.cluster import KMeans
    clf = KMeans(n_clusters=4)   #景區 動物 人物 國家
    s = clf.fit(weight)
    print s

    '''
    print 'Start MiniBatchKmeans:'
    from sklearn.cluster import MiniBatchKMeans
    clf = MiniBatchKMeans(n_clusters=20)
    s = clf.fit(weight)
    print s
    '''

    #中心點
    print(clf.cluster_centers_)
    
    #每個樣本所屬的簇
    label = []               #儲存1000個類標 4個類
    print(clf.labels_)
    i = 1
    while i <= len(clf.labels_):
        print i, clf.labels_[i-1]
        label.append(clf.labels_[i-1])
        i = i + 1

    #用來評估簇的個數是否合適,距離越小說明簇分的越好,選取臨界點的簇個數  958.137281791
    print(clf.inertia_)


    ########################################################################
    #                               第三步 圖形輸出 降維

    from sklearn.decomposition import PCA
    pca = PCA(n_components=2)             #輸出兩維
    newData = pca.fit_transform(weight)   #載入N維
    print newData

    #5A景區
    x1 = []
    y1 = []
    i=0
    while i<400:
        x1.append(newData[i][0])
        y1.append(newData[i][1])
        i += 1

    #動物
    x2 = []
    y2 = []
    i = 400
    while i<600:
        x2.append(newData[i][0])
        y2.append(newData[i][1])
        i += 1

    #人物
    x3 = []
    y3 = []
    i = 600
    while i<800:
        x3.append(newData[i][0])
        y3.append(newData[i][1])
        i += 1

    #國家
    x4 = []
    y4 = []
    i = 800
    while i<1000:
        x4.append(newData[i][0])
        y4.append(newData[i][1])
        i += 1

    #四種顏色 紅 綠 藍 黑
    plt.plot(x1, y1, 'or')
    plt.plot(x2, y2, 'og')
    plt.plot(x3, y3, 'ob')
    plt.plot(x4, y4, 'ok')
    plt.show()
    



3 輸出結果

採用Kmeans中設定類簇數為4,分別表示景區、動物、明星和國家。
其中執行結果如下圖所示,包括17900維tfidf特徵向量:

聚類輸出結果如下圖所示:其中"紅-景區 綠-動物 藍-人物 黑-國家"。由於資料集比較小,文字聚類效果還是很明顯的,而LDA演算法是計算每個主題分佈的演算法,推薦你也去學習下。



4 效能評估

這裡我想結合文字聚類簡單敘述下最常用的評估方法:
        正確率 Precision = 正確識別的個體總數 /  識別出的個體總數
        召回率 Recall = 正確識別的個體總數 /  測試集中存在的個體總數
        F值 F-measure = 正確率 * 召回率 * 2 / (正確率 + 召回率)

由於"clf.labels_"會返回聚類每個樣本所屬的簇,比如1000行資料,就會返回1000個label值。同時,clf = KMeans(n_clusters=4)設定了類簇為4,故每個值對應在0、1、2、3中的一個,統計結果如下:

其中以世界國家為例,label1數目為198,同時識別出的個體數=198(世界國家)+2(動物)=200,故:
        準確率=198/200=0.990
其中動物裡面有兩個聚類到了世界國家中。而召回率我以人物明星為例,因為知道測試集中601~800這200個數據對應人物明星,故測試集中存在個體數為200,而正確識別數目為185個,故:
        召回率=185/200=0.925
最後計算F值即可。同時可以計算巨集平均聚類準確率(Macro-Prec)和巨集平均召回率(Macro-Rec)。




5 總結及推薦學習資料



(By:Eastmount 2016-01-20 深夜5點    )