jieba 分词 + 共现矩阵构建——《釜山行》人物关系提取(二)
jieba 分词 共现矩阵构建——《釜山行》人物关系提取二标签:Python3|jieba|共现矩阵|NLP|釜山行|人物关系提取实验环境: 华为云 FlexusX / Ubuntu 24.04 / Python 3.12.3运行节点: node-01公网 1.94.202.191. 回顾与目标第一篇已经搭好了四节点环境。本篇在node-01上完成加载自定义 jieba 词典对《釜山行》文本分词统计人物出现频次以段落为窗口构建人物共现矩阵导出nodes.csv、edges.csv、stats.json。2. 完整代码busan_segment.py#!/usr/bin/env python3 jieba 分词 人物关系提取 — 《釜山行》 节点: node-01 (1.94.202.19) 功能: 加载自定义词典 - 分词 - 统计人物出现频次 - 按段落构建共现关系 importjiebaimportjieba.possegaspsegimportjsonfromcollectionsimportdefaultdict,Counter# 配置 TEXT_FILE/root/busan_text.txtDICT_FILE/root/busan_dict.txtCHARACTERS[石宇,秀安,尚华,盛京,珍熙,英国,容国,老姐姐,老妹妹,乞丐,列车长]# 1. 加载自定义词典 print(*60)print(步骤1: 加载自定义人物词典)print(*60)jieba.load_userdict(DICT_FILE)print(f已加载词典:{DICT_FILE})print(f人物列表:{CHARACTERS})# 2. 读取文本 print(\n*60)print(步骤2: 读取《釜山行》文本)print(*60)withopen(TEXT_FILE,r,encodingutf-8)asf:textf.read()print(f文本总长度:{len(text)}字符)print(f文本前100字:{text[:100]}...)# 3. 分词处理 print(\n*60)print(步骤3: jieba 分词处理)print(*60)wordsjieba.lcut(text)# 精确模式分词words_pospseg.lcut(text)# 带词性标注print(f分词总数:{len(words)}个词)# 4. 统计人物出现频次 print(\n*60)print(步骤4: 统计人物出现频次)print(*60)char_countCounter()forwinwords:ifwinCHARACTERS:char_count[w]1forchar,countinchar_count.most_common():print(f{char:10}{count:10})# 5. 按段落构建共现关系 print(\n*60)print(步骤5: 构建人物共现关系基于段落窗口)print(*60)paragraphs[p.strip()forpintext.split(\n)ifp.strip()]print(f段落数:{len(paragraphs)})co_occurrencedefaultdict(lambda:defaultdict(int))forparainparagraphs:para_wordsjieba.lcut(para)chars_in_paralist(set([wforwinpara_wordsifwinCHARACTERS]))foriinrange(len(chars_in_para)):forjinrange(i1,len(chars_in_para)):c1,c2chars_in_para[i],chars_in_para[j]co_occurrence[c1][c2]1co_occurrence[c2][c1]1# 6. 输出共现关系 edges[]forc1inCHARACTERS:forc2inCHARACTERS:ifc1c2andco_occurrence[c1][c2]0:edges.append((c1,c2,co_occurrence[c1][c2]))print(f\n共现关系总数:{len(edges)}条)# 7. 保存结果 withopen(/root/nodes.csv,w,encodingutf-8)asf:f.write(Id,Label,Weight\n)forcharinCHARACTERS:countchar_count.get(char,0)f.write(f{char},{char},{count}\n)withopen(/root/edges.csv,w,encodingutf-8)asf:f.write(Source,Target,Weight\n)forc1,c2,winsorted(edges,keylambdax:-x[2]):f.write(f{c1},{c2},{w}\n)stats{total_words:len(words),total_paragraphs:len(paragraphs),character_frequency:dict(char_count.most_common()),co_occurrence_edges:sorted(edges,keylambdax:-x[2]),total_edges:len(edges),}withopen(/root/stats.json,w,encodingutf-8)asf:json.dump(stats,f,ensure_asciiFalse,indent2)print(\n处理完成)3. 真实服务器输出rootecs-11e6-0001:~# cd /root python3 busan_segment.py Building prefix dict from the default dictionary ... Dumping model to file cache /tmp/jieba.cache Loading model cost 0.432 seconds. Prefix dict has been built successfully. 步骤1: 加载自定义人物词典 已加载词典: /root/busan_dict.txt 人物列表: [石宇, 秀安, 尚华, 盛京, 珍熙, 英国, 容国, 老姐姐, 老妹妹, 乞丐, 列车长] 步骤2: 读取《釜山行》文本 文本总长度: 1854 字符 步骤3: jieba 分词处理 分词总数: 1175 个词 步骤4: 统计人物出现频次 石宇 34 秀安 26 盛京 24 尚华 20 珍熙 17 英国 16 容国 15 乞丐 8 老妹妹 6 老姐姐 5 列车长 3 步骤5: 构建人物共现关系基于段落窗口 段落数: 16 步骤6: 人物共现关系表 石宇 - 秀安: 共现 12 次 石宇 - 盛京: 共现 11 次 秀安 - 盛京: 共现 11 次 石宇 - 尚华: 共现 9 次 尚华 - 盛京: 共现 9 次 珍熙 - 秀安: 共现 9 次 容国 - 秀安: 共现 9 次 容国 - 珍熙: 共现 9 次 ... 列车长 - 老妹妹: 共现 2 次 共现关系总数: 55 条 节点文件: /root/nodes.csv 边文件: /root/edges.csv 统计文件: /root/stats.json4. 关键结果解读4.1 人物出现频次人物出现次数角色定位石宇34男主 / 基金经理秀安26石宇女儿 / 核心线索人物盛京24尚华妻子 / 孕妇尚华20肌肉男 / 保护者珍熙17女高中生英国16自私的运营部长 / 反派容国15棒球少年乞丐8善良流浪汉老妹妹6老妹妹老姐姐5老姐姐列车长3列车工作人员频次直接反映人物在文本中的叙事权重。石宇和秀安是父女双主角因此频次最高。4.2 最强共现关系Top 10人物A人物B共现次数关系说明石宇秀安12父女石宇盛京11共同逃亡 / 尚华之托秀安盛京11共同被保护石宇尚华9并肩作战的战友尚华盛京9夫妻珍熙秀安9女性互助容国秀安9青年组共同逃亡容国珍熙9恋人石宇英国8冲突对抗秀安英国8被阻拦的受害者这些强共现关系基本对应了电影里的核心关系线父女、夫妻、情侣、战友、对抗。5. 生成的 CSV 数据格式nodes.csvId,Label,Weight 石宇,石宇,34 秀安,秀安,26 盛京,盛京,24 ...Gephi 导入时列Id作为节点唯一标识Label作为显示标签Weight控制节点大小。edges.csvSource,Target,Weight 石宇,秀安,12 盛京,石宇,11 盛京,秀安,11 ...Source和Target分别对应人物名称Weight控制边的粗细。6. 为什么段落窗口得到的是“完全图”细心的读者会发现在本实验中11 个人物之间两两都有共现55 条边 C(11,2)因此后续的网络密度为 1.0。这并不意外文本较短只有 16 个段落故事发生在一列封闭的列车上所有主要人物在同一灾难空间中高频交互老姐姐、老妹妹、列车长等次要人物仍出现在多个段落中。为了得到更稀疏、更聚焦的核心网络第三篇会用边权重过滤只保留Weight 7的边那时网络会呈现清晰的社群结构。7. 代码要点解析7.1 jieba.load_userdict自定义词典是识别人名的关键。如果不加载jieba 可能会把“石宇”切成“石/宇”从而丢失人物信息。7.2set()去重同一人物在一段落中可能出现多次必须去重否则共现次数会被重复计算。chars_in_paralist(set([wforwinpara_wordsifwinCHARACTERS]))7.3 无向边处理共现关系是无向的所以统计时加两次保证矩阵对称co_occurrence[c1][c2]1co_occurrence[c2][c1]1输出时只取c1 c2避免重复输出。8. 数据传递到下一节点生成的nodes.csv/edges.csv通过paramiko.SFTP从node-01传送到node-03做网络分析以及node-04做可视化。第三篇会展示这一过程。9. 下一篇预告第三篇将在node-03用NetworkX计算度中心性、介数中心性、接近中心性、特征向量中心性、聚类系数、网络密度、平均路径长度并导出.gexf供 Gephi 使用。10. 完整代码文件获取busan_text.txt电影文本busan_dict.txt自定义人名词典busan_segment.py分词与共现提取脚本nodes.csv/edges.csv节点与边数据stats.json统计结果这些文件已保存在 node-011.94.202.19的/root目录下读者可以直接复制到本地重复实验。