jieba分詞模塊的基本用法參加我的另一篇博文:好玩的分詞(1)——python jieba分詞模塊的基本用法
《三體》是一部很好看的硬科幻作品状婶,當(dāng)初是一口氣把三部全都看完的意敛,包括《三體1》、《三體2:黑暗森林》和《三體3:死神永生》膛虫,洋洋灑灑幾十萬(wàn)字草姻,看的叫一個(gè)酣暢淋漓。本文就使用jieba分詞稍刀,對(duì)《三體》三部曲全集文本做一些有趣的分析撩独,涉及到分詞和詞頻分析等。
文本準(zhǔn)備
到網(wǎng)上隨便一搜"三體全集",就很容易下載到三體三部曲的全集文本(txt文檔大概有2~3Mb)跌榔,這里重命名為santi.txt异雁,并存放到當(dāng)前目錄下。
讀取三體全集文本
# coding:utf-8
import sys
# 設(shè)置環(huán)境為utf-8編碼格式僧须,防止處理中文出錯(cuò)
reload(sys)
sys.setdefaultencoding('utf-8')
# 讀取三體全集文本
santi_text = open('./santi.txt').read()
print len(santi_text)
# 輸出:
'''
2681968
'''
可以看出文本的長(zhǎng)度有2681968字節(jié)纲刀,數(shù)據(jù)量還是很龐大的,語(yǔ)料庫(kù)足夠豐富担平。
對(duì)文本分詞并緩存到文件中
下面用jieba.posseg
模塊對(duì)文本進(jìn)行分詞并標(biāo)注詞性示绊,這里標(biāo)注詞性的目的是為了后面接下來(lái)根據(jù)詞性過濾掉那些沒有實(shí)際意義的詞(如'好的'、'一般'暂论、'他的'等等這種詞)面褐,而將分詞結(jié)果緩存到文件中是為了提高每次運(yùn)行腳本的效率,畢竟這么大的數(shù)據(jù)量取胎,分詞一次還是耗時(shí)很長(zhǎng)的(大概為幾分鐘)展哭,緩存到文件中,只需第一次做一次分詞闻蛀,后面再運(yùn)行腳本就只需從文件中讀取分詞結(jié)果即可匪傍,畢竟讀文件的速度比分詞要快很多。下面上代碼:
import jieba.posseg as psg
# 將三體全集文本分詞觉痛,并附帶上詞性役衡,因?yàn)閿?shù)據(jù)量比較大,防止每次運(yùn)行腳本都花大量時(shí)間薪棒,所以第一次分詞后就將結(jié)果存入文件out.txt中
# 相當(dāng)于做一個(gè)緩存手蝎,格式為每個(gè)詞占一行,每一行的內(nèi)容為:
# 詞 詞性
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]))
運(yùn)行上面一段代碼棵介,幾分鐘之后在當(dāng)前目錄生成了一個(gè)out.txt文件,有273033行泼各,數(shù)據(jù)量還是非常大的鞍时,其前幾行的內(nèi)容如下:
手機(jī) n
TXT eng
小說 n
下載 v
www eng
sjtxt eng
com eng
歡迎您 l
sjtxt eng
推薦 v
好書 n
x
x
x
看到這,肯定會(huì)說:這什么鬼!?!!! [黑人問號(hào).gif]
不急扣蜻,這是因?yàn)槲谋局写嬖诖罅康奈覀儾恍枰脑~,甚至還有很多空白符詞及塘,這肯定是沒法玩的莽使,所以接下來(lái)我們對(duì)垃圾詞進(jìn)行過濾,對(duì)數(shù)據(jù)做一下清洗笙僚。
分詞結(jié)果清洗
現(xiàn)在我們緩存的分詞結(jié)果文件out.txt就可以派上用場(chǎng)了芳肌,為了清洗分詞結(jié)果,我們需要再次獲取分詞結(jié)果,而現(xiàn)在就不需要再運(yùn)行一次超級(jí)耗時(shí)的分詞代碼了亿笤,而只需從out.txt中讀取即可翎迁,上代碼:
# 從out.txt中讀取帶詞性的分詞結(jié)果列表
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]))
# 將分詞列表的詞性構(gòu)建成一個(gè)字典,以便后面使用净薛,格式為:
# {詞:詞性}
attr_dict = {}
for x in santi_words_with_attr:
attr_dict[x[0]] = x[1]
# 要過濾掉的詞性列表汪榔,這些詞性的詞都是沒有實(shí)際意義的詞,如連詞肃拜、代詞等虛詞痴腌,這個(gè)列表初始化為空列表,后面根據(jù)分析結(jié)果手工往里面一個(gè)個(gè)添加
stop_attr = []
# 獲取過濾掉stop_attr里的詞性的詞后的分詞列表
words = [x[0] for x in santi_words_with_attr if x[1] not in stop_attr]
# 統(tǒng)計(jì)在分詞表中出現(xiàn)次數(shù)排名前500的詞的列表燃领,并將結(jié)果輸出到文件most.txt中士聪,每行一個(gè)詞,格式為:
# 詞,出現(xiàn)次數(shù),詞性
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]]))
第一次運(yùn)行上述代碼猛蔽,生成的most.txt文件有500行剥悟,前10行內(nèi)容如下:
一個(gè),3057,m
沒有,2128,v
他們,1690,r
我們,1550,r
程心,1451,n
這個(gè),1357,r
自己,1347,r
現(xiàn)在,1273,t
已經(jīng),1259,d
羅輯,1256,n
可以看到詞頻排名前四的都是些沒意義的詞,而第5個(gè)'程心'才是三體中有實(shí)際意義的詞(程圣母果然厲害)曼库。等等区岗,這是因?yàn)槲覀儧]有將前四名這些詞的詞性添加到stop_attr列表中,導(dǎo)致它們并沒有被過濾掉凉泄,那我們現(xiàn)在就把這前4個(gè)詞的詞性添加到stop_attr列表中躏尉,stop_attr列表變成:['m','v','r']
,再次運(yùn)行腳本后众,most.txt的內(nèi)容(前10個(gè)詞)變?yōu)榱耍?/p>
程心,1451,n
現(xiàn)在,1273,t
已經(jīng),1259,d
羅輯,1256,n
世界,1243,n
地球,951,n
人類,935,n
太空,930,n
三體,879,n
宇宙,875,n
可以看到胀糜,我們成功清洗掉了剛剛前四名的無(wú)意義的詞,'程心'成功變?yōu)樵~頻最高的詞蒂誉。但是第2教藻、3名的'現(xiàn)在'、'已經(jīng)'等詞顯然也是我們不需要的右锨,那么就重復(fù)上面的過程括堤,把這些不需要的詞性添加到stop_attr列表中,再看結(jié)果绍移。然后繼續(xù)重復(fù)以上過程悄窃,重復(fù)N次之后,我得到的stop_attr變成了:['a','ad','b','c','d','f','df','m','mq','p','r','rr','s','t','u','v','z']
蹂窖,長(zhǎng)長(zhǎng)的一串轧抗。而most.txt的內(nèi)容變?yōu)榱?前20行):
程心,1451,n
羅輯,1256,n
世界,1243,n
地球,951,n
人類,935,n
太空,930,n
三體,879,n
宇宙,875,n
太陽(yáng),775,ns
艦隊(duì),649,n
飛船,644,n
汪淼,633,nrfg
時(shí)間,611,n
文明,561,nr
東西,515,ns
信息,480,n
感覺,468,n
智子,452,n
計(jì)劃,451,n
葉文潔,446,nr
太陽(yáng)系,428,n
世界一下子明朗了,可以看出分詞結(jié)果已經(jīng)被清洗的很干凈了瞬测,也可以發(fā)現(xiàn)我們需要的有實(shí)際意義的詞絕大多數(shù)都為名詞(n或n開頭的)横媚。
TopN詞匯輸出
接下來(lái)我們把文本中的TopN詞匯及詞頻輸出到result.txt中纠炮,每一行一個(gè)詞,格式為:詞,詞頻
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行內(nèi)容如下:
程心,1451
羅輯,1256
世界,1243
地球,951
人類,935
太空,930
三體,879
宇宙,875
太陽(yáng),775
艦隊(duì),649
完整代碼封裝
將上述每一步的代碼封裝成一個(gè)完整的腳本灯蝴,如下:
# coding:utf-8
import jieba.posseg as psg
from collections import Counter
import sys
# 對(duì)文本分詞并標(biāo)注詞性恢口,并緩存到文件
def cut_and_cache(text):
# 將三體全集文本分詞,并附帶上詞性穷躁,因?yàn)閿?shù)據(jù)量比較大耕肩,防止每次運(yùn)行腳本都花大量時(shí)間,所以第一次分詞后就將結(jié)果存入文件cut_result.txt中
# 相當(dāng)于做一個(gè)緩存折砸,格式為每個(gè)詞占一行看疗,每一行的內(nèi)容為:
# 詞,詞性
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中讀取帶詞性的分詞結(jié)果列表
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
# 將分詞列表的詞性構(gòu)建成一個(gè)字典,以便后面使用睦授,格式為:
# {詞:詞性}
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
# 統(tǒng)計(jì)在分詞表中出現(xiàn)次數(shù)排名前500的詞的列表两芳,并將結(jié)果輸出到文件result.txt中,每行一個(gè)詞去枷,格式為:
# 詞,出現(xiàn)次數(shù)
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():
# 設(shè)置環(huán)境為utf-8編碼格式怖辆,防止處理中文出錯(cuò)
reload(sys)
sys.setdefaultencoding('utf-8')
# 讀取三體全集文本
santi_text = open('./santi.txt').read()
# 分詞并緩存,只需運(yùn)行一次删顶,后續(xù)可注釋掉
cut_and_cache(santi_text)
# 從cut_result.txt中讀取帶詞性的分詞結(jié)果列表
santi_words_with_attr = read_cut_result()
# 構(gòu)建詞性字典竖螃,這個(gè)字典在探索stop_attr的時(shí)候會(huì)有幫助
# 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()