準備考試?python也能幫你劃重點
- 2019 年 10 月 8 日
- 筆記
個人部落格地址:https://blog.csdn.net/blmoistawinde。
本文首發於:https://blog.csdn.net/blmoistawinde
準備工作
程式:「首先引入一些必要的庫,然後我載入doc為1840—1919年中國大事的那一段段文本做個簡單的示例,這部分程式碼就不用我列出來了吧。」
旁白:這裡使用harvesttext庫進行文本挖掘,它的許多功能能夠使得文本分析的流程變得更加輕鬆。前面的用python分析《三國演義》中的社交網路一文也使用了這一工具。
ht = HarvestText() sentences = ht.cut_sentences(doc)
有哪些重要對象
「重要對象,一般都是一些專有名詞。我可以利用自然語言處理中的命名實體識別技術就能夠識別出這樣的一些對象,比如:人名、地名、機構名還有其他專有名詞等。」

HarvestText中包裝精簡了pyhanlp中的命名實體識別介面,讓我們來使用它找到近代史中的重要對象吧。
entity_type_dict = {} for i, sent in enumerate(sentences): entity_type_dict0 = ht.named_entity_recognition(sent) for entity0, type0 in entity_type_dict0.items(): entity_type_dict[entity0] = type0 for entity in list(entity_type_dict.keys())[:10]: print(entity, entity_type_dict[entity]) 中國 地名 鴉片戰爭 其他專名 五四運動 其他專名 英國 地名 南京 地名 望廈 其他專名 黃埔 地名 不平等條約 其他專名 洪秀全 人名 金田 地名
把找到的實體登錄,我們就可以統計他們出現的次數,通過詞頻來判斷它們的重要性。
ht.add_entities(entity_type_dict = entity_type_dict) inv_index = ht.build_index(sentences) counts = ht.get_entity_counts(sentences,inv_index) print(pd.Series(counts).sort_values(ascending=False).head()) 中國 21 清政府 6 日本 5 孫中山 4 英國 3 dtype: int64
我:「這個分析確實有用,看著這些詞我就聯想到了,在1840—1919年的中國,清政府面對外敵的屈辱,以及孫中山先生為代表的有識之士的努力。但是考試不是單考這些對象,關鍵要考和它們有關的知識點啊。」
程式:「別著急,對於知識點,我也有辦法找到。」
有哪些重要知識點
程式:「你們說的重要知識點,可以認為是包含了那些重要對象的事件或者事實吧。對於你們人類,事實可能就是自然語言描述的一句話。不過對於我們程式,我們要用一種標準清晰的結構來表示它。三元組組成的知識圖譜就是一種解決方案。」
三元組就是類似(主語,謂詞,賓語)的結構,比如:
[『清政府』, 『簽訂』, 『天津條約』]
[『袁世凱』, 『復辟』, 『帝制』]
[『孫中山』, 『就任』, 『臨時大總統』]
我:「有點意思,三個詞基本就能凝練地表達一句話中的主要事實了。但是你只有文本作為輸入,你要怎麼從中提取出這樣的三元組呢?」
程式:「上面已經提到三元組有(主語,謂詞,賓語)的結構。你要是英語/語文課學得好的話,應該會聯想到主語、謂語、賓語這些語法概念吧?而我就可以使用依存句法分析技術從文本中獲得這些句法資訊。」
分析大致是這樣的:

可以看到,從主謂關係和動賓關係,我們就能夠自然地得到我們需要的三元組[『袁世凱』, 『復辟』, 『帝制』]。
保留更多的資訊,比如修飾主語的形容詞,能夠讓三元組的意思更加完整。我們可以利用別的關係來擴充事實:

原來我們只會得到[『孫中山』, 『就任』, 『大總統』]。現在利用定中關係,我們就知道「臨時」一詞修飾「大總統」,我們就能夠得到[『孫中山』, 『就任』, 『臨時大總統』]這個更完整的事實了。
我:「emmm…我的英語學得不好,這些語法看得有點頭暈。」
程式:「好吧 (¬_¬),不過把它包裝成介面以後,我們就可以很簡單地使用這個技術了。現在讓我們用它來找到課本里的重要知識點:」
ht2 = HarvestText() SVOs = [] for i, sent in enumerate(sentences): SVOs += ht2.triple_extraction(sent.strip()) print("n".join(" ".join(tri) for tri in SVOs[5:10])) 英法聯軍 發動 侵略中國 清政府 簽訂 天津條約 清政府 簽訂 北京條約 慈禧太后 掌握 清王朝政權 這是中國半殖民地半封建社會 形成 中國資本主義產生時期
程式:「怎麼樣?要不考慮下次考試讓我幫你劃重點?」
我:「有的三元組看起來還挺不錯的,但是有的感覺有點奇怪啊。」
程式:「不要在意這些細節……那是因為你們給我寫的演算法還有很多提升空間嗎,但總體品質還是不錯的。」
「有了這些結構化的知識,我就可以接著建立知識圖譜,『掌握』這些知識之間的聯繫。」
知識圖譜長什麼樣呢?它可以理解為實體之間的網路,網路之間的連邊就是實體之間的聯繫,做出一張圖來直觀地感受下:
fig = plt.figure(figsize=(12,8),dpi=100) g_nx = nx.DiGraph() labels = {} for subj, pred, obj in SVOs: g_nx.add_edge(subj,obj) labels[(subj,obj)] = pred pos=nx.spring_layout(g_nx) nx.draw_networkx_nodes(g_nx, pos, node_size=300) nx.draw_networkx_edges(g_nx,pos,width=4) nx.draw_networkx_labels(g_nx,pos,font_size=10,font_family='sans-serif') nx.draw_networkx_edge_labels(g_nx, pos, labels , font_size=10, font_family='sans-serif') plt.axis("off") plt.show()

現在,上考場吧
「現在我學會了這些知識,就可以建立起問答系統,回答一些問題。出幾個問題來考考我吧?」
問答系統的具體實現思路可以見我的另一篇部落格:https://blog.csdn.net/blmoistawinde/article/details/86556844
QA = NaiveKGQA(SVOs, entity_type_dict=entity_type_dict) questions = ["孫中山幹了什麼事?","清政府簽訂了哪些條約?","誰復辟了帝制?"] for question0 in questions: print("問:"+question0) print("答:"+QA.answer(question0)) 問:孫中山幹了什麼事? 答:讓位於袁世凱、發動護法運動、就任臨時大總統 問:清政府簽訂了哪些條約? 答:天津條約、北京條約 問:誰復辟了帝制? 答:袁世凱
回答得相當不錯。儘管當下這些問題是我特地挑選出來的,確定知識庫里有正確的答案。不過當技術發展完善,或許有一天,它真的能夠走上考場,取得不錯的成績呢。
本文故事純屬虛構,近綱考砸卻是真事。不過我會感謝這門課教給我的歷史教訓,還有帶給我的本文寫作靈感 ?