https://www.cnblogs.com/jiayongji/p/7119072.htmlhtml
到網上隨便一搜"三體全集",就很容易下載到三體三部曲的全集文本(txt文檔大概有2~3Mb),這裏重命名爲santi.txt,並存放到當前目錄下。python
# coding:utf-8 import sys # 設置環境爲utf-8編碼格式,防止處理中文出錯 reload(sys) sys.setdefaultencoding('utf-8') # 讀取三體全集文本 santi_text = open('./santi.txt').read()
print len(santi_text) # 輸出: ''' 2681968 '''
能夠看出文本的長度有2681968字節,數據量仍是很龐大的,語料庫足夠豐富。緩存
下面用jieba.posseg模塊對文本進行分詞並標註詞性,這裏標註詞性的目的是爲了後面接下來根據詞性過濾掉那些沒有實際意義的詞(如'好的'、'通常'、'他的'等等這種詞),而將分詞結果緩存到文件中是爲了提升每次運行腳本的效率,畢竟這麼大的數據量,分詞一次仍是耗時很長的(大概爲幾分鐘),緩存到文件中,只需第一次作一次分詞,後面再運行腳本就只需從文件中讀取分詞結果便可,畢竟讀文件的速度比分詞要快不少。下面上代碼:app
import jieba.posseg as psg # 將三體全集文本分詞,並附帶上詞性,由於數據量比較大,防止每次運行腳本都花大量時間,因此第一次分詞後就將結果存入文件out.txt中 # 至關於作一個緩存,格式爲每一個詞佔一行,每一行的內容爲: # 詞 詞性 santi_words_with_attr = [(x.word,x.flag) for x in psg.cut(santi_text) if len(x.word) >= 2] # 這裏的x.word爲詞自己,x.flag爲詞性 print len(santi_words_with_attr) # 輸出: with open('out.txt','w+') as f: for x in santi_words_with_attr: f.write('{0}\t{1}\n'.format(x[0],x[1]))
運行上面一段代碼,幾分鐘以後在當前目錄生成了一個out.txt文件,有273033行,數據量仍是很是大的,其前幾行的內容以下:ui
''' 手機 n TXT eng 小說 n 下載 v www eng sjtxt eng com eng 歡迎您 l sjtxt eng 推薦 v 好書 n x x x '''
你確定會大呼一聲:這什麼鬼!?!!!編碼
不急,這是由於文本中存在大量的咱們不須要的詞,甚至還有不少空白符詞,這確定是無法玩的,因此接下來咱們對垃圾詞進行過濾,對數據作一下清洗。spa
如今咱們緩存的分詞結果文件out.txt就能夠派上用場了,爲了清洗分詞結果,咱們須要再次獲取分詞結果,而如今就不須要再運行一次超級耗時的分詞代碼了,而只需從out.txt中讀取便可,上代碼:code
# 從out.txt中讀取帶詞性的分詞結果列表 santi_words_with_attr = [] with open('out.txt','r') as f: for x in f.readlines(): pair = x.split() if len(pair) < 2: continue santi_words_with_attr.append((pair[0],pair[1])) # 將分詞列表的詞性構建成一個字典,以便後面使用,格式爲: # {詞:詞性} attr_dict = {} for x in santi_words_with_attr: attr_dict[x[0]] = x[1] # 要過濾掉的詞性列表,這些詞性的詞都是沒有實際意義的詞,如連詞、代詞等虛詞,這個列表初始化爲空列表,後面根據分析結果手工往裏面一個個添加 stop_attr = [] # 獲取過濾掉stop_attr裏的詞性的詞後的分詞列表 words = [x[0] for x in santi_words_with_attr if x[1] not in stop_attr] # 統計在分詞表中出現次數排名前500的詞的列表,並將結果輸出到文件most.txt中,每行一個詞,格式爲: # 詞,出現次數,詞性 from collections import Counter c = Counter(words).most_common(500) with open('most.txt','w+') as f: for x in c: f.write('{0},{1},{2}\n'.format(x[0],x[1],attr_dict[x[0]]))
第一次運行上述代碼,生成的most.txt文件有500行,前10行內容以下:orm
''' 一個,3057,m 沒有,2128,v 他們,1690,r 咱們,1550,r 程心,1451,n 這個,1357,r 本身,1347,r 如今,1273,t 已經,1259,d 羅輯,1256,n '''
能夠看到詞頻排名前四的都是些沒意義的詞,而第5個'程心'纔是三體中有實際意義的詞(程聖母果真厲害)。等等,這是由於咱們沒有將前四名這些詞的詞性添加到stop_attr列表中,致使它們並無被過濾掉,那咱們如今就把這前4個詞的詞性添加到stop_attr列表中,stop_attr列表變成:['m','v','r'],再次運行腳本,most.txt的內容(前10個詞)變爲了:htm
''' 程心,1451,n 如今,1273,t 已經,1259,d 羅輯,1256,n 世界,1243,n 地球,951,n 人類,935,n 太空,930,n 三體,879,n 宇宙,875,n '''
能夠看到,咱們成功清洗掉了剛剛前四名的無心義的詞,'程心'成功變爲詞頻最高的詞。可是第二、3名的'如今'、'已經'等詞顯然也是咱們不須要的,那麼就重複上面的過程,把這些不須要的詞性添加到stop_attr列表中,再看結果。而後繼續重複以上過程,重複N次以後,我獲得的stop_attr變成了:['a','ad','b','c','d','f','df','m','mq','p','r','rr','s','t','u','v','z'],長長的一串。而most.txt的內容變爲了(前20行):
''' 程心,1451,n 羅輯,1256,n 世界,1243,n 地球,951,n 人類,935,n 太空,930,n 三體,879,n 宇宙,875,n 太陽,775,ns 艦隊,649,n 飛船,644,n 汪淼,633,nrfg 時間,611,n 文明,561,nr 東西,515,ns 信息,480,n 感受,468,n 智子,452,n 計劃,451,n 葉文潔,446,nr 太陽系,428,n '''
能夠看出分詞結果已經被清洗的很乾淨了,也能夠發現咱們須要的有實際意義的詞絕大多數都爲名詞(n或n開頭的)。
接下來咱們把文本中的TopN詞彙及詞頻輸出到result.txt中,每一行一個詞,格式爲:詞,詞頻
from collections import Counter c = Counter(words).most_common(500) with open('result.txt','w+') as f: for x in c: f.write('{0},{1}\n'.format(x[0],x[1]))
獲得的result.txt的前10行內容以下:
''' 程心,1451 羅輯,1256 世界,1243 地球,951 人類,935 太空,930 三體,879 宇宙,875 太陽,775 艦隊,649 '''
將上述每一步的代碼封裝成一個完整的腳本,以下:
# coding:utf-8 import jieba.posseg as psg from collections import Counter import sys # 對文本分詞並標註詞性,並緩存到文件 def cut_and_cache(text): # 將三體全集文本分詞,並附帶上詞性,由於數據量比較大,防止每次運行腳本都花大量時間,因此第一次分詞後就將結果存入文件cut_result.txt中 # 至關於作一個緩存,格式爲每一個詞佔一行,每一行的內容爲: # 詞,詞性 santi_words_with_attr = [(x.word,x.flag) for x in psg.cut(santi_text) if len(x.word) >= 2] print len(santi_words_with_attr) with open('cut_result.txt','w+') as f: for x in santi_words_with_attr: f.write('{0}\t{1}\n'.format(x[0],x[1])) # 從cut_result.txt中讀取帶詞性的分詞結果列表 def read_cut_result(): santi_words_with_attr = [] with open('cut_result.txt','r') as f: for x in f.readlines(): pair = x.split() if len(pair) < 2: continue santi_words_with_attr.append((pair[0],pair[1])) return santi_words_with_attr # 將分詞列表的詞性構建成一個字典,以便後面使用,格式爲: # {詞:詞性} def build_attr_dict(santi_words_with_attr): attr_dict = {} for x in santi_words_with_attr: attr_dict[x[0]] = x[1] return attr_dict # 統計在分詞表中出現次數排名前500的詞的列表,並將結果輸出到文件result.txt中,每行一個詞,格式爲: # 詞,出現次數 def get_topn_words(words,topn): c = Counter(words).most_common(topn) with open('result.txt','w+') as f: for x in c: f.write('{0},{1}\n'.format(x[0],x[1])) def main(): # 設置環境爲utf-8編碼格式,防止處理中文出錯 reload(sys) sys.setdefaultencoding('utf-8') # 讀取三體全集文本 santi_text = open('./santi.txt').read() # 分詞並緩存,只需運行一次,後續可註釋掉 cut_and_cache(santi_text) # 從cut_result.txt中讀取帶詞性的分詞結果列表 santi_words_with_attr = read_cut_result() # 構建詞性字典,這個字典在探索stop_attr的時候會有幫助 # attr_dict = build_attr_dict(santi_words_with_attr) # 要過濾掉的詞性列表 stop_attr = ['a','ad','b','c','d','f','df','m','mq','p','r','rr','s','t','u','v','z'] # 過濾掉不須要的詞性的詞 words = [x[0] for x in santi_words_with_attr if x[1] not in stop_attr] # 獲取topn的詞並存入文件result.txt get_topn_words(words = words,topn = 500) if __name__ == '__main__': main()