在R中用across()为后缀_date的日期列批量叠加xdays值
问题:使用
across()批量处理后缀为_date的列,叠加xdays列数值生成新日期列 输入示例(df)
id xdays curation_date event_date 1 1 -4 2024-09-01 2024-07-04 2 2 10 2024-07-24 2024-06-13 3 3 7 2024-01-03 2023-12-03
预期输出(df1)
id xdays curation_date event_date manual_shift_curation_date manual_shift_event_date 1 1 -4 2024-09-01 2024-07-04 2024-08-28 2024-06-30 2 2 10 2024-07-24 2024-06-13 2024-08-03 2024-06-23 3 3 7 2024-01-03 2023-12-03 2024-01-10 2023-12-10
尝试的代码及错误
手动实现的代码可正常运行,但使用自定义函数结合across()的多种写法均报错:
#requirement - #add the value of df$xdays to any column that is named as a date (and output the result as a date) library(tidyverse) ################functions attempted # 1) include a parameter for the column with the date shift dateshift <- function(x,shiftcolumn) {as.Date(as.Date(x) + {{shiftcolumn}})} #shiftcolumn is actually a constant, but this is closest to working. # or # 2) just call the dateshift column within the function dateshift_nocol <- function(x) {as.Date(as.Date(x) + {{xdays}})} #example dataframe df <- data.frame(id=c(1,2,3), xdays=c(-4, 10, 7), curation_date=c('2024-09-01','2024-07-24','2024-01-03'), event_date=c('2024-07-04','2024-06-13','2023-12-03') ) ###############manaully shift date to show expected results df1 <- df %>% mutate(manual_shift_curation_date=as.Date(as.Date(curation_date)+xdays), manual_shift_event_date =as.Date(as.Date(event_date)+xdays)) #works ###############using dateshift passing the constant column as a parameter df2 <- df %>% mutate(across(matches("date"), dateshift(.,shiftcolumn=xdays), .names = "shifted_{.col}")) #renamed for qc check #error: Caused by error in `as.Date.default()`:! do not know how to convert 'x' to class “Date” df3 <- df %>% mutate(across(matches("date"), ~ apply(., 1, dateshift))) #error: Caused by error in `apply()`:! dim(X) must have a positive length ###################using dateshift_nocol (without passing the constant column value) df4 <- df %>% mutate(across(matches("date"), dateshift_nocol, .names = "shifted_{.col}")) #renamed for qc check # Caused by error in `across()`:! Can't compute column `shifted_curation_date`. Caused by error: ! object 'xdays' not found df5 <- df %>% mutate(across(matches("date"), ~ apply(., 1, dateshift_nocol))) #error: Caused by error in `apply()`:! dim(X) must have a positive length
解决方案
方法1:直接在across()中使用lambda表达式(无需自定义函数)
这是最简洁的实现方式,避免函数作用域问题:
df_result <- df %>% mutate(across(ends_with("_date"), ~ as.Date(as.Date(.x) + xdays), .names = "manual_shift_{.col}"))
- 用
ends_with("_date")精准匹配后缀为_date的列 ~定义lambda函数,.x代表当前处理的日期列,xdays可直接引用数据框内的列
方法2:修正自定义函数的参数传递
若需保留自定义函数,可通过两种方式修复:
方式A:使用.data代词明确作用域
dateshift <- function(x) { as.Date(as.Date(x) + .data$xdays) } df_result <- df %>% mutate(across(ends_with("_date"), dateshift, .names = "manual_shift_{.col}"))
方式B:显式传递xdays参数
dateshift <- function(x, shift_col) { as.Date(as.Date(x) + shift_col) } df_result <- df %>% mutate(across(ends_with("_date"), ~ dateshift(.x, shift_col = xdays), .names = "manual_shift_{.col}"))
错误原因解析
df2错误:直接调用dateshift(.,shiftcolumn=xdays)会把整个数据框传给x参数,而非当前处理的列,需用lambda函数传递单个列df3/df5错误:apply用于矩阵/数组处理,而across处理的是向量列,日期向量加数值向量本身就是逐行运算,无需额外嵌套applydf4错误:自定义函数dateshift_nocol中的{{xdays}}无法找到数据框内的xdays,函数不在数据框作用域内,需用.data代词或显式传参
内容的提问来源于stack exchange,提问作者Lauren Gigliotti
相关产品推荐
相关产品推荐

