Python实现《红楼梦》中贾宝玉与十二金钗关系图谱

       这段代码的整体功能是从一个红楼梦文本文件中利用python的jieba分词库通过算法提取人名,分析这些人名在文本中的出现频率以及他们之间的关联关系,然后将这些信息输出到两个文件中,并最终在控制台上以prettytable表格的形式展示关系信息。下面我会详细解释每个部分的工作原理:

导入必要的库

  • codecs:用于读取和写入文件,支持多种编码方式。
  • jieba:中文分词工具。
  • jieba.posseg:用于词性标注的分词工具。
  • PrettyTable:用于创建漂亮的表格输出。

定义相关变量

  • names:一个字典,用于存储每个人名及其出现的次数。
  • relationships:一个字典,用于存储人名之间的关联关系及其次数。
  • line_names:一个列表,用于存储每一行文本中识别出的人名。

加载任务表和分词

  • 使用jieba.load_userdict("./names.txt")加载用户自定义词典,这里假设names.txt包含了一些人名。
  • 读取hlm.txt文件,对每一行进行分词和词性标注。
  • 如果一个词的词性为nr(人名)且长度大于或等于2,则将其添加到line_names列表,并更新namesrelationships字典。

分析人名关联关系

  • 遍历line_names列表,分析每一行中不同人名之间的关联关系。
  • 如果两个不同的人名在同一行中出现,则增加他们之间的关联次数。

输出到文件

  • 将出现次数大于10的人名及其次数输出到People_node.txt文件。
  • 将关联次数大于10的人名对及其关联次数输出到People_edge.txt文件。

过滤和展示关系信息

  • 读取People_edge.txt文件,将内容存储到列表a中。
  • 根据names.txt中的内容过滤掉一些关系。
  • 使用PrettyTable创建一个表格,展示过滤后的关系信息。

细节解释

  • w.flag != 'nr' or len(w.word) < 2:这里过滤掉了非人名词性的词和长度小于2的词,因为可能有一些很短的词被误判为人名。
  • if relationships[name1].get(name2) is None:如果name1name2之间的关联关系还没有被记录,则初始化为1;否则,增加关联次数。
  • 在输出到文件时,代码选择了出现次数和关联次数大于10的人名和关系进行输出,这是一个阈值选择,可以根据需要进行调整。
  • 在过滤和展示关系信息时,代码使用了列表推导式和PrettyTable库来简化代码和提高可读性。
# coding = utf-8
# 导入必要的库
import codecs  # 导入codecs库,用于文件编码的读写
import jieba  # 导入jieba库,用于中文分词
import jieba.posseg as pseg  # 导入jieba的标注词性的模块
from prettytable import PrettyTable  # 导入prettytable库,可以创建漂亮的表格

# 定义相关变量
# 定义存储人名和出现次数的字典
names = {}
# 定义存储人物关系和出现次数的字典
relationships = {}
# 定义每行分词后的人物列表
line_names = []  # 定义一个列表,用于存储每一行分词后的人物名称
# 加载词典提高分词准确性
jieba.load_userdict("./names.txt")

# 读取文章并同时录入人名
with codecs.open("./hlm.txt", "r", encoding="utf-8") as f:  
    for line in f.readlines():
        poss = pseg.cut(line)  # 对每一行词语进行词性标注
        line_names.append([])  # 为该行创建一个专属列表
        for w in poss:
            if w.flag != 'nr' or len(w.word) < 2:  # 忽略不是人名或者词的长度小于2的词
                continue
            line_names[-1].append(w.word)  # 符合要求的词添加到行列表内
            if names.get(w.word) is None:  # 如果人名在names字典中不存在就添加该人名并重置次数为0
                names[w.word] = 0
                relationships[w.word] = {}  # 在relationships字典中添加新人名并初始化其关系字典
            names[w.word] += 1  # 人名出现次数加1

# 遍历每一行的人物列表,统计人物之间的关系
for line in line_names:
    for name1 in line:
        for name2 in line:
            if name1 == name2:  # 如果两个人名相同就跳过
                continue
            if relationships[name1].get(name2) is None:  # 如果name1和name2的关系在relationships字典中不存在就在relationships字典中添加该关系
                relationships[name1][name2] = 1  # 设置两者关系出现次数为1
            else:
                relationships[name1][name2] = relationships[name1][name2] + 1  # 关系出现次数加1

# 将出现次数大于10的人名及其出现次数写入文件
with codecs.open("./People_node.txt", "w", encoding="utf-8") as f:
    f.write("ID Label \r\n")
    for name, times in names.items():  # 遍历names字典,键:名字,值:出现次数
        if times > 10:  # 如果人名出现次数大于10就将人名、标签和出现次数写入文件
            f.write(name + " " + name + " " + str(times) + "\r\n")

# 将出现次数大于10的人物关系及其出现次数写入文件
with codecs.open("./People_edge.txt", "w", "utf-8") as f:
    f.write("Source Target Weight\r\n")
    for name, edges in relationships.items():  # 遍历relationships字典,键:名字,值:关系出现次数
        for v, w in edges.items():  # 遍历关系嵌套字典edges
            if w > 10:  # 如果关系出现次数大于10就将源、目标和权重写入文件
                f.write(name + " " + v + " " + str(w) + "\r\n")

# 读取文件准备过滤并显示数据
f1 = open("./People_edge.txt", "r", encoding='utf-8')
f2 = open("./names.txt", "r", encoding='utf-8').read()
lines = f1.readlines()  # 读取文件所有行
a = []  # 初始化一个空列表用来存放展示关系图谱的数据
# 遍历从文件中读取的每一行
for line in lines:
    # 为当前行创建一个新的空列表,并添加到列表a中
    a.append([])
    # 去除行尾的换行符,并按空格分割字符串,得到包含各个字段的列表m
    m = line.strip('\n').split(' ')
    # 遍历分割后的字段列表m
    for x in m:
        # 将字段x添加到当前行的列表中
        a[-1].append(x)
# 遍历列表a中的每一项(即每一行数据)
for items in a:
    # 如果当前行的第一个字段存在(非空),并且第二个字段不在f2(names.txt的内容)中
    if items[0] and items[1] not in f2:
        # 则从列表a中删除这一行数据
        del items
# 关闭文件
f1.close()

# 实例PrettyTable对象
x = PrettyTable()
# 设置表头为Source、Target、Weight共3列
x.field_names = ['Source', 'Target', 'Weight']
# 遍历列表a中除了第一行之外的行的数据
for i in a[1:]:
    # 将a列表嵌套的每行子列表的数据添加到行内
    x.add_row([i[0], i[1], i[2]])
# 打印去掉标题的记录数
print(f"Total Records Number: {len(a) - 1}")
# 展示表格
print(x)

缺陷

       这段代码主要用于文本分析中的人物关系提取和可视化,它使用了中文分词和词性标注技术来识别人名,并通过分析人名在文本中的共现关系来构建人物关系网络。但还是会出现误认为某些词语是人名的现象,这个问题还需要对提取人名的算法进行改进。有其他问题也可以直接私聊我哦。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值