当前位置:   article > 正文

NLP分析小说人物关系,找找主人公的真爱。_小说人物关系 nlp

小说人物关系 nlp

思路
基于共现来挖掘人物之间的关系。
准备好三个存储器

  1. names 存放的是人物出现次数,用来后面刻画节点的大小。names类似’叶三姐’: 8, ‘马鞍’: 6,
  2. relationships 存放人物关系 {‘钱塘江’: {‘牛家村’: 1}, ‘牛家村’: {‘钱塘江’: 1, ‘武功’: 1, ‘王道乾’: 1, ‘郭啸天’: 1,}} 嵌套字典。
  3. lineNames 共现词 类似[[‘钱塘江’, ‘牛家村’], [‘柏树’, ‘叶子’], [], [‘萧索’, ‘松树’]]

思路不解释,自己看代码,这也是我学习之后写的。
看别人文字思路,不如看代码。毕竟文字思路多啦一道转换。

步骤1

import jieba.posseg as pseg
from  tqdm import tqdm#设置一个进度条
# 姓名字典
names = {}
# 关系字典
relationships = {}
# 每段内人物关系
lineNames = []
#打开文件
with open('射雕英雄传.txt', 'r',encoding='utf-8') as fp:
    for line in tqdm(fp):
        line = line.strip('\n')#去除换行
        poss = pseg.cut(line)# 分词返回词性

        # 为新读取的一段添加人物关系
        lineNames.append([])
        for w in poss:#遍历每一个
           # print("%s:%s" % (w.word, w.flag))
           # 分词长度小于2 或词性不为nr时则与影片所需分析人物无关
           if w.flag != "nr" or len(w.word) < 2:
               continue
           lineNames[-1].append(w.word)#当前段存放人物名

           if names.get(w.word) is None:#如果姓名未出现过
               names[w.word] = 0#当前姓名添加进names字典里
               relationships[w.word] = {}#初始化该姓名关系图
               # 人物出现次数+1
           names[w.word] += 1

print('names\n',names)
print('relationships\n',relationships)
print('lineNames\n',lineNames)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

步骤2

#分析人物关系
for line in lineNames:
        for name1 in line:
            for name2 in line:
                if name1 == name2:
                    continue
                if relationships[name1].get(name2) is None:
                    # 两个人物第一次共同出现 初始化次数
                    relationships[name1][name2] = 1
                else:
                    # 两个人物共同出现 关系+1
                    relationships[name1][name2] += 1

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

步骤3

# 写csv文件 用于网络图使用
def generate_gephi():
    # 人物权重(节点)
    with open("earth_node.csv", "w", encoding='utf-8') as f:
        f.write("Id Label Weight\r\n")
        for name, times in names.items():
            f.write(name + " " + name + " " + str(times) + "\r\n")

    # 人物关系边(边)
    with open("earth_edge.csv", "w", encoding='utf-8') as f:
        f.write("Source Target Weight\r\n")
        for name, edge in relationships.items():
            for v, w in edge.items():
                if w > 3:
                    f.write(name + " " + v + " " + str(w) + "\r\n")

generate_gephi()


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

得到的数据 是一列的

需要应用excel 技术将一列分成多列
如结果

画图

import pandas as pd



file1=pd.read_csv('earth_edge.csv',encoding='gbk')#人物关系
file1=file1.dropna()



import networkx as nx
from pylab import *
import matplotlib.pyplot as plt
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

def painting(): #绘制人物亲密度图
    G = nx.Graph()  # 绘制个人物之间的亲密关系

    for index, row in file1.iterrows():
        G.add_node(row['Source'])#添加节点
    for index, row in file1.iterrows():
        G.add_weighted_edges_from([(row['Source'],row['Target'],row['Weight'])])
    pos = nx.shell_layout(G)
    print('画出网络图像:')
    nx.draw(G, pos, with_labels=True, node_color='white', edge_color='red', node_size=400, alpha=0.5)
    plt.show()



painting()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

人太多 ,图炸啦。

接下来我只绘制重要人物的图

import pandas as pd
import numpy as np
file=pd.read_csv('earth_node.csv',encoding='gbk')#人物权重文件
file=file.dropna()

file1=pd.read_csv('earth_edge.csv',encoding='gbk')#人物关系文件
file1=file1.dropna()#去空白

#主要人物
namelist = ['郭啸天','杨铁心','冷笑','武功','包惜弱','那道人','郭靖','杨康','李萍','段天德','完颜洪烈',
                '柯镇恶','朱聪','韩宝驹','韩小莹','铁木真','梅超风','黄药师','尹志平','马钰','沙通天',
                '黄蓉','穆念慈','洪七公','周伯通','欧阳锋','裘千仞']
#人物权重
node_size=[]#no人物权重

for name in namelist :
    node_size.append(np.array(file.loc[file['Id'] == name, 'Weight'])[0])




import networkx as nx
from pylab import *
import matplotlib.pyplot as plt
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

def painting(): #绘制人物亲密度图
    G = nx.Graph()  # 绘制个人物之间的亲密关系

    for index, row in file1.iterrows():
        if row['Source']  in namelist:
            G.add_node(row['Source'])  # 添加节点# 将当前人物添加进节点

    for index, row in file1.iterrows():
        if (row['Source']  in namelist) & (row['Target']  in namelist):
            #G.add_node(row['Source'], row['Target'])
            G.add_weighted_edges_from([(row['Source'], row['Target'], 10*np.array(row['Weight']))])#添加权重



    pos = nx.shell_layout(G)
    print('画出网络图像:')
    nx.draw(G, pos, with_labels=True, node_color=range(27), edge_color='red', node_size=node_size, alpha=0.5,width=[float(d['weight']*0.01) for (u,v,d) in G.edges(data=True)])

    plt.show()



painting()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50

郭靖和黄蓉果然是真爱。

分析
本次 还有些缺陷。
如郭靖和黄蓉之间还有些昵称。如靖哥哥,蓉儿,未统计进来。(主要是我懒,懒得写多余代码,使他们都映射到同一个名字。如把靖哥哥、郭大哥、郭靖 全部映射到郭靖。)
在这里插入图片描述
作者:电气余登武

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/煮酒与君饮/article/detail/848627
推荐阅读
相关标签
  

闽ICP备14008679号