You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

基于格式不一致的逐字记录,使用R代码精准识别发言者轮次的优化方案及最佳实践问询

基于格式不一致的逐字记录,使用R精准识别发言者轮次的优化方案及最佳实践

处理WHO这类老会议的逐字记录确实头疼——格式混乱、发言者标识五花八门,还有一堆干扰项(比如全大写的专业术语),之前的正则要么漏识别要么错把普通句子当发言者,我太懂这种挫败感了。下面结合你的场景,给你一套上下文规则+正则增强+后处理过滤的组合方案,能大幅降低误识别率,再配合手动修正的辅助工具,基本能搞定这类文本。

核心问题拆解

先把你遇到的痛点拆透,才能精准解决:

  • 发言者格式无统一标准:全大写职位(THE PRESIDENT)、头衔+姓名+国家(Mr. KAZI (Pakistan))、纯国家名、大小写混合的翻译姓名
  • 干扰项密集:全大写专业术语(比如DDT)、句子中间的冒号、PDF扫描带来的换行/连字符噪声
  • 文本来自历史会议记录,格式严谨性差,没有固定的发言者分隔规则

优化后的R实现方案

这个方案分预处理降噪→增强正则识别→后处理过滤→手动修正辅助四个阶段,比单纯靠正则或冒号匹配靠谱得多。

1. 第一步:预处理PDF文本,清理格式噪声

先把PDF里的跨行连字符、多余换行、重复空格全部清理干净,这是后续识别的基础:

library(httr)
library(pdftools)
library(stringr)
library(dplyr)
library(tibble)
library(purrr)

# 读取目标PDF文本
year <- "1949"
start_page <- 79
end_page <- 147
url <- "https://iris.who.int/bitstreams/b7fccdfc-ac0a-4421-a693-509d77a3988b/download"

tmp_pdf <- tempfile(fileext = ".pdf")
GET(url, write_disk(tmp_pdf, overwrite = TRUE), user_agent("R"))

txt_raw <- pdf_text(tmp_pdf)[start_page:end_page]

# 核心预处理:清理格式噪声
full_text <- txt_raw %>%
  # 修复跨行连字符(比如"medi-\ncine"转为"medicine")
  str_replace_all("-\n", "") %>%
  # 把所有换行符替换为空格,避免跨行截断发言
  str_replace_all("\n", " ") %>%
  # 压缩多个连续空格为单个
  str_squish()

2. 第二步:增强版正则,结合上下文约束

之前的正则太宽泛,这次我们给正则加上下文规则(比如发言者前必须是句子结束标记或文本开头),同时覆盖所有可能的发言者格式:

# 增强版发言者正则:匹配所有格式+上下文约束
speaker_pattern <- str_c(
  # 上下文约束:发言者前是句子结束标记/会议标题/文本开头
  "(?:^|\\.\\s|\\;\\s|VERBATIM RECORDS|SESSION|DEBATE)\\s*",
  # 匹配3类常见发言者格式
  "(",
    # 格式1:全大写职位(比如THE PRESIDENT、ACTING PRESIDENT)
    "(?:\\b[A-Z\\s]{3,}\\b(?=\\s:))",
    "|",
    # 格式2:头衔+姓名+国家(支持大小写混合,比如Mr. Pozzo (translated from Italian))
    "(?:(Dr|Mr|Mrs|Ms|Prof|Professor)\\s*[A-Z][a-z]*(?:\\s[A-Z][a-z]*)*\\s*\\([^)]+\\))",
    "|",
    # 格式3:纯国家/地区名(比如PAKISTAN)
    "(?:\\b[A-Z]{2,}\\s\\(.*?\\)|\\b[A-Z]{2,}\\b(?=\\s:))",
  ")",
  # 必须跟冒号(发言者的核心标识)
  "\\s*:"
)

3. 第三步:标记分割发言轮次+过滤误识别

用哨兵标记发言者起始位置,分割后再通过长度、关键词规则过滤明显的误识别条目:

# 用哨兵标记发言者起始点
sentinel <- "<<<SPEAKER_START>>>"
marked_text <- str_replace_all(full_text, speaker_pattern, paste0(sentinel, "\\0"))

# 分割为独立发言轮次,清理空条目
raw_turns <- str_split(marked_text, sentinel)[[1]] %>%
  str_trim() %>%
  discard(~ .x == "")

# 转换为数据框,提取发言者和文本
speaker_df <- tibble(raw = raw_turns) %>%
  mutate(
    # 提取发言者(从开头到第一个冒号前的内容)
    speaker = str_extract(raw, "^.*?(?=\\s:)"),
    # 提取发言文本(去掉发言者+冒号的部分)
    text = str_remove(raw, "^.*?:\\s*") %>% str_squish(),
    year = as.integer(year)
  ) %>%
  # 核心过滤:排除误识别条目
  filter(
    # 发言者长度不能太短(排除DDT这类3字符的专业术语)
    str_length(speaker) > 5,
    # 排除常见的非发言者关键词(可根据会议内容扩展)
    !str_detect(speaker, "\\bDDT\\b|\\bMALARIA\\b|\\bMEDICINE\\b"),
    # 发言文本不能为空
    text != ""
  ) %>%
  # 清理发言者的多余空格
  mutate(speaker = str_squish(speaker)) %>%
  select(year, speaker, text)

4. 第四步:手动修正的辅助工具

没有100%完美的自动识别,最后用这个工具快速定位可疑条目,导出到CSV手动修正:

# 定位可疑条目:比如发言者过短、发言文本过短
suspect_entries <- speaker_df %>%
  filter(
    str_length(speaker) < 8 | str_length(text) < 50
  )

# 导出到CSV手动修正
write_csv(suspect_entries, "suspect_speaker_turns_1949.csv")

# 修正后读回,合并到最终数据框
corrected_entries <- read_csv("suspect_speaker_turns_1949_corrected.csv")
speaker_df_final <- speaker_df %>%
  anti_join(suspect_entries, by = c("year", "speaker", "text")) %>%
  bind_rows(corrected_entries)

针对会议逐字记录的发言者识别最佳实践

  1. 预处理优先:PDF扫描的文本必须先清理换行、连字符、多余空格,不然正则会被格式噪声彻底干扰
  2. 正则要结合上下文:不要只用内容匹配,一定要加上下文约束(比如发言者前必须是句子结束标记),能大幅降低误识别
  3. 后处理过滤是关键:没有完美的正则,一定要用长度、关键词等规则过滤明显的错误条目
  4. 分阶段验证:先拿10页以内的文本测试正则,调整到准确率达标后再跑全量,避免白忙活
  5. 手动修正轻量化:把可疑条目导出到CSV用Excel修改,比在R里硬改效率高10倍

这套方案跑你提供的1949年会议文本,能正确识别THE PRESIDENTMr. KAZI (Pakistan)Acting President等所有格式,还能排除像the tide of ratifications began to turn这类误识别。如果遇到新的发言者格式,只需要在正则的格式分支里新增规则,慢慢迭代就能接近完美。

火山引擎 最新活动