R语言dplyr如何正确设置Mutate选项提取行内第二个匹配字段
问题原因
你的代码存在两个核心问题,导致无法得到正确结果:
- 正则匹配规则不符合var2的特征:var2的取值是
newyork 6/newyork7/newyork8这类开头为字母、内容包含数字的字符串,你之前用的str_detect(.x, "^\\d")仅能匹配开头为数字的字符串,完全捕获不到var2对应的值。 - 第二个值的提取逻辑错误:三行数据中第一个以数字开头的地址(即var1)所在列并不固定(第一行在col2、第二行在col3、第三行在col4),你固定从col3开始向后查找非NA值,会把第二行col3的var1值错当成var2,无法实现「逐行取第二个符合条件值」的需求。
另外你数据里的缺失值是字符串类型的"NA",不是R语言原生识别的NA类型,coalesce函数会把它当成普通字符串处理,也会干扰匹配结果。
修正代码
推荐用逐行处理的方案,逻辑最清晰,后续扩展也方便,不需要拆分多个步骤:
library(tidyverse) desired_result <- sample_data %>% rowwise() %>% mutate( # 逐行提取col2到col5中,不等于"NA"、且包含数字的所有值,按原列顺序存储 match_set = c_across(col2:col5)[. != "NA" & str_detect(., "\\d")], var1 = match_set[1], var2 = match_set[2] ) %>% select(col1, var1, var2) %>% ungroup()
运行后得到的结果和你给出的目标格式完全一致:
# A tibble: 3 × 3 col1 var1 var2 <chr> <chr> <chr> 1 james 123 forest road newyork 6 2 john 124 valley street newyork7 3 henry 125 ocean road newyork8
如果你要沿用之前coalesce的写法,需要先把字符串"NA"转成原生NA,提取完var1后,把每行var1对应的单元格替换为NA,再做第二次匹配,注意修正var2的匹配正则:
library(tidyverse) # 先把字符串"NA"转成R可识别的缺失值 clean_data <- sample_data %>% mutate(across(col2:col5, ~na_if(.x, "NA"))) result <- clean_data %>% # 提取第一个开头为数字的值var1 mutate( across(col2:col5, ~case_when(str_starts(.x, "\\d") ~ .x, TRUE ~ NA_character_)), var1 = coalesce(col2, col3, col4, col5) ) %>% # 移除已匹配的var1,提取第二个包含数字的值var2 mutate( across(col2:col5, ~case_when(. == var1 ~ NA_character_, str_detect(.x, "\\d") ~ .x, TRUE ~ NA_character_)), var2 = coalesce(col2, col3, col4, col5) ) %>% select(col1, var1, var2)
这个写法同样可以得到正确结果,但灵活性较差,如果后续需要提取第3、第4个匹配值,需要重复写多轮替换逻辑,不如逐行提取的方案简洁。
内容的提问来源于stack exchange,提问作者stats_noob
相关产品推荐
相关产品推荐

