用Python+Gephi画《人民的名义》人物关系图

转载自https://blog.csdn.net/qq_38253732/article/details/80021381





理一下画关系图的步骤:

首先,要找到《人民的名义》的台词(或剧本),可以使用UTF8编码的txt文件。

其次,要提取剧中的角色,这里我们使用jieba分词模块来提取文本中的角色名,得到图的“节点

然后,为再剧本中每一段中出现的若干个角色,两两之间建立一条“”,根据两两角色一同出现频度,来决定边的“权值

最后,根据上面的信息,使用Gephi来图


可以先定义三个变量


      
      
      
      
  1. # names : 保存人物,键为人物名称,值为该人物在全文中出现的次数
  2. # relationship : 保存人物关系的有向边,键为有向边的起点,值为一个字典 edge ,edge 的键为有向边的终点,值是有向边的权值,
  3. # 代表两个人物之间联系的紧密程度
  4. # lineNames : 缓存变量,保存对每一段分词得到当前段中出现的人物名称
  5. names = {}
  6. relationships = {}
  7. lineNames = []

1.提取角色(节点)

jieba分词中对人名的识别不够准确,比如,可能会把“明白”、“文明”这样的词识别为人名,针对这个问题,可以建立用户自定义字典,以提高《人民的名义》中人名的识别准确率。

可以在网上查找角色表,写入一个txt文件。如下是一个自定义字典的示例,每行第一个代表字典中的词,第二个代表频数,第三个代表词性。

侯亮平 100 nr
沙瑞金 100 nr
李达康 100 nr
高育良 100 nr
祁同伟 100 nr
陆亦可 100 nr
高小琴 100 nr
吴慧芬 100 nr
刘新建 100 nr
陈岩石 100 nr
季昌明 100 nr
赵瑞龙 100 nr
郑西坡 100 nr
钟小艾 100 nr
赵东来 100 nr
蔡成功 100 nr
欧阳菁 100 nr
丁义珍 100 nr
程度 100 nr
陈海 100 nr
郑胜利 100 nr
王文革 100 nr
田国富 100 nr
赵德汉 100 nr
易学习 100 nr
梁璐 100 nr
孙连成 100 nr
肖钢玉 100 nr
林华华 100 nr
jieba.load_userdict("RoleTable.txt")
      
      
      
      

在分词后判断一个词是否为人名,可以用下面两个条件筛选,满足条件的可以人为不是人名

1) 该词词性不为 “nr”   2) 该词长度小于2


      
      
      
      
  1. with codecs.open( "人民的名义.txt", 'r', 'utf8') as f:
  2. for line in f.readlines(): # 注意是 readlines 要加s 不加s 只读取一行
  3. poss = pseg.cut(line) # 分词,返回词性
  4. lineNames.append([]) # 为本段增加一个人物列表
  5. for w in poss:
  6. if w.flag != 'nr' or len(w.word) < 2:
  7. continue # 当分词长度小于2或该词词性不为nr(人名)时认为该词不为人名
  8. lineNames[ -1].append(w.word) # 为当前段的环境增加一个人物
  9. if names.get(w.word) is None: # 如果某人物(w.word)不在人物字典中
  10. names[w.word] = 0
  11. relationships[w.word] = {}
  12. names[w.word] += 1

可以查看一下结果:


      
      
      
      
  1. # 输出人物出现次数统计结果
  2. for name, times in names.items():
  3. print(name, times)

2.创建角色关系(边)


       
       
       
       
  1. # 对于 lineNames 中每一行,我们为该行中出现的所有人物两两相连。如果两个人物之间尚未有边建立,则将新建的边权值设为 1,
  2. # 否则将已存在的边的权值加 1。这种方法将产生很多的冗余边,这些冗余边将在最后处理。
  3. for line in lineNames:
  4. for name1 in line:
  5. for name2 in line:
  6. if name1 == name2:
  7. continue
  8. if relationships[name1].get(name2) is None:
  9. relationships[name1][name2] = 1
  10. else:
  11. relationships[name1][name2] = relationships[name1][name2] + 1

3.输出图的信息


       
       
       
       
  1. # 由于分词的不准确会出现很多不是人名的“人名”,从而导致出现很多冗余边,为此可设置阈值为10,即当边出现10次以上则认为不是冗余
  2. with codecs.open( "People_node.txt", "w", "utf8") as f:
  3. f.write( "ID Label Weight\r\n")
  4. for name, times in names.items():
  5. if times > 10:
  6. f.write(name + " " + name + " " + str(times) + "\r\n")
  7. with codecs.open( "People_edge.txt", "w", "utf8") as f:
  8. f.write( "Source Target Weight\r\n")
  9. for name, edges in relationships.items():
  10. for v, w in edges.items():
  11. if w > 10:
  12. f.write(name + " " + v + " " + str(w) + "\r\n")

节点:

用Python+Gephi画《人民的名义》人物关系图_第1张图片

