【问题标题】:Return value if column heading falls between two dates如果列标题位于两个日期之间,则返回值
【发布时间】:2019-10-23 13:38:35
【问题描述】:

我有两个数据框 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 数据框的列标题中指定的日期介于 @ 中的两个日期之间987654329@ 数据框。根据上面的例子,它看起来像这样:

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=2Attendance 中的日期与 ID_list 中的日期不重叠 - 这是错误还是我误解了?
  • @Ben 谢谢,这是一个错字 - 现在更正了。

标签: r dplyr left-join lubridate


【解决方案1】:

您可以在这里做几件事来解决您的问题。

首先,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

希望对你有帮助!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-23
    • 1970-01-01
    • 2021-01-28
    • 1970-01-01
    • 2015-07-05
    • 2018-06-28
    相关资源
    最近更新 更多