歡迎光臨
每天分享高質量文章

Python自然語言處理分析倚天屠龍記

音樂資源載入中…

轉載自:Python中文社群     ID:python-china


最近在瞭解到,在機器學習中,自然語言處理是較大的一個分支。存在許多挑戰。例如: 如何分詞,識別物體關係,物體間關係,關係網路展示等。

我用Jieba + Word2vec + NetworkX 結合在一起,做了一次自然語言分析。語料是 倚天屠龍記。 之前也有很多人用金庸的武俠小說做分析和處理,希望帶來一些不同的地方。截幾張圖來看看:

所有人物的相似圖連線。

關係同上。展示形式為多中心結構

以張無忌的不同身份為中心的網路關係圖。 

這次分析的不一樣之處主要是:

1、Word2Vec的相似度結果 – 作為後期社交網路權重

2、NetworkX中分析和展示

上面兩個方法結合起來,可以大幅減少日常工作中閱讀文章的時間。 採用機器學習,可以從頭到尾半自動抽取文章中的物體資訊,節約大量時間和成本。 在各種工作中都有利用的場景, 如果感興趣的朋友,可以聯絡合作。

先來看看,用Word2Vec+NetworkX 可以發現什麼。

一、分析結果

物體的不同屬性(張無忌的總多馬甲)

張無忌,無忌,張教主,無忌哥哥,張公子。同一個張無忌有多個身份,不同身份又和不同的人聯絡,有不一樣的相似度。

先來看看圖:

無忌哥哥是過於親密的名字,一般不喊。好似和這個詞相似度高的都是比較奇怪的角色。

無忌是關係熟了以後,平輩或者長輩可以稱呼的名字。還有周姑娘,殷姑娘等

張無忌是通用的名字,人人可以稱呼 和馬甲聯絡密切。

張公子是禮貌尊稱。 例如,黃衫女子,汝陽王等

張教主是頭銜。既要尊重,也表示其實不太熟,有時還有些敵意。 例如: 朱元璋

註:

1、圖是Networkx 基於Word2vex畫出來了,上面的描述是我的人工分析。 

2、趙敏不在上面的網路關係圖中。Word2Vec計算出來 張無忌和趙敏 相似度不太高。有些出乎我的意料。 仔細回憶一下,當年看此書時,突然就發現二人在一起了,顯得比較突兀。推想起來,書中世界二人成婚了,如果變成現實世界,二人關係比較懸。

二、實現過程

主要步驟:

準備語料

  1. 倚天屠龍記 小說的文字檔案

  2. 自定義分詞詞典 (小說中的人物名,網上有現成的,約180個)

  3. 停用詞表

