You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

R中提取带上下文的匹配字符串:如何从个人经历描述识别首份工作年份

需求与现有方法说明

数据集基础结构

当前待处理数据集包含3个基础字段:

  • Id:样本唯一标识
  • First_name:受访者名
  • Description:受访者个人经历的自然语言描述文本
    核心目标是从Description字段中抽取受访者获得第一份工作的年份,生成First_job_year字段。根据数据集特征,绝大多数首份工作的记录年份都集中在20世纪70年代。

示例数据集结构如下:

library(stringr)
dat <- data.frame(Id = c(1,2,3), 
           First_name = c("Adam", "Bob", "Chris"), 
           Description = c("Adam graduated high school in 1971, got married in 1973, and started working at Ford in 1975", 
           "Bob graduated from university in 1972, and a year later started working in the civil service", 
           "Chris dropped out of school in 1969 and was unemployed for a while, but found work in 1973"),
           First_job_year = c(1975, 1972, 1973))

现有方法的缺陷

最初尝试通过正则规则提取所有以197开头的4位数字字符串(覆盖1970-1979年区间),代码与运行结果如下:

first_job_dates <- str_extract_all(dat$Description, "197.")
first_job_dates
# [[1]]
# [1] "1971" "1973" "1975"
# [[2]]
# [1] "1972"
# [[3]]
# [1] "1973"

该方法存在明显的识别误差:

  • Adam的样本匹配结果混入了高中毕业、结婚等非就业场景的70年代年份,仅1975是正确的首份工作年份
  • Bob的样本仅匹配到大学毕业的1972年,完全漏过了“毕业1年后入职公职”的真实首份工作时间

优化思路与当前卡点

计划的优化逻辑为:匹配到符合197.规则的年份字符串时,同步提取匹配位置前后固定范围(如前后各5个单词)的文本上下文,通过上下文是否包含job、work/working这类就业相关词汇,筛选出真正对应首份工作的年份;对无法通过规则自动识别的样本(如Bob的案例)直接标记为缺失值,留待后续人工校准。
当前卡点是不清楚R中可以用什么命令实现「匹配点位周边固定范围文本的提取」,需要适配这类需求的命令或扩展包推荐。

R环境下的实现方案

不需要依赖复杂的专用扩展包,基于stringr的原生函数即可完整实现上下文提取的需求,核心用到两个基础能力:

  1. 匹配位置定位:用str_locate_all()获取每个匹配到的年份在原文本中的起始、结束字符坐标
  2. 上下文截取:用str_sub()根据定位到的坐标,按设定的偏移量截取范围文本

具体实现代码如下:

library(stringr)

# 1. 定位文本中所有符合"197."规则的年份的字符位置
match_pos <- str_locate_all(dat$Description, "197.")

# 2. 逐样本提取每个匹配年份的上下文(这里设定为年份前后各50个字符,可根据文本长度调整)
dat$match_context <- lapply(seq_along(dat$Description), function(idx){
  full_text <- dat$Description[idx]
  pos <- match_pos[[idx]]
  # 无匹配项时返回空值
  if(nrow(pos) == 0) return(NA)
  # 对每个匹配到的年份,截取对应范围的上下文,注意处理文本边界防止越界
  ctx_list <- apply(pos, 1, function(p){
    start <- max(1, p["start"] - 50)
    end <- min(nchar(full_text), p["end"] + 50)
    str_sub(full_text, start, end)
  })
  # 绑定匹配年份与对应的上下文
  data.frame(
    year = as.integer(str_extract(ctx_list, "197.")),
    context = ctx_list
  )
})

提取完上下文后,即可通过关键词规则筛选出真实对应工作场景的年份:

# 定义就业相关的关键词匹配规则
work_pattern <- "work|working|job|employed|started.*company|civil service"

# 筛选上下文匹配到就业关键词的年份,取第一个命中的作为首份工作年份
dat$rule_matched_year <- lapply(dat$match_context, function(ctx){
  if(is.data.frame(ctx)){
    valid_year <- ctx[str_detect(ctx$context, work_pattern), "year"]
    as.integer(valid_year[1])
  } else {
    NA_integer_
  }
}) |> unlist()

对示例数据集运行上述代码的输出结果为:

  • Adam:1975(1971、1973的上下文无就业关键词,被过滤)
  • Bob:NA(他的首份工作年份没有直接以数字形式出现在文本中,符合预期标记为缺失)
  • Chris:1973(上下文包含found work,命中关键词规则)

如果觉得按字符偏移量计算范围不够精准,想要严格按照单词数统计上下文范围,可以搭配tokenizers包先将文本拆分为独立单词,定位到年份对应的单词索引后,直接按索引前后取固定数量的单词拼接成上下文即可,逻辑与上述实现完全一致。

内容的提问来源于stack exchange,提问作者nbai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.31 23:54:05