在tidyr::pivot_longer中提取字符串中间首个数字的正则问题
解决tidyr::pivot_longer的names_pattern正则分组错误问题
问题背景
需要提取drink_type_1_Day_7、drink_vol_1_Day_7这类字段名中间的首个数字(范围1-10),完成pivot_longer数据转换。此前无Day_7后缀时用(.*)(.*)实现,但传入\d+作为names_pattern参数时,出现错误提示:
regex should define 2 groups; 1 found
希望通过构建包含两组的正则表达式(组1存储数字前缀内容,组2存储目标数字)解决问题,测试代码如下:
library(tidyr) study_id <- c(1,2,3,4,5,6) drink_type_1_Day_7 <-c(1,2,3,1,2,3) drink_vol_1_Day_7 <- c(100,500,1000,100,500,750) drink_type_2_Day_7 <-c(NA,3,2,1,NA,3) drink_vol_2_Day_7 <- c(NA,125,300,200,NA,500) drink_df <- data.frame(study_id,drink_type_1_Day_7,drink_vol_1_Day_7,drink_type_2_Day_7,drink_vol_2_Day_7) drink_df <- drink_df %>% mutate_at(c('drink_type_1_Day_7','drink_type_2_Day_7'), as.factor) drink_df_pivot <- drink_df %>% pivot_longer(cols = starts_with("drink"), names_to = c(".value", "drink"), names_pattern = " ") %>% dplyr::group_by(study_id, drink_type) %>% dplyr:: summarise(drink_vol = sum(na_if(drink_vol,0), na.rm = TRUE), .groups = "drop") %>% pivot_wider(names_from = drink_type, values_from = drink_vol, names_prefix = "drink_vol_", values_fill = 0) %>% ungroup() %>% select(-contains("NA"))
解决方案
错误原因是names_to = c(".value", "drink")指定了两个目标元素,因此names_pattern必须包含两个捕获组,分别对应这两个元素:
- 第一个组对应
.value:字段名中数字之前的部分(如drink_type、drink_vol),后续会作为转换后的列名 - 第二个组对应
drink:需要提取的1-10数字部分
针对你的字段格式,可使用以下正则表达式:
"(.*)_([1-9]|10)_Day_7"
(.*):捕获数字前的所有内容(直到最后一个下划线)([1-9]|10):精准匹配1-10的数字(单独的1-9,或完整的10)_Day_7:匹配固定后缀,确保只处理目标字段
修改后的完整代码如下:
library(tidyr) library(dplyr) study_id <- c(1,2,3,4,5,6) drink_type_1_Day_7 <-c(1,2,3,1,2,3) drink_vol_1_Day_7 <- c(100,500,1000,100,500,750) drink_type_2_Day_7 <-c(NA,3,2,1,NA,3) drink_vol_2_Day_7 <- c(NA,125,300,200,NA,500) drink_df <- data.frame(study_id,drink_type_1_Day_7,drink_vol_1_Day_7,drink_type_2_Day_7,drink_vol_2_Day_7) drink_df <- drink_df %>% mutate_at(c('drink_type_1_Day_7','drink_type_2_Day_7'), as.factor) drink_df_pivot <- drink_df %>% pivot_longer(cols = starts_with("drink"), names_to = c(".value", "drink"), names_pattern = "(.*)_([1-9]|10)_Day_7") %>% group_by(study_id, drink_type) %>% summarise(drink_vol = sum(na_if(drink_vol,0), na.rm = TRUE), .groups = "drop") %>% pivot_wider(names_from = drink_type, values_from = drink_vol, names_prefix = "drink_vol_", values_fill = 0) %>% ungroup() %>% select(-contains("NA"))
执行后即可正确提取数字并完成数据转换,解决正则分组不匹配的问题。
内容的提问来源于stack exchange,提问作者GJW
相关产品推荐
相关产品推荐