準備工具

  1. Python Pandas, Numpy,Scipy(標準庫)

  2. Jieba(中文分詞)

  3. Word2vec (單詞向量化工具,可以計算單詞之間的詳細度)

  4. Networks(網路圖工具,用於展示覆雜的網路關係

資料預處理

  1. 文字檔案轉發成utf8(pandas)

  2. 文字檔案分句,分詞(Jieba)

  3. 文字檔案分句,分詞, 分析詞性,主要是人名(Jieba)

  4. 更新自定義詞典,重新分詞(整個過程需要幾遍,直至滿意)

  5. 手工少量刪除(分詞出來的人名誤判率不高,但是還是存在一些。例如:趙敏笑道,可以被識別的 一個叫 趙敏笑的人。 這部分工作還需要手工做。 除非有更好的分詞工具,或者可以訓練的分詞工具,才能解決這一問題。

Word2Vec 訓練模型。這個模型可以計算兩個人之間的相似度

  1. 採用300個維度

  2. 過濾詞頻小於20次

  3. 滑動視窗 為20

  4. 下取樣:0.001

生成物體關係矩陣。

  1. 網上沒找找到現成庫,我就自己寫了一個。

  2. N*N 維度。 N是人名數量。

  3. 用上面WordVec的模型來,填充物體關係矩陣

NetworkX 生成網路圖

  1. 節點是人名

  2. 邊是兩個節點之間的線條。也就是兩個人之間的關係。

三、部分程式碼實現

初始化


  1. import numpy as np



  2. import pandas as pd



  3. import jieba



  4. import jieba.posseg as posseg



  5. %matplotlib inline


資料分詞,清洗


  1. renming_file = "yttlj_renming.csv"



  2. jieba.load_userdict(renming_file)



  3. stop_words_file = "stopwordshagongdakuozhan.txt"



  4. stop_words = pd.read_csv(stop_words_file,essay-header=None,quoting=3,sep=" ")[0].values



  5. corpus = "yttlj.txt"



  6. yttlj = pd.read_csv(corpus,encoding="gb18030",essay-header=None,names=["sentence"])







  7. def cut_join(s):



  8.    new_s=list(jieba.cut(s,cut_all=False)) #分詞



  9.    #print(list(new_s))



  10.    stop_words_extra =set([""])







  11.    for seg in new_s:





  12.        if len(seg)==1:



  13.            #print("aa",seg)



  14.            stop_words_extra.add(seg)





  15.    #print(stop_words_extra)



  16.    #print(len(set(stop_words)| stop_words_extra))





  17.    new_s =set(new_s) -set(stop_words)-stop_words_extra



  18.    #過濾標點符號



  19.    #過濾停用詞



  20.    result = ",".join(new_s)





  21.    return  result





  22. def extract_name(s):



  23.    new_s=posseg.cut(s) #取詞性



  24.    words=[]



  25.    flags=[]



  26.    for k,v in new_s:



  27.        if len(k)>1:



  28.            words.append(k)



  29.            flags.append(v)



  30.    full_wf["word"].extend(words)



  31.    full_wf["flag"].extend(flags)



  32.    return len(words)





  33. def check_nshow(x):



  34.    nshow = yttlj["sentence"].str.count(x).sum()



  35.    #print(x, nshow)



  36.    return nshow





  37. # extract name & filter times





  38. full_wf={"word":[],"flag":[]}



  39. possible_name = yttlj["sentence"].apply(extract_name)



  40. #tmp_w,tmp_f





  41. df_wf = pd.DataFrame(full_wf)





  42. df_wf_renming = df_wf[(df_wf.flag=="nr")].drop_duplicates()



  43. df_wf_renming.to_csv("tmp_renming.csv",index=False)





  44. df_wf_renming = pd.read_csv("tmp_renming.csv")



  45. df_wf_renming.head()









  46. df_wf_renming["nshow"] = df_wf_renming.word.apply(check_nshow)





  47. df_wf_renming[df_wf_renming.nshow>20].to_csv("tmp_filtered_renming.csv",index=False)





  48. df_wf_renming[df_wf_renming.nshow>20].shape





  49. #手工編輯,刪除少量非人名,分詞錯的人名



  50. df_wf_renming=pd.read_csv("tmp_filtered_renming.csv")



  51. my_renming = df_wf_renming.word.tolist()







  52. external_renming = pd.read_csv(renming_file,essay-header=None)[0].tolist()







  53. combined_renming = set(my_renming) |set(external_renming)



  54. pd.DataFrame(list(combined_renming)).to_csv("combined_renming.csv",essay-header=None,index=False)







  55. combined_renming_file ="combined_renming.csv"



  56. jieba.load_userdict(combined_renming_file)







  57. # tokening





  58. yttlj["token"]=yttlj["sentence"].apply(cut_join)





  59. yttlj["token"].to_csv("tmp_yttlj.csv",essay-header=False,index=False)



  60. sentences = yttlj["token"].str.split(",").tolist()


Word2Vec 向量化訓練


  1. # Set values for various parameters



  2. num_features = 300    # Word vector dimensionality                      



  3. min_word_count = 20   # Minimum word count                        



  4. num_workers = 4       # Number of threads to run in parallel



  5. context = 20          # Context window size                                                                                    



  6. downsampling = 1e-3   # Downsample setting for frequent words





  7. # Initialize and train the model (this will take some time)





  8. from gensim.models import word2vec





  9. model_file_name = 'yttlj_model.txt'



  10. #sentences = w2v.LineSentence('cut_jttlj.csv')







  11. model = word2vec.Word2Vec(sentences, workers=num_workers,



  12.            size=num_features, min_count = min_word_count,



  13.            window = context,



  14.            sample = downsampling



  15.            )









  16. model.save(model_file_name)  


建立物體關係矩陣


  1. entity = pd.read_csv(combined_renming_file,essay-header=None,index_col=None)



  2. entity = entity.rename(columns={0:"Name"})



  3. entity = entity.set_index(["Name"],drop=False)





  4. ER = pd.DataFrame(np.zeros((entity.shape[0],entity.shape[0]),dtype=np.float32),index=entity["Name"],columns=entity["Name"])



  5. ER["tmp"] = entity.Name





  6. def check_nshow(x):



  7.    nshow = yttlj["sentence"].str.count(x).sum()



  8.    #print(x, nshow)



  9.    return nshow





  10. ER["nshow"]=ER["tmp"].apply(check_nshow)



  11. ER = ER.drop(["tmp"],axis=1)





  12. count = 0



  13. for i in entity["Name"].tolist():



  14.    count +=1



  15.    if count % round(entity.shape[0]/10) ==0:



  16.        print("{0:.1f}% relationship has been checked".format(100*count/entity.shape[0]))



  17.    elif count == entity.shape[0]:



  18.        print("{0:.1f}% relationship has been checked".format(100*count/entity.shape[0]))





  19.    for j in entity["Name"]:



  20.        relation =0



  21.        try:



  22.            relation = model.wv.similarity(i,j)



  23.            ER.loc[i,j] = relation



  24.            if i!=j:



  25.                ER.loc[j,i] = relation



  26.        except:



  27.            relation = 0









  28. ER.to_hdf("ER.h5","ER")


NetworkX 展示人物關係圖


  1. import networkx as nx



  2. import matplotlib.pyplot as plt



  3. import pandas as pd



  4. import numpy as np



  5. import pygraphviz



  6. from networkx.drawing.nx_agraph import graphviz_layout


本文作者

王勇,python中文社群作者,雪球ID:快樂_爸,目前感興趣專案商業分析、Python、機器學習、Kaggle。17年專案管理,通訊業幹了11年專案經理管合同交付,製造業幹了6年專案管理:PMO,變革,生產轉移,清算和資產處理。MBA, PMI-PBA, PMP。


《Python人工智慧和全棧開發》2018年07月23日即將在北京開課,120天衝擊Python年薪30萬,改變速約~~~~

*宣告:推送內容及圖片來源於網路,部分內容會有所改動,版權歸原作者所有,如來源資訊有誤或侵犯權益,請聯絡我們刪除或授權事宜。


- END -


更多Python好文請點選【閱讀原文】哦

↓↓↓

贊(0)

分享創造快樂

© 2022 知識星球   網站地圖