如何比较多日期列中指定日期对并提取对应索引?
问题需求
我有一个包含日期列的数据框,其中date_ind列表示date_col列的列索引。需要按每行date_ind指定的日期列对进行比较,找出其中较早的日期,并获取该日期对应的date_ind值。若日期相同,则选择较小的索引。目前已能获取较早日期,但不知如何提取对应的date_ind值,寻求解决方法。
示例说明
- 第1行
date_ind1=1、date_ind3=4,需比较date_col1和date_col4,date_col4更早,对应earlier_date_ind为4; - 第2行
date_ind1=1、date_ind2=2,比较date_col1和date_col2,date_col2更早,对应索引为2。
数据
set.seed(123) df <- data.frame( date_ind1 = c(1, 1, 3, 1, 1, 3, 2, 1), date_ind2 = c(NA, 2, NA, NA, 2, NA, 3, 4), date_ind3 = c(4, NA, 1, 2, NA, 1, NA, NA), date_col1 = sample(seq(as.Date("2000-01-01"), as.Date("2000-1-31"), by="day"), 8), date_col2 = sample(seq(as.Date("2000-01-01"), as.Date("2000-1-31"), by="day"), 8), date_col3 = sample(seq(as.Date("2000-01-01"), as.Date("2000-1-31"), by="day"), 8), date_col4 = sample(seq(as.Date("2000-01-01"), as.Date("2000-1-31"), by="day"), 8) ) > df date_ind1 date_ind2 date_ind3 date_col1 date_col2 date_col3 date_col4 1 1 NA 4 2000-01-31 2000-01-11 2000-01-27 2000-01-10 2 1 2 NA 2000-01-15 2000-01-05 2000-01-25 2000-01-09 3 3 NA 1 2000-01-19 2000-01-20 2000-01-28 2000-01-19 4 1 NA 2 2000-01-14 2000-01-14 2000-01-30 2000-01-04 5 1 2 NA 2000-01-03 2000-01-22 2000-01-09 2000-01-14 6 3 NA 1 2000-01-10 2000-01-25 2000-01-03 2000-01-17 7 2 3 NA 2000-01-18 2000-01-30 2000-01-08 2000-01-11 8 1 4 NA 2000-01-22 2000-01-19 2000-01-07 2000-01-07
已尝试代码
library(dplyr) col_names1 <- paste0("date_col", df$date_ind1) col_names2 <- paste0("date_col", coalesce(df$date_ind2, df$date_ind3)) df$earlier_date <- sapply(1:nrow(df), function(i) min(df[ i, col_names1[i] ], df[ i, col_names2[i] ]) ) |> as.Date()
期望结果
date_ind1 date_ind2 date_ind3 date_col1 date_col2 date_col3 1 1 NA 4 2000-01-31 2000-01-11 2000-01-27 2 1 2 NA 2000-01-15 2000-01-05 2000-01-25 3 3 NA 1 2000-01-19 2000-01-20 2000-01-28 4 1 NA 2 2000-01-14 2000-01-14 2000-01-30 5 1 2 NA 2000-01-03 2000-01-22 2000-01-09 6 3 NA 1 2000-01-10 2000-01-25 2000-01-03 7 2 3 NA 2000-01-18 2000-01-30 2000-01-08 8 1 4 NA 2000-01-22 2000-01-19 2000-01-07 date_col4 earlier_date earlier_date_ind 1 2000-01-10 2000-01-10 4 2 2000-01-09 2000-01-05 2 3 2000-01-19 2000-01-19 1 4 2000-01-04 2000-01-14 1 5 2000-01-14 2000-01-03 1 6 2000-01-17 2000-01-03 3 7 2000-01-11 2000-01-08 3 8 2000-01-07 2000-01-07 4
解决方案
可以在逐行处理时,同时比较日期和对应的索引,一次性返回结果。以下提供两种实现方式:
方式1:使用dplyr的rowwise逐行处理
library(dplyr) df_result <- df %>% rowwise() %>% mutate( # 获取当前行需要比较的两个date_ind值 ind1 = date_ind1, ind2 = coalesce(date_ind2, date_ind3), # 获取对应的日期值 date1 = get(paste0("date_col", ind1)), date2 = get(paste0("date_col", ind2)), # 确定更早的日期和对应的索引 earlier_date = min(date1, date2), earlier_date_ind = case_when( date1 < date2 ~ ind1, date2 < date1 ~ ind2, TRUE ~ min(ind1, ind2) # 日期相同时选较小的索引 ) ) %>% ungroup() %>% select(-ind1, -ind2, -date1, -date2) # 移除中间辅助列 # 查看结果 print(df_result)
方式2:沿用原sapply思路扩展
library(dplyr) result_list <- sapply(1:nrow(df), function(i) { ind1 <- df$date_ind1[i] ind2 <- coalesce(df$date_ind2[i], df$date_ind3[i]) date1 <- df[i, paste0("date_col", ind1)] date2 <- df[i, paste0("date_col", ind2)] if (date1 < date2) { list(earlier_date = date1, earlier_date_ind = ind1) } else if (date2 < date1) { list(earlier_date = date2, earlier_date_ind = ind2) } else { list(earlier_date = date1, earlier_date_ind = min(ind1, ind2)) } }) # 将列表转成数据框并合并到原数据 df$earlier_date <- as.Date(sapply(result_list, function(x) x$earlier_date)) df$earlier_date_ind <- sapply(result_list, function(x) x$earlier_date_ind) print(df)
两种方式都能生成符合要求的结果,满足日期相同时选择较小索引的规则。
内容的提问来源于stack exchange,提问作者nightstand
相关产品推荐
相关产品推荐