边:

用Python+Gephi画《人民的名义》人物关系图_第2张图片


至此工作已完成一大半。

4.使用Gephi画图

笔者是在Windows环境下使用Gephi,为了能将图的信息导入Gephi,需要对上面的People_node.txt与People_edge.txt文件进行预处理。Linux环境可以跳过此步骤。

我们借助Office的Excel将txt文件转换为csv文件(一种逗号分隔的文件)

打开Excel -> 数据  -> 自文本 -> 选择要转换的txt文件

用Python+Gephi画《人民的名义》人物关系图_第3张图片

选择下一步

用Python+Gephi画《人民的名义》人物关系图_第4张图片

注意选择分隔符号为空格

用Python+Gephi画《人民的名义》人物关系图_第5张图片


然后就可以将txt文本导入,最后选择另存为csv文件即可。

打开Gephi -> 文件 -> 导入电子表格 -> 选择刚刚生成的csv文件

注意:先导入节点后导入边,两个文件导入到同一个工作区域

用Python+Gephi画《人民的名义》人物关系图_第6张图片

若出现乱码重选字符集(如GBK)

用Python+Gephi画《人民的名义》人物关系图_第7张图片

注意:导入节点文件时可以是新建一个工作空间,但记得导入边文件时要加入同一个工作空间

用Python+Gephi画《人民的名义》人物关系图_第8张图片



在 概况 -> 工作区 -> 外观 中选择你想要的外观

在 概况 -> 工作区 -> 布局 中选择你想要的布局,记得点运行

在 预览 -> 预览设置 -> 节点 中勾选 显示标签,选择合适的字体字号

在 预览 -> 预览设置 -> 边 中勾选 重新调整权重

为了美观可以将边箭头尺寸调为零,最后选择刷新

可以通过 文件 -> 输出 来输出图文件,下面是笔者做出来的示例:

用Python+Gephi画《人民的名义》人物关系图_第9张图片

全部代码:


      
      
      
      
  1. # -- conding: utf-8 --
  2. import codecs
  3. import jieba.posseg as pseg
  4. import jieba
  5. # names : 保存人物,键为人物名称,值为该人物在全文中出现的次数
  6. # relationship : 保存人物关系的有向边,键为有向边的起点,值为一个字典 edge ,edge 的键为有向边的终点,值是有向边的权值,
  7. # 代表两个人物之间联系的紧密程度
  8. # lineNames : 缓存变量,保存对每一段分词得到当前段中出现的人物名称
  9. names = {}
  10. relationships = {}
  11. lineNames = []
  12. jieba.load_userdict( "RoleTable.txt")
  13. with codecs.open( "人民的名义.txt", 'r', 'utf8') as f:
  14. for line in f.readlines(): # 注意是 readlines 要加s 不加s 只读取一行
  15. poss = pseg.cut(line) # 分词,返回词性
  16. lineNames.append([]) # 为本段增加一个人物列表
  17. for w in poss:
  18. if w.flag != 'nr' or len(w.word) < 2:
  19. continue # 当分词长度小于2或该词词性不为nr(人名)时认为该词不为人名
  20. lineNames[ -1].append(w.word) # 为当前段的环境增加一个人物
  21. if names.get(w.word) is None: # 如果某人物(w.word)不在人物字典中
  22. names[w.word] = 0
  23. relationships[w.word] = {}
  24. names[w.word] += 1
  25. # 输出人物出现次数统计结果
  26. # for name, times in names.items():
  27. # print(name, times)
  28. # 对于 lineNames 中每一行,我们为该行中出现的所有人物两两相连。如果两个人物之间尚未有边建立,则将新建的边权值设为 1,
  29. # 否则将已存在的边的权值加 1。这种方法将产生很多的冗余边,这些冗余边将在最后处理。
  30. for line in lineNames:
  31. for name1 in line:
  32. for name2 in line:
  33. if name1 == name2:
  34. continue
  35. if relationships[name1].get(name2) is None:
  36. relationships[name1][name2] = 1
  37. else:
  38. relationships[name1][name2] = relationships[name1][name2] + 1
  39. # 由于分词的不准确会出现很多不是人名的“人名”,从而导致出现很多冗余边,为此可设置阈值为10,即当边出现10次以上则认为不是冗余
  40. with codecs.open( "People_node.txt", "w", "utf8") as f:
  41. f.write( "ID Label Weight\r\n")
  42. for name, times in names.items():
  43. if times > 10:
  44. f.write(name + " " + name + " " + str(times) + "\r\n")
  45. with codecs.open( "People_edge.txt", "w", "utf8") as f:
  46. f.write( "Source Target Weight\r\n")
  47. for name, edges in relationships.items():
  48. for v, w in edges.items():
  49. if w > 10:
  50. f.write(name + " " + v + " " + str(w) + "\r\n")



你可能感兴趣的:(python数据可视化,python数据分析及可视化)