R中日期的条件滞后-如果日期相同,如何编码跳到下一个日期?

j2cgzkjk  于 2023-02-01  发布在  其他
关注(0)|答案(3)|浏览(131)

我一直在研究如何有条件地延迟同一ID组中的日期变量,但如果下一个日期值与原始日期相同,则跳过它并延迟后面的日期值。

data have
ID Value Date
a 50 1987-01-01
a 52 1987-01-01
a 33 1989-05-03
b 10 1979-08-28
b 52 1988-02-23
b 45 1988-02-23
b 33 1988-02-23
b 40 1990-05-20

data want
ID Value Date Lead_date
a 50 1987-01-01 1989-05-03
a 52 1987-01-01 1989-05-03
a 33 1989-05-03 NA
b 10 1979-08-28 1988-02-23
b 52 1988-02-23 1990-05-20
b 45 1988-02-23 1990-05-20
b 33 1988-02-23 1990-05-20
b 40 1990-05-20 NA

我不确定是否有一种优雅的方法来实现这一点,或者我是否需要一个for循环?
任何建议都非常感谢!

zd287kbt

zd287kbt1#

1)findInterval将查找与当前日期匹配的最后一个日期的位置,因此只需加1即可获得下一个日期的位置。

library(data.table)

setDT(DF)
DF[, Lead_date := Date[findInterval(Date, Date) + 1], by = ID]

DF
##    ID Value       Date  Lead_date
## 1:  a    50 1987-01-01 1989-05-03
## 2:  a    52 1987-01-01 1989-05-03
## 3:  a    33 1989-05-03       <NA>
## 4:  b    10 1979-08-28 1988-02-23
## 5:  b    52 1988-02-23 1990-05-20
## 6:  b    45 1988-02-23 1990-05-20
## 7:  b    33 1988-02-23 1990-05-20
## 8:  b    40 1990-05-20       <NA>

**2)**另一种方法是获取Date与唯一日期匹配的位置,然后获取下一个唯一日期:

library(data.table)
setDT(DF)
DF[, Lead_date := { u <- unique(Date); u[match(Date, u) + 1] }, by = ID]

**3)**另一种方法是将重复的日期替换为NA,然后使用na.locf0在获取下一个日期时填充它们。

library(data.table)
library(zoo)

setDF(DF)
DF[, Lead_Date := replace(Date, duplicated(Date), NA) |>
                    na.locf0(fromLast = TRUE) |>
                    shift(-1), by = ID]

注解

Lines <- "ID Value Date
a 50 1987-01-01
a 52 1987-01-01
a 33 1989-05-03
b 10 1979-08-28
b 52 1988-02-23
b 45 1988-02-23
b 33 1988-02-23
b 40 1990-05-20"
DF <- read.table(text = Lines, header = TRUE)
DF$Date <- as.Date(DF$Date)
1mrurvl1

1mrurvl12#

do.call(rbind, lapply(split(d, d["ID"]),
                      function(x) {
                        ld <- rle(x$Date)
                        ld$values <- c(ld$values[-1], NA)
                        x$Lead_date <- inverse.rle(ld)
                        x}
                      
))

数据

d <- read.table(text="ID Value Date
a 50 1987-01-01
a 52 1987-01-01
a 33 1989-05-03
b 10 1979-08-28
b 52 1988-02-23
b 45 1988-02-23
b 33 1988-02-23
b 40 1990-05-20", header=TRUE)
ha5z0ras

ha5z0ras3#

你可以使用for循环来实现这个功能,但是在R中有一个更优雅的方法,使用dplyrdata.table包。

library(dplyr)
library(data.table)

df <- data.frame(ID = c("a", "a", "a", "b", "b", "b", "b", "b"),
                 Value = c(50, 52, 33, 10, 52, 45, 33, 40),
                 Date = as.Date(c("1987-01-01", "1987-01-01", "1989-05-03", "1979-08-28", "1988-02-23", "1988-02-23", "1988-02-23", "1990-05-20")))

df_lead_dates <- df %>% 
  group_by(ID, Value) %>% 
  slice_tail(n = 1) %>% 
  ungroup() %>% 
  rename(Lead_date = Date)

df %>% 
  left_join(df_lead_dates, by = c("ID", "Value", "Date")) %>% 
  mutate(Lead_date = ifelse(is.na(Lead_date), NA_real_, Lead_date))

它首先为每个IDValue组创建一个只包含最后一个日期的新数据框df_lead_dates。然后使用left_join函数将此数据框与原始数据框连接。最后,它将Lead_date列中的NA值替换为NA_real_。这是R中的特殊类型的缺失值,其指示缺少真实的值。

相关问题