私は自然言語処理とソーシャル ネットワーク分析にずっと興味がありました。前者はテキストから多くの発見を得るのに役立ち、後者は人と物の間に共通する関係を理解するのに役立ちます。 . ネットワークのようなつながりが気づきの拡大につながります。二つが合わさるとどんな魔法が生まれるのでしょうか?三国志ファンとして、テキスト処理手法を用いて『三国志』の登場人物のソーシャルネットワークを取得し、分析できないか、と考えました。 Python には、私の好奇心旺盛なアイデアを実装するのに役立つ優れたツールがたくさんあります。今すぐ始めましょう。
準備
『三国志』のテキストを入手します。
chapters = get_sanguo() # 文本列表,每个元素为一章的文本print(chapters[0][:106])第一回 宴桃园豪杰三结义 斩黄巾英雄首立功滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。白发渔樵江渚上,惯看秋月春风。一壶浊酒喜相逢。古今多少事,都付笑谈中
『三国志』は、古文書に近く、古文書のフォントサイズなど、さまざまな別名に直面することになるので、扱うのは簡単なテキストではありません。 。たとえば、コンピューターは「玄徳」が「劉備」を指すことをどのようにして知るのでしょうか?次に、それにある程度の知識を与える必要があります。私たち人間は、「玄徳」が劉備のキャラクターであることを研究を通じて知っており、コンピューターも同様の方法を使用してこの概念の接続を完了することができます。 「劉備」が実体 (オブジェクトの標準名に似ています) であり、「宣徳」が「劉備」への参照であることをコンピュータに伝える必要があります。それを伝える方法は、コンピュータに知識ベース。
entity_mention_dict, entity_type_dict = get_sanguo_entity_dict() print("刘备的指称有:",entity_mention_dict["刘备"] 刘备的指称有: [ 刘备 , 刘玄德 , 玄德 , 使君 ]
人間の実体や参照に加えて、三国の勢力などの他の種類の参照も含めることができます。たとえば、「蜀」は「蜀漢」とも呼ばれます。ナレッジ ベースには、区別するためのエンティティ タイプ情報も含めることができます。
print("刘备的类型为",entity_type_dict["刘备"]) print("蜀的类型为",entity_type_dict["蜀"]) print("蜀的指称有",entity_mention_dict["蜀"]) 刘备的类型为 人名 蜀的类型为 势力 蜀的指称有 [ 蜀 , 蜀汉 ]
この知識があれば、理論上はエンティティのさまざまなニックネームをプログラムで結び付けることができます。しかし、ゼロから始めなければならない場合は、依然として多くの作業が必要になります。 HarvestText[1] は、これらの手順をカプセル化したテキスト処理ライブラリであり、このタスクを簡単に完了するのに役立ちます。
ht = HarvestText()ht.add_entities(entity_mention_dict, entity_type_dict) # 加载模型print(ht.seg("誓毕,拜玄德为兄,关羽次之,张飞为弟。",standard_name=True))[ 誓毕 , , , 拜 , 刘备 , 为兄 , , , 关羽 , 次之 , , , 张飞 , 为弟 , 。 ]
ソーシャル ネットワークの確立
参照を標準エンティティ名に統合することに成功したら、三国志のソーシャル ネットワークの探索を開始できます。これを確立する具体的な方法は、隣接する共起関係を使用することです。 2 つの文の中で 1 対のエンティティが一緒に登場する場合は常に、それらにエッジを追加します。ネットワークを確立するプロセス全体は、次の図に示すようになります:
HarvestText が提供する関数を使用して、このプロセスを直接完了できます。第 1 章の小さなテキスト 練習してみましょう:
# 准备工作 doc = chapters[0].replace("操","曹操") # 由于有时使用缩写,这里做一个微调 ch1_sentences = ht.cut_sentences(doc) # 分句 doc_ch01 = [ch1_sentences[i]+ch1_sentences[i+1] for i in range(len(ch1_sentences)-1)] #获得所有的二连句 ht.set_linking_strategy("freq") # 建立网络 G = ht.build_entity_graph(doc_ch01, used_types=["人名"]) # 对所有人物建立网络,即社交网络 # 挑选主要人物画图 important_nodes = [node for node in G.nodes if G.degree[node]>=5] G_sub = G.subgraph(important_nodes).copy() draw_graph(G_sub,alpha=0.5,node_scale=30,figsize=(6,4))
それらの間の具体的な関係は何ですか?この章の具体的な内容を取得するには、テキストの概要を使用できます。
stopwords = get_baidu_stopwords() #过滤停用词以提高质量for i,doc in enumerate(ht.get_summary(doc_ch01, topK=3, stopwords=stopwords)): print(i,doc)玄德见皇甫嵩、朱儁,具道卢植之意。嵩曰:“张梁、张宝势穷力乏,必投广宗去依张角。时张角贼众十五万,植兵五万,相拒于广宗,未见胜负。植谓玄德曰:“我今围贼在此,贼弟张梁、张宝在颍川,与皇甫嵩、朱儁对垒。次日,于桃园中,备下乌牛白马祭礼等项,三人焚香再拜而说誓曰:“念刘备、关羽、张飞,虽然异姓,既结为兄弟,则同心协力,
この章の主な内容は、劉、関、張桃源が義兄弟となり、黄巾賊と戦う物語のようです。一緒に泥棒。
三国志完全ネットワーク描画
小規模な実践を基礎として、同じ方法で各章の内容を統合して描画することができます。三国志の全世代にわたる大きな絵。
G_chapters = []
ソーシャル ネットワーク全体には 1,290 人ものユーザーと数万のエッジがあります。それでは描くのはほぼ不可能なので、その中からキーとなる人物を選択してサブセットを描いてみましょう。
#
important_nodes = [node for node in G_global.nodes if G_global.degree[node]>=30]
from pyecharts import Graph
#ネットワーク全体は複雑で、その背後には三国志の物語における無数の征服と陰謀があります。ただし、コンピューターの強力な計算能力を使用すると、次のような重要な手がかりを分類することができます。
キャラクター ランキング - 重要度この質問については、ネットワーク内のソートアルゴリズムを使用して解決できます。 PageRank はその代表的な手法で、本来は検索エンジンが Web サイト間のつながりを利用して検索結果を順位付けする手法ですが、人と人のつながりについても同様です。最も重要なトップ 20 を見てみましょう:
page_ranks = pd.Series(nx.algorithms.pagerank(G_global)).sort_values() page_ranks.tail(20).plot(kind="barh") plt.show()
结果的确和上面的排序有所不同,我们看到刘备、曹操、孙权、袁绍等主公都名列前茅。而另一个有趣的发现是,司马懿、司马昭、司马师父子三人同样榜上有名,而曹氏的其他后裔则不见其名,可见司马氏之权倾朝野。司马氏之心,似乎就这样被大数据揭示了出来!
社群发现
人物关系有亲疏远近,因此往往会形成一些集团。社交网络分析里的社区发现算法就能够让我们发现这些集团,让我使用community库[2]中的提供的算法来揭示这些关系吧。
import community # python-louvainpartition = community.best_partition(G_main) # Louvain算法划分社区comm_dict = defaultdict(list)for person in partition: comm_dict[partition[person]].append(person)
在下面3个社区里,我们看到的主要是魏蜀吴三国重臣们。(只有一些小“问题”,有趣的是,电脑并不知道他们的所属势力,只是使用算法。)
draw_community(2) ommunity 2: 张辽 曹仁 夏侯惇 徐晃 曹洪 夏侯渊 张郃 许褚 乐进 李典 于禁 荀彧 刘晔 郭嘉 满宠 程昱 荀攸 吕虔 典韦 文聘 董昭 毛玠
draw_community(4) community 4: 曹操 诸葛亮 刘备 关羽 赵云 张飞 马超 黄忠 许昌 孟达[魏] 孙乾 曹安民 刘璋 关平 庞德 法正 伊籍 张鲁 刘封 庞统 孟获 严颜 马良 简雍 蔡瑁 陶谦 孔融 刘琮[刘表子] 刘望之 夏侯楙 周仓 陈登
draw_community(3) community 3: 孙权 孙策 周瑜 陆逊 吕蒙 丁奉 周泰 程普 韩当 徐盛 张昭[吴] 马相 黄盖[吴] 潘璋 甘宁 鲁肃 凌统 太史慈 诸葛瑾 韩吴郡 蒋钦 黄祖 阚泽 朱桓 陈武 吕范
draw_community(0) community 0: 袁绍 吕布 刘表 袁术 董卓 李傕 贾诩 审配 孙坚 郭汜 陈宫 马腾 袁尚 韩遂 公孙瓒 高顺 许攸[袁绍] 臧霸 沮授 郭图 颜良 杨奉 张绣 袁谭 董承 文丑 何进 张邈[魏] 袁熙
还有一些其他社区。比如在这里,我们看到三国前期,孙坚、袁绍、董卓等主公们群雄逐鹿,好不热闹。
draw_community(1) community 1: 司马懿 魏延 姜维 张翼 马岱 廖化 吴懿 司马昭 关兴 吴班 王平 邓芝 邓艾 张苞[蜀] 马忠[吴] 费祎 谯周 马谡 曹真 曹丕 李恢 黄权 钟会 蒋琬 司马师 刘巴[蜀] 张嶷 杨洪 许靖 费诗 李严 郭淮 曹休 樊建 秦宓 夏侯霸 杨仪 高翔 张南[魏] 华歆 曹爽 郤正 许允[魏] 王朗[司徒] 董厥 杜琼 霍峻 胡济 贾充 彭羕 吴兰 诸葛诞 雷铜 孙綝 卓膺 费观 杜义 阎晏 盛勃 刘敏 刘琰 杜祺 上官雝 丁咸 爨习 樊岐 曹芳 周群
这个社区是三国后期的主要人物了。这个网络背后的故事,是司马氏两代三人打败姜维率领的蜀汉群雄,又扫除了曹魏内部的曹家势力,终于登上权力的顶峰。
动态网络
研究社交网络随时间的变化,是个很有意思的任务。而《三国演义》大致按照时间线叙述,且有着极长的时间跨度,顺着故事线往下走,社交网络会发生什么样的变化呢?
这里,我取10章的文本作为跨度,每5章记录一次当前跨度中的社交网络,就相当于留下一张快照,把这些快照连接起来,我们就能够看到一个社交网络变化的动画。快照还是用networkx得到,而制作动画,我们可以用moviepy。
江山代有才人出,让我们看看在故事发展的各个阶段,都是哪一群人活跃在舞台中央呢?
import moviepy.editor as mpy from moviepy.video.io.bindings import mplfig_to_npimage width, step = 10,5 range0 = range(0,len(G_chapters)-width+1,step) numFrame, fps = len(range0), 1 duration = numFrame/fps pos_global = nx.spring_layout(G_main) def make_frame_mpl(t): i = step*int(t*fps) G_part = nx.Graph() for G0 in G_chapters[i:i+width]: for (u,v) in G0.edges: if G_part.has_edge(u,v): G_part[u][v]["weight"] += G0[u][v]["weight"] else: G_part.add_edge(u,v,weight=G0[u][v]["weight"]) largest_comp = max(nx.connected_components(G_part), key=len) used_nodes = set(largest_comp) & set(G_main.nodes) G = G_part.subgraph(used_nodes) fig = plt.figure(figsize=(12,8),dpi=100) nx.draw_networkx_nodes(G,pos_global,node_size=[G.degree[x]*10 for x in G.nodes]) # nx.draw_networkx_edges(G,pos_global) nx.draw_networkx_labels(G,pos_global) plt.xlim([-1,1]) plt.ylim([-1,1]) plt.axis("off") plt.title(f"第{i+1}到第{i+width+1}章的社交网络") return mplfig_to_npimage(fig) animation = mpy.VideoClip(make_frame_mpl, duration=duration) animation.write_gif("./images/三国社交网络变化.gif", fps=fps)
美观起见,动画中省略了网络中的边。
随着时间的变化,曾经站在历史舞台中央的人们也渐渐地会渐渐离开,让人不禁唏嘘感叹。正如《三国演义》开篇所言:
古今多少事,都付笑谈中。
今日,小辈利用python做的一番笑谈也就到此结束吧……
【推荐课程:Python视频教程】
以上が楽しい楽しい - Python を使用して「三国志」のソーシャル ネットワークを分析するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。