【火爐煉AI】機器學習042-NLP文字的主題建模

煉丹老頑童發表於2018-10-18

(本文所使用的Python庫和版本號: Python 3.6, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2, NLTK 3.3)

文字的主題建模時用NLP來識別文字文件中隱藏的某種模式的過程,可以發現該文件的隱藏主題,以便對文件進行分析。主題建模的實現過程是,識別出某文字文件中最有意義,最能表徵主題的詞來實現主題分類,即尋找文字文件中的關鍵詞,通過關鍵詞就可以識別出某文件的隱藏主題。


1. 準備資料集

本次所用的資料集存放在一個txt文件中,故而需要從txt文件中載入該文字內容,然後再對這些文字進行預處理。由於預處理的步驟比較多,故而此處建立一個class來完成資料的載入和預處理過程,也使得程式碼看起來更簡潔,更通用。

# 準備資料集,建一個class來載入資料集,對資料進行預處理
from nltk.tokenize import RegexpTokenizer
from nltk.corpus import stopwords
from nltk.stem.snowball import SnowballStemmer
from gensim import models, corpora

class DataSet:
    
    def __init__(self,txt_file_path):
        self.__txt_file=txt_file_path
    
    def __load_txt(self): # 從txt文件中載入文字內容,逐行讀入
        with open(self.__txt_file,'r') as file:
            content=file.readlines() # 一次性將所有的行都讀入
        return [line[:-1] for line in content] # 去掉每一行末尾的\n
    
    def __tokenize(self,lines_list): # 預處理之一:對每一行文字進行分詞
        tokenizer=RegexpTokenizer('\w+') 
        # 此處用正規表示式分詞器而不用word_tokenize的原因是:排除帶有標點的單詞
        return [tokenizer.tokenize(line.lower()) for line in lines_list]
    
    def __remove_stops(self,lines_list): # 預處理之二:對每一行取出停用詞
        # 我們要刪除一些停用詞,避免這些詞的噪聲干擾,故而需要一個停用詞表
        stop_words_list=stopwords.words('english')  # 獲取英文停用詞表
        return [[token for token in line if token not in stop_words_list]
                for line in lines_list] 
        # 這兒有點難以理解,lines_list含有的元素也是list,這一個list就是一行文字,
        # 而一行文字內部有N個分片語成,故而lines_list可以看出二維陣列,需要用兩層generator
    
    def __word_stemm(self,lines_list): # 預處理之三:對每個分詞進行詞幹提取
        stemmer=SnowballStemmer('english')
        return [[stemmer.stem(word) for word in line] for line in lines_list]
    
    def prepare(self):
        '''供外部呼叫的函式,用於準備資料集'''
        # 先從txt檔案中載入文字內容,再進行分詞,再去除停用詞,再進行詞幹提取
        stemmed_words=self.__word_stemm(self.__remove_stops(self.__tokenize(self.__load_txt())))
        # 後面的建模需要用到基於dict的詞矩陣,故而先用corpora構建dict在建立詞矩陣
        dict_words=corpora.Dictionary(stemmed_words)
        matrix_words=[dict_words.doc2bow(text) for text in stemmed_words]
        return dict_words, matrix_words 
    
    # 以下函式主要用於測試上面的幾個函式是否執行正常
    def get_content(self):
        return self.__load_txt()
    
    def get_tokenize(self):
        return self.__tokenize(self.__load_txt())
    
    def get_remove_stops(self):
        return self.__remove_stops(self.__tokenize(self.__load_txt()))
    
    def get_word_stemm(self):
        return self.__word_stemm(self.__remove_stops(self.__tokenize(self.__load_txt())))
複製程式碼

這個類是否執行正常,是否能夠得到我們預期的結果了?可以用下面的程式碼來測試

# 檢驗上述DataSet類是否執行正常
dataset=DataSet("E:\PyProjects\DataSet\FireAI\data_topic_modeling.txt")

# 以下測試load_txt()函式是否正常
content=dataset.get_content()
print(len(content))
print(content[:3])

# 以下測試__tokenize()函式是否正常
tokenized=dataset.get_tokenize()
print(tokenized)

# 一下測試__remove_stops()函式是否正常
removed=dataset.get_remove_stops()
print(removed)

# 以下測試__word_stemm()函式是否正常
stemmed=dataset.get_word_stemm()
print(stemmed)

# 以下測試prepare函式是否正常
_,prepared=dataset.prepare()
print(prepared)
複製程式碼

輸出的執行結果比較長,可以看我的github原始碼。


2. 構建模型,訓練資料集

我們用LDA模型(Latent Dirichlet Allocation, LDA)做主題建模,如下:

# 獲取資料集
dataset=DataSet("E:\PyProjects\DataSet\FireAI\data_topic_modeling.txt")
dict_words, matrix_words =dataset.prepare()

# 使用LDAModel建模
lda_model=models.ldamodel.LdaModel(matrix_words,num_topics=2,
                           id2word=dict_words,passes=25) 
# 此處假設原始文件有兩個主題
複製程式碼

上面的程式碼會建立LDAModel並對模型進行訓練,需要注意,LDAModel位於gensim模組中,這個模組需要自己用pip install gensim來安裝,安裝之後才能使用。

LDAModel會計算每個單詞的重要性,然後建立重要性計算方程,依靠此方程來給出預測主題。

如下程式碼可以列印出該重要性方程:

# 檢視模型中最重要的N個單詞
print('Most important words to topics: ')
for item in lda_model.print_topics(num_topics=2,num_words=5):
    # 此處只列印最重要的5個單詞
    print('Topic: {}, words: {}'.format(item[0],item[1]))
複製程式碼

-------------------------------------輸---------出--------------------------------

Most important words to topics: Topic: 0, words: 0.075*"need" + 0.053*"order" + 0.032*"system" + 0.032*"encrypt" + 0.032*"work" Topic: 1, words: 0.037*"younger" + 0.037*"develop" + 0.037*"promot" + 0.037*"talent" + 0.037*"train"

--------------------------------------------完-------------------------------------

########################小**********結###############################

1,一般機器學習專案需要我們自己處理的內容都是資料集方面,可以將資料集處理過程寫成一個專門的class,比如上面我把文字預處理過程寫在class裡面,每一個函式代表一種預處理方式,這樣條理清楚,具有一定通用性。

2,此處我們使用gensim模組中的LDAModel來做主題建模,gensim模組是一個非常有用的NLP處理工具,在文字內容分析中應用較多。

#################################################################


注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。

參考資料:

1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯

相關文章