1. 程式人生 > >基於 K-Means 演算法的文字聚類

基於 K-Means 演算法的文字聚類

先粘一篇我的實驗報告,其中涉及的細節,有時間再提出來總結

實驗內容:基於K-Means演算法的文字聚類
實驗要求:
1、 能夠從社交媒體或網上給定的資料集(資料集已給定),從中挖掘出新聞話題,如線上檢測微博訊息中大量突現的關鍵字,並將它們進行聚類,從而找到若干個新聞話題。
2、 給定一個新聞資訊或報道作為測試樣本,測試其所屬的報道分類。
3、 最終要求有訓練集,測試集,聚類模型和相關原始碼及簡要說明。
4、 系統實現包含預處理,特徵提取,訓練時採用的聚類模型,測試時採用的分類模型。
5、 報告內容包括:實現流程,概要設計,關鍵模組詳細設計實現。
6、 提交時以壓縮包形式,需包括:系統實現原始碼(包含清晰註釋),訓練集和測試集,實驗報告等三部分內容。壓縮包命名方式:學號-姓名-班級.rar
實驗預備知識: Python基本語法
K-means聚類演算法相關知識
基於TF-IDF演算法的特徵提取
文件相似度計算
實驗環境: Windows10作業系統Python2.7 IDLE

一、 實現流程
這裡寫圖片描述
二、 概要設計
1、 讀取訓練集文字內容
讀取給定資料集資料夾中每一個文件後,將文字內容寫入一個Result.txt,每一行為一個文件,方便後面詞頻矩陣的處理。
2、 文字預處理
讀取之前存放所有文字內容的Result.txt,將其內容去空格,去標點,並用結巴進行分詞。
3、 特徵提取
使用scikit-learn工具呼叫CountVectorizer()和TfidfTransformer()函式計算TF-IDF值,將文字轉為詞頻矩陣,矩陣元素a[i][j] 表示j詞在i類文字下的詞頻。將詞頻矩陣儲存在TF-IDF_Result文件中。
4、 K-Means聚類
,對文字根據瀏覽內容後的經驗分為3類,呼叫sklearn.cluster實現,並儲存該聚類模型,對測試集使用
5、 測試集分類
使用clf.fit_predict 方法測試測試集文字。
三、 關鍵模組詳細設計實現
1、 特徵提取

from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer

# 將文字中的詞語轉換為詞頻矩陣 矩陣元素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()

2、 聚類模型

from sklearn.cluster import KMeans
from sklearn.externals import joblib

def K_Means(weight):
    print 'Start Kmeans:'

    # 選擇3箇中心點
    clf = KMeans(n_clusters=3)

    # clf.fit(X)可以把資料輸入到分類器裡
    clf.fit(weight)

    # 3箇中心點
    print 'cluster_center:'
    print(clf.cluster_centers_)

    # 每個樣本所屬的簇
    # print(clf.labels_)
    print'list_number label  '
    i = 1
    while i <= len(clf.labels_):
        print i,'          ',clf.labels_[i - 1]
        i = i + 1

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

    # 儲存模型
    joblib.dump(clf, 'km.pkl')

四、 結果展示
1、聚類結果
注:訓練集在train資料夾中
這裡寫圖片描述
這裡寫圖片描述

2、 分類結果
注:測試集在test資料夾中
這裡寫圖片描述

六、實驗原始碼

# *- coding: utf-8 -*-


import sys
import os
import jieba
import jieba.analyse
import codecs
import re
from sklearn.feature_extraction.text import TfidfTransformer
from sklearn.feature_extraction.text import CountVectorizer
from zhon.hanzi import punctuation
from sklearn.cluster import KMeans
from sklearn.externals import joblib

reload(sys)
sys.setdefaultencoding('utf8')


# Step1:Read file

def read_file():
    path = "train\\C4-Literature\\"
    resName = "Result.txt"
    if os.path.exists(resName):
        os.remove(resName)
    result = codecs.open(resName, 'w', 'utf-8')

    num = 1
    while num <= 33:
        name = "C4-Literature%d" % num
        fileName = path + str(name) + ".txt"
        source = open(fileName, 'r')
        line = source.readline().decode('GB2312')
        line = line.strip('\n')
        line = line.strip('\r')

        while line != "":
            line = line.encode('utf-8')
            line = line.replace('\n', ' ')
            line = line.replace('\r', ' ')
            result.write(line + ' ')
            line = source.readline().decode('GB2312')
        else:
            result.write('\r\n')
            source.close()
        num = num + 1

    else:
        result.close()

    return resName

# Step2:cut file and get feature vector matrixes
def get_TFIDF(resname,filename):
    corpus = []  # 語料庫 空格連線

    # 讀取語料  一行為一個文件
    for line in open(resname, 'r').readlines():
        line=line.strip() # 刪除末尾的'/n'
        string = re.sub(ur"[%s]+" % punctuation, "", line.decode("utf-8"))  # 去標點
        seg_list = jieba.cut(string,cut_all=False) # 結巴分詞
        corpus.append(' '.join(seg_list))

    # 將文字中的詞語轉換為詞頻矩陣 矩陣元素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()

    # fileName = "TF-IDF_Result.txt"
    result = codecs.open(filename, '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)):
        for j in range(len(word)):
            result.write(str(weight[i][j]) + ' ')
        result.write('\r\n\r\n')

    result.close()
    return weight

# Step3:Clustering
def K_Means(weight):
    print 'Start Kmeans:'

    # 選擇3箇中心點
    clf = KMeans(n_clusters=3)

    # clf.fit(X)可以把資料輸入到分類器裡
    clf.fit(weight)

    # 3箇中心點
    print 'cluster_center:'
    print(clf.cluster_centers_)

    # 每個樣本所屬的簇
    # print(clf.labels_)
    print'list_number label  '
    i = 1
    while i <= len(clf.labels_):
        print i,'          ',clf.labels_[i - 1]
        i = i + 1

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

    # 儲存模型
    joblib.dump(clf, 'km.pkl')

# Step4:Test
def test():
    path = "test\\"
    test_name = "test_result.txt"
    file_name = "test_TF-IDF.txt"
    if os.path.exists(test_name):
        os.remove(test_name)
    test_result = codecs.open(test_name,'w','utf-8')

    for file in os.listdir(path):
        source = open(path + file,'r')
        line = source.readline().decode('GB2312')
        line = line.strip('\n')
        line = line.strip('\r')

        while line !="":
            line = line.encode('utf-8')
            line = line.replace('\n',' ')
            line = line.replace('\r',' ')
            test_result.write(line + ' ')
            line=source.readline().decode('GB2312')

        else:
            test_result.write('\n\r')
            source.close()
    test_result.close()

    test_weight = get_TFIDF(test_name,file_name)

    # 載入儲存的模型
    clf = joblib.load('km.pkl')

    clf.fit_predict(test_weight)

    print'list_number label  '
    i = 1
    while i <= len(clf.labels_):
        print i, '          ', clf.labels_[i - 1]
        i = i + 1


if __name__ == '__main__':
    resName = read_file()
    filename = "TF-IDF_Result.txt"
    weight=get_TFIDF(resName,filename)
    K_Means(weight)
    test()