《神秘网络》
原文towardsdatascience.com/the-arcane-network-95d3f19749be?sourcecollection_archive---------3-----------------------#2024-12-02https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/4302fc9ae4ee9be837e375bae43e5b52.png如何使用网络科学和 Python 绘制出这部流行剧集https://medium.com/janosovm?sourcepost_page---byline--95d3f19749be--------------------------------https://towardsdatascience.com/?sourcepost_page---byline--95d3f19749be-------------------------------- Milan Janosov·发布于面向数据科学 ·阅读时长 7 分钟·2024 年 12 月 2 日–《神秘之境》第二季是 Netflix 最近的一部热门剧集改编自全球最受欢迎的在线电子游戏之一《英雄联盟》的宇宙。剧集设定在一个重蒸汽朋克风格的幻想世界中以惊人的视觉效果和创纪录的预算收尾。作为一名网络和数据科学家特别热衷于将流行文化项目转化为数据可视化这就是我在完成最后一季后所需要的一切目的是绘制出隐藏的联系并将《神秘之境》的故事情节转化为网络可视化——使用 Python。因此在本教程结束时您将掌握如何创建并可视化《神秘之境》背后的网络。然而这些技能和方法绝不是这部故事所特有的。事实上它们突出了网络科学提供的一般方法用于绘制、设计、可视化和解释任何复杂系统的网络。这些系统可以从交通和 COVID-19 传播的网络模式到大脑网络再到各种社交网络例如《神秘之境》系列中的网络。所有图像由作者创作。1. 收集角色列表由于我们在这里要绘制出所有角色背后的联系首先我们需要获取每个角色的列表。为此《神秘之境》粉丝维基网站是一个很好的免费使用信息来源CC BY-SA 3.0我们可以通过简单的网页抓取技术轻松访问。具体来说我们将使用 urllib 进行下载使用 BeautifulSoup 提取每个角色在主角页面上列出的名字和粉丝维基个人资料链接。首先下载角色列表网站的 HTMLimporturllibimportbs4asbsfromurllib.requestimporturlopen url_charhttps://arcane.fandom.com/wiki/Category:Characterssauceurlopen(url_char).read()soupbs.BeautifulSoup(sauce,lxml)然后我提取了所有潜在相关的名字。通过右键点击一个想要的元素在这个案例中是角色档案并选择浏览器中的元素检查选项您可以轻松找出要传递给解析的 html存储在‘soup’变量中的标签。从中我了解到角色的名字和网址存储在包含‘title’的行中但不包含‘:’对应于类别。此外我创建了一个still_character标志它帮助我确定角色列表页面上的哪些子页面仍属于故事中的合法角色。importre charssoup.find_all(li)still_characterTruenames_urls{}forcharinchars:if titleinstr(char)and:notinchar.textandstill_character:char_namechar.text.strip().rstrip()ifchar_nameArcane:still_characterFalsechar_urlhttps://arcane.fandom.comre.search(rhref([^]),str(char)).group(1)ifstill_character:names_urls[char_name]char_url前面的代码块将创建一个字典‘names_urls’它以每个角色的名字和网址作为键值对存储。现在让我们快速查看一下我们得到的内容并打印出名字-网址字典以及它的总长度forname,urlinnames_urls.items():print(name,url)这个代码块的输出样本我们可以测试每个链接——指向每个角色的传记档案https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3ad33d86437ab3146554e91a80d70500.pngprint(len(names_urls))哪个代码单元返回 67 的结果这意味着我们需要处理的命名角色总数。这表示我们已经完成了第一项任务——我们有一个全面的角色列表并且可以轻松访问它们在粉丝维基网站上的完整文本档案。2. 收集档案为了绘制两个角色之间的关系我们需要找出一种方法来量化两个角色之间的关系。为了捕捉这一点我依赖于这两个角色的传记相互提及的频率。在技术层面上为了实现这一点我们需要收集我们刚刚获得链接的完整传记。我们将通过简单的网页抓取技术再次获取这些信息然后将每个网站的源代码分别保存在本地文件中如下所示。# output folder for the profile htmlsimportos folderoutfandom_profilesifnotos.path.exists(folderout):os.makedirs(folderout)# crawl and save the profile htmlsforind,(name,url)inenumerate(names_urls.items()):ifnotos.path.exists(folderout/name.html):foutopen(folderout/name.html,w)fout.write(str(urlopen(url).read()))fout.close()到了本节末我们的文件夹‘fandom_profiles’应包含每个《Arcane》角色的粉丝维基档案——准备好在我们构建《Arcane》网络的过程中进行处理。3. 《Arcane》网络为了建立角色之间的网络我们假设两个角色之间的互动强度由每个角色的档案提到另一个角色的次数来表示。因此网络的节点是角色节点之间通过基于每个角色的维基网站源引用其他角色维基的次数的强度不同的连接链接。构建网络在下面的代码块中我们构建了边列表——包含每个连接的源节点和目标节点角色以及这两个角色之间的权重共同引用频率的连接列表。此外为了有效地进行档案内搜索我创建了一个names_ids它只包含每个角色的特定标识符而不包括其余的网页地址。# extract the name mentions from the html sources# and build the list of edges in a dictionaryedges{}names_ids{n:u.split(/)[-1]forn,uinnames_urls.items()}forfnin[fnforfninos.listdir(folderout)if.htmlinfn]:namefn.split(.html)[0]withopen(folderout/fn)asmyfile:textmyfile.read()soupbs.BeautifulSoup(text,lxml)text .join([str(a)forainsoup.find_all(p)[2:]])soupbs.BeautifulSoup(text,lxml)forn,iinnames_ids.items():wtext.split(Image Gallery)[0].count(/i)ifw0:edge\t.join(sorted([name,n]))ifedgenotinedges:edges[edge]welse:edges[edge]wlen(edges)当这个代码块运行时它应该返回大约 180 条边。接下来我们使用 NetworkX 图分析库将边列表转换为图对象并输出图中的节点和边的数量# create the networkx graph from the dict of edgesimportnetworkxasnx Gnx.Graph()fore,winedges.items():ifw0:e1,e2e.split(\t)G.add_edge(e1,e2,weightw)G.remove_edges_from(nx.selfloop_edges(G))print(Number of nodes: ,G.number_of_nodes())print(Number of edges: ,G.number_of_edges())该代码块的输出https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/0efcd63ba520a218c408ab4c57c3bcac.png该输出告诉我们虽然我们从 67 个角色开始其中 16 个角色最终没有与网络中的任何人建立连接因此构建的图表中节点的数量较小。可视化网络一旦我们拥有网络就可以将其可视化首先让我们使用 Matplotlib 和 NetworkX 内置工具创建一个简单的网络草图可视化。# take a very brief look at the networkimportmatplotlib.pyplotasplt f,axplt.subplots(1,1,figsize(15,15))nx.draw(G,axax,with_labelsTrue)plt.savefig(test.png)该单元的输出图像https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/3b7a5aa717021a4b84c3d48a813ef25d.png虽然该网络已经提供了一些关于节目主要结构和最常见特点的线索但我们可以使用开源网络可视化软件 Gephi 设计出更为详细的可视化。为此我们首先需要将网络导出为 .gexf 图数据文件如下所示。nx.write_gexf(G,arcane_network.gexf)现在关于如何使用 Gephi 可视化此网络的教程https://github.com/OpenDocCN/towardsdatascience-blog-zh-2024/raw/master/docs/img/aae9b3347f0af50a8557d15dbb93153c.pngYouTube 视频教程:www.youtube.com/watch?vutm91FhZalQ附加内容这是一个扩展部分我在视频中提到过。导出包含网络社区指数的节点表后我使用 Pandas 读取该表并为每个社区分配了不同的颜色。我从 ChatGPT 那里得到了这些颜色及其十六进制代码并要求它们与节目主色调对齐。然后这段代码将颜色导出——我再次在 Gephi 中使用它来给最终图形上色。importpandasaspd nodespd.read_csv(nodes.csv)pink#FF4081blue#00FFFFgold#FFD700silver#C0C0C0green#39FF14cmap{0:green,1:pink,2:gold,3:blue,}nodes[color]nodes.modularity_class.map(cmap)nodes.set_index(Id)[[color]].to_csv(arcane_colors.csv)总结当我们根据发现的社区为网络着色时社区指的是原始网络中的高度互联子图我们揭示了四个主要群体每个群体对应着故事情节中具体的一组角色。并不令人惊讶的是算法将主角家庭与金克丝、维和范德粉色聚集在了一起。然后我们还看到了扎恩地下人物蓝色的群体如希尔科而皮尔托弗的精英蓝色和军事执法绿色也被很好地分组在一起。这种社区结构的美妙之处和作用在于虽然这样的解释可以非常容易地将其置于背景中但通常仅凭直觉很难得出类似的图示。尽管此处呈现的方法清楚地展示了我们如何利用网络科学提取虚拟或真实社交系统的隐藏联系无论是律师事务所的合伙人、会计师事务所的同事还是一家大型石油公司的 HR 部门。