Return 列标题介于两个日期之间时的值

Return value if column heading falls between two dates

我有两个数据帧 ID_listAttendance:

ID_list 包含唯一 ID 的列表、他们的出生日期和他们生命中随后几年的生日

ID DOB         Y1          Y2          Y3
1  01/05/2003  01/05/2004  01/05/2005  01/05/2006
2  05/02/2010  05/02/2011  05/02/2012  05/02/2013
3  17/06/2015  17/06/2016  17/06/2017  17/06/2018

Attendance 包含一个 ID 列表,其中一些与 ID_list 中的 ID 和不同日期的出席率数字相匹配:

ID  01/07/2010  01/07/2011  01/07/2012
4   100%        50%         75%
2   60%         40%         30%
6   80%         60%         100%

我想生成一个新的数据框,其中包含 ID 列表及其生命中每一年的出勤率,其中 Attendance 数据框中列标题中指定的日期介于两个之间ID_List 数据框中的日期。基于上面的示例,它看起来像这样:

ID  Y1_att  Y2_att  Y3_att
1   NA      NA      NA
2   60%     40%     30%
3   NA      NA      NA

我一直在尝试使用 %within%interval 函数结合 mutate:

ID_all <- left_join(ID_list, Attendance, by = ID)
ID_all <- mutate(ID_all, Y1_att = ifelse(**column name** %within% interval(DOB, Y1), **value from column name**, NA)

其中星号中的值取自 Attendance 数据框。然后的想法是遍历取自 Attendance 数据框的列,但我不确定如何在计算中使用它的同时在 mutate 函数中引用列,或者是否有更好的方法这样做的方法比从一开始就加入两个数据帧。

您可以在此处执行多种操作来解决您的问题。

首先,ID_list 并不是很有用,因为生日通常恰好以一年分隔,因此您可以自动检索该值。其次,出勤数据集的格式不适合您想要实现的目标:它很宽(列的数量可能会密集增加)并且更容易处理。

为此,您可以使用包 tidyr 中的新函数 pivot_longerpivot_wider(之前名为 gatherspread) .

library(lubridate)
library(tidyverse)

ID_list = read.table(text = "
ID DOB         Y1          Y2          Y3
1  01/05/2003  01/05/2004  01/05/2005  01/05/2006
2  05/02/2010  05/02/2011  05/02/2012  05/02/2013
3  17/06/2015  17/06/2016  17/06/2017  17/06/2018
", header=T) 

Attendance = read.table(text = "
ID  01/07/2010  01/07/2011  01/07/2012
4   100%        50%         75%
2   60%         40%         30%
6   80%         60%         100%
", header=T) 


Attendance_long = Attendance %>% 
  pivot_longer(-ID, names_to = "date", values_to = "percent") %>% 
  mutate(date=date %>% str_remove("X") %>% str_replace_all("\.", "/") %>% as.Date("%d/%m/%Y")) #dates as columns behave badly, needs refactoring :-(
Attendance_long

# A tibble: 9 x 3
#     ID date       percent
#  <int> <date>     <fct>  
#1     4 2010-07-01 100%   
#2     4 2011-07-01 50%    
#3     4 2012-07-01 75%    
#4     2 2010-07-01 60%    
#5     2 2011-07-01 40%    
#6     2 2012-07-01 30%    
#7     6 2010-07-01 80%    
#8     6 2011-07-01 60%    
#9     6 2012-07-01 100%    

有了长格式的出勤率,您现在可以加入数据并计算出勤日期和出生日期(上限)之间的差值年数。然后,为了达到您的预期输出,您可以再次转向宽格式并删除不必要的列。

ID_all = ID_list %>% as_tibble %>% 
  select(ID, DOB) %>% #don't need other columns
  left_join(Attendance_long, by="ID") %>% 
  mutate_at(vars(DOB), as.Date, format="%d/%m/%Y") %>% 
  mutate(year = ceiling(interval(DOB, date) / years(1)),
         year = ifelse(!is.na(year), paste0("Y", year, "_att"), year))%>% 
  select(-date) %>% #important to pivot
  pivot_wider(names_from = year,
              values_from = percent) %>% 
  select(-`NA`, -DOB) 

ID_all

希望对您有所帮助!