J'ai toujours été intéressé par le traitement du langage naturel et l'analyse des réseaux sociaux. Le premier peut nous aider à faire de nombreuses découvertes à partir du texte, tandis que le second nous permet de comprendre les relations communes entre les personnes et les choses. Les connexions de type réseau conduisent à une plus grande prise de conscience. Lorsque les deux seront combinés, quel genre de magie y aura-t-il ? En tant que fan des Trois Royaumes, j'ai eu cette idée : puis-je utiliser des méthodes de traitement de texte pour obtenir le réseau social des personnages de « La Romance des Trois Royaumes » et ensuite l'analyser ? Il existe de nombreux bons outils en python qui peuvent m'aider à mettre en œuvre mes idées curieuses, commençons maintenant.
Préparation
Récupérez le texte de "Le Roman des Trois Royaumes" .
chapters = get_sanguo() # 文本列表,每个元素为一章的文本print(chapters[0][:106])第一回 宴桃园豪杰三结义 斩黄巾英雄首立功滚滚长江东逝水,浪花淘尽英雄。是非成败转头空。青山依旧在,几度夕阳红。白发渔樵江渚上,惯看秋月春风。一壶浊酒喜相逢。古今多少事,都付笑谈中
"Le Roman des Trois Royaumes" n'est pas un texte facile à traiter. Il est proche des textes anciens, et nous serons confrontés à une série d'alias tels que la taille des polices des anciens. . Par exemple, comment l'ordinateur sait-il que « Xuande » fait référence à « Liu Bei » ? Ensuite, nous devons lui donner quelques connaissances. Nous, les humains, savons grâce à l'étude que "Xuande" est le personnage de Liu Bei, et les ordinateurs peuvent également utiliser une méthode similaire pour compléter la connexion de ce concept. Nous devons dire à l'ordinateur que "Liu Bei" est une entité (similaire au nom standard d'un objet), et "Xuande" est une référence à "Liu Bei". La façon de le savoir est de fournir à l'ordinateur un. base de connaissances.
entity_mention_dict, entity_type_dict = get_sanguo_entity_dict() print("刘备的指称有:",entity_mention_dict["刘备"] 刘备的指称有: [ 刘备 , 刘玄德 , 玄德 , 使君 ]
En plus des entités et références humaines, nous pouvons également inclure d'autres types de références telles que les forces des Trois Royaumes. Par exemple, "Shu" peut aussi être appelé "Shuhan". , de sorte que la base de connaissances peut également inclure des informations sur le type d'entité pour les distinguer.
print("刘备的类型为",entity_type_dict["刘备"]) print("蜀的类型为",entity_type_dict["蜀"]) print("蜀的指称有",entity_mention_dict["蜀"]) 刘备的类型为 人名 蜀的类型为 势力 蜀的指称有 [ 蜀 , 蜀汉 ]
Grâce à ces connaissances, nous pouvons en théorie connecter par programme les différents surnoms d'entités. Mais si vous devez repartir de zéro, cela impliquera encore beaucoup de travail. HarvestText[1] est une bibliothèque de traitement de texte qui encapsule ces étapes et peut nous aider à accomplir cette tâche facilement.
ht = HarvestText()ht.add_entities(entity_mention_dict, entity_type_dict) # 加载模型print(ht.seg("誓毕,拜玄德为兄,关羽次之,张飞为弟。",standard_name=True))[ 誓毕 , , , 拜 , 刘备 , 为兄 , , , 关羽 , 次之 , , , 张飞 , 为弟 , 。 ]
Établissement des réseaux sociaux
Après avoir réussi à unifier les références en noms d'entités standards, nous pouvons commencer à explorer les réseaux sociaux des Trois Royaumes. La manière spécifique de l’établir est d’utiliser des relations de cooccurrence voisines. Chaque fois qu'une paire d'entités apparaît ensemble dans deux phrases, ajoutez-leur un avantage. Ensuite, l'ensemble du processus d'établissement d'un réseau est illustré dans la figure ci-dessous :
Nous pouvons utiliser la fonction fournie par HarvestText pour terminer directement ce processus. le petit texte du chapitre 1 Pratiquons-le :
# 准备工作 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))
Quelle est la relation spécifique entre eux ? Nous pouvons utiliser le résumé du texte pour obtenir le contenu spécifique de ce chapitre :
stopwords = get_baidu_stopwords() #过滤停用词以提高质量for i,doc in enumerate(ht.get_summary(doc_ch01, topK=3, stopwords=stopwords)): print(i,doc)玄德见皇甫嵩、朱儁,具道卢植之意。嵩曰:“张梁、张宝势穷力乏,必投广宗去依张角。时张角贼众十五万,植兵五万,相拒于广宗,未见胜负。植谓玄德曰:“我今围贼在此,贼弟张梁、张宝在颍川,与皇甫嵩、朱儁对垒。次日,于桃园中,备下乌牛白马祭礼等项,三人焚香再拜而说誓曰:“念刘备、关羽、张飞,虽然异姓,既结为兄弟,则同心协力,
Le contenu principal de ce chapitre semble être l'histoire de Liu, Guan et Zhang Taoyuan devenant frères jurés et luttant contre le Voleurs de Turban jaune ensemble.
Dessin en réseau complet des Trois Royaumes
Avec la base d'une pratique à petite échelle, nous pouvons utiliser la même méthode pour intégrer le contenu de chaque chapitre et dessiner Une vue d'ensemble couvrant toutes les générations des Trois Royaumes.
G_chapters = []
L'ensemble du réseau social compte jusqu'à 1 290 personnes et des dizaines de milliers de bords ! Il nous est alors presque impossible de le dessiner, alors sélectionnons parmi eux les chiffres clés et dessinons un sous-ensemble.
important_nodes = [node for node in G_global.nodes if G_global.degree[node]>=30]
Visualisation à l'aide de pyecharts
from pyecharts import Graph
Les graphiques interactifs ne peuvent pas être affichés sur le blog, voici une capture d'écran : les nœuds adjacents de Liu Bei sont affichés
L'ensemble du réseau est complexe, et derrière lui se cachent d'innombrables conquêtes et intrigues dans l'histoire des Trois Royaumes. Cependant, grâce à la puissante puissance de calcul des ordinateurs, nous pouvons encore trier certains indices clés, tels que :
Classement des personnages-Importance
Pour cette question, nous peut être résolu en utilisant l'algorithme de tri dans le réseau. Le PageRank est une méthode typique. Il s'agit à l'origine d'une méthode permettant aux moteurs de recherche d'utiliser les connexions entre les sites Web pour classer les résultats de recherche, mais il en va de même pour les connexions entre les personnes. Voyons le top 20 des plus importants :
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视频教程】
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!