如何结合str_detect与lag/lead函数跨多行查找目标匹配项?
问题需求
现有处理单行lag()/lead()匹配的函数,但需要优化:当目标行的紧邻前后行无匹配项时,查找当前行前后最近的、满足str_detect=TRUE的实例(例如匹配项出现在前三行),完成对应字符串替换。
当前使用的包
library(tidytext) library(dplyr) library(stringr)
原单行匹配函数
匹配前一行的函数
# 仅匹配前一行的函数 r_sen_from_states_alabama_lag <- function(x){ ifelse(str_detect(x, regex("the senator from Alabama",ignore_case = TRUE))==TRUE & str_detect(lag(x),"^Mr\\. SHELBY \\(R; Alabama\\):")==TRUE, str_replace(x,regex("the senator from Alabama", ignore_case = TRUE),"senator Shelby"), ifelse(str_detect(x, regex("the senator from Alabama", ignore_case = TRUE))==TRUE & str_detect(lag(x),"^Mr\\. SESSIONS \\(R; Alabama\\):")==TRUE, str_replace(x, regex("the senator from Alabama",ignore_case = TRUE), "senator Sessions"),x)) }
匹配后一行的函数
# 仅匹配后一行的函数 r_sen_from_states_alabama_lead <- function(x){ ifelse(str_detect(x, regex("the senator from Alabama",ignore_case = TRUE))==TRUE & str_detect(lead(x),"^Mr\\. SHELBY \\(R; Alabama\\):")==TRUE, str_replace(x,regex("the senator from Alabama", ignore_case = TRUE),"senator Shelby"), ifelse(str_detect(x, regex("the senator from Alabama", ignore_case = TRUE))==TRUE & str_detect(lead(x),"^Mr\\. SESSIONS \\(R; Alabama\\):")==TRUE, str_replace(x, regex("the senator from Alabama",ignore_case = TRUE), "senator Sessions"),x)) } test_df_try_1 <- as.data.frame(r_sen_from_states_alabama_lead(test_df))
测试数据
# 测试数据 test_col <- c("Mr. SHELBY (R; Alabama): I acknowledge this is a test.", "Mrs. MURRAY (D; Washington): I say to my friend, the senator from Alabama, that they are wrong.", "Mr. SHELBY (R; Alabama): I do not agree with my colleague.", "Mr. FRIST (R; Tennessee): The senator from Alabama is correct, senator Murray.", "Mr. SHELBY (R; Alabama): I thank the majority leader for their support.", "Mr. SESSIONS (R; Alabama): I am proud of my junior, the senator from Alabama.", "Mr. SHELBY (R; Alabama): To my senior peer, the senator from Alabama, I say great things.", "Ms. PEABODY (I; Atlantis): This is just to fill space.", "Mr. Quail (Q; Nowhere): Match this one, the senator from Alabama, with the senator at the bottom.", "Ms. PEABODY (I; Atlantis): This is just to fill space.", "Ms. PEABODY (I; Atlantis): This is just to fill space!", "Ms. PEABODY (I; Atlantis): This is just to fill space?", "Mr. SESSIONS (R; Alabama): Match this one with Quail.") test_df <- data.frame(test_col) colnames(test_df) <- c("speeches")
期望输出
向前查找(最近的前序匹配)结果
1 Mr. SHELBY (R; Alabama): I acknowledge this is a test. 2 Mrs. MURRAY (D; Washington): I say to my friend, senator Shelby, that they are wrong. 3 Mr. SHELBY (R; Alabama): I do not agree with my colleague. 4 Mr. FRIST (R; Tennessee): senator Shelby is correct, senator Murray. 5 Mr. SHELBY (R; Alabama): I thank the majority leader for their support. 6 Mr. SESSIONS (R; Alabama): I am proud of my junior, senator Shelby. 7 Mr. SHELBY (R; Alabama): To my senior peer, senator Sessions, I say great things. 8 Ms. PEABODY (I; Atlantis): This is just to fill space. 9 Mr. Quail (Q; Nowhere): Match this one, senator Shelby, with the senator before. 10 Ms. PEABODY (I; Atlantis): This is just to fill space. 11 Ms. PEABODY (I; Atlantis): This is just to fill space! 12 Ms. PEABODY (I; Atlantis): This is just to fill space? 13 Mr. SESSIONS (R; Alabama): Match this one with Quail.
注:第9行匹配的是前数第2行的Shelby
向后查找(最近的后序匹配)结果
1 Mr. SHELBY (R; Alabama): I acknowledge this is a test. 2 Mrs. MURRAY (D; Washington): I say to my friend, senator Shelby, that they are wrong. 3 Mr. SHELBY (R; Alabama): I do not agree with my colleague. 4 Mr. FRIST (R; Tennessee): senator Shelby is correct, senator Murray. 5 Mr. SHELBY (R; Alabama): I thank the majority leader for their support. 6 Mr. SESSIONS (R; Alabama): I am proud of my junior, senator Shelby. 7 Mr. SHELBY (R; Alabama): To my senior peer, senator Sessions, I say great things. 8 Ms. PEABODY (I; Atlantis): This is just to fill space. 9 Mr. Quail (Q; Nowhere): Match this one, senator Sessions, with the senator at the bottom. 10 Ms. PEABODY (I; Atlantis): This is just to fill space. 11 Ms. PEABODY (I; Atlantis): This is just to fill space! 12 Ms. PEABODY (I; Atlantis): This is just to fill space? 13 Mr. SESSIONS (R; Alabama): Match this one with Quail.
注:第6行匹配的是后数第7行的Shelby,第9行匹配的是后数第4行的Sessions
解决方案
核心思路:先标记所有Shelby/Sessions的行,再向前/向后填充这些标记,让每行对应最近的匹配项,最后根据标记替换目标字符串。
1. 向前查找(最近前序匹配)实现
test_df_lag <- test_df %>% # 标记当前行对应的参议员 mutate(senator = case_when( str_detect(speeches, "^Mr\\. SHELBY \\(R; Alabama\\):") ~ "Shelby", str_detect(speeches, "^Mr\\. SESSIONS \\(R; Alabama\\):") ~ "Sessions", TRUE ~ NA_character_ )) %>% # 向前填充NA,得到每行最近的前序参议员 fill(senator, .direction = "down") %>% # 替换目标字符串 mutate(speeches = ifelse( str_detect(speeches, regex("the senator from Alabama", ignore_case = TRUE)), str_replace(speeches, regex("the senator from Alabama", ignore_case = TRUE), str_c("senator ", senator)), speeches )) %>% select(-senator)
2. 向后查找(最近后序匹配)实现
test_df_lead <- test_df %>% mutate(senator = case_when( str_detect(speeches, "^Mr\\. SHELBY \\(R; Alabama\\):") ~ "Shelby", str_detect(speeches, "^Mr\\. SESSIONS \\(R; Alabama\\):") ~ "Sessions", TRUE ~ NA_character_ )) %>% # 向后填充NA,得到每行最近的后序参议员 fill(senator, .direction = "up") %>% mutate(speeches = ifelse( str_detect(speeches, regex("the senator from Alabama", ignore_case = TRUE)), str_replace(speeches, regex("the senator from Alabama", ignore_case = TRUE), str_c("senator ", senator)), speeches )) %>% select(-senator)
验证结果
运行上述代码后,test_df_lag会输出向前查找的期望结果,test_df_lead会输出向后查找的期望结果。
内容的提问来源于stack exchange,提问作者Rochelle
相关产品推荐
相关产品推荐

