根据 R 中的两个日期/时间列,在给定用户 ID 的列中选取一个值

Pick a value in a column for a given User ID based on two date/time columns in R

提问人:Hack-R 提问时间:7/15/2014 最后编辑:CommunityHack-R 更新时间:7/17/2014 访问量:117

问:

我有一个包含时间戳、列和状态的数据框。每个用户 ID 都有一个创建时间戳、多个日期以及每个日期的不同状态。user ID'screationdate

我需要选择与创建日期之前(或当天)的最近日期相对应的状态。我的数据如下所示:

userid    creation               date        status
0001    2014-01-01 03:30:50    2013-01-12    Red
0001    2014-01-01 12:31:12    2011-01-01    Blue
0001    2014-01-01 03:30:50    2014-05-01    Green
0002    2013-12-31 03:30:50    NA            NA
0003    2013-11-11 03:30:50    2013-11-11    Purple
0003    2013-11-11 03:30:50    2012-01-01    Red

创建时间戳和日期均为 。class "POSIXct" "POSIXt"

我对如何做到这一点感到困惑。我很想使用这个包,但即使在SQL中,我也不确定如何查询它。数据中也有 NA,只是为了让事情更有趣。sqldf

我发现了一些半相关的帖子,例如:在 R 中匹配多个日期值,但没有一个足够接近,我可以用作解决方案。

我要的输出示例是:

userid    initial_status
0001      Red
0002      NA
0003      Purple

我刚刚将 status 重命名为 initial_status(尽管这不是必需的——它可以称为 status)。

我来得最近...这显然在不止一个方面是错误的......是

initial_status <- sqldf("select distinct user_id, status as initial_status, date from x where date <= creation group by user_id")

我会使用而不是在该查询中,但是当我这样做时,它会将日期戳更改为一些奇怪的,不直观的数字(也许是因为它必须更改要使用的类)。max(date)datesqldfnumbericmax

R 匹配

评论

0赞 ccapizzano 7/15/2014
您能否根据提供的表格提供所需输出的示例?

答:

1赞 rrs 7/15/2014 #1

假设您的数据位于一个名为df

library(lubridate)
df$creation <- ymd_hms(df$creation)  # convert to date-time
df$date <- ymd(df$date)

library(dplyr)
df %>%
  group_by(userid) %>%  # group by userid
  filter(date <= creation) %>%  # filter by date prior to (or on) creation
  filter(row_number(creation) == 1) %>%  # filter by min creation (see ?row_number)
  select(userid, initial_status = status) # select status variable and rename

评论

0赞 Hack-R 7/16/2014
谢谢。我几乎可以接受你在这里所拥有的东西,并在此基础上得到我的解决方案,但@fxi似乎有一个解决方案,所以我会把他标记为正确答案。这是使用创建的行号,但是对于给定的用户 ID,每行的创建都是相同的,我需要它来查找 <= 创建的 min(date),这与此略有不同。不过,我喜欢你使用的是 dplyr;我知道这是一个非常强大的工具。
0赞 rrs 7/16/2014
啊,我误解了你需要什么。
0赞 rrs 7/16/2014
我更新了我的答案;但是,它会过滤掉用户,因为用户在创建之前没有日期。0002
0赞 Hack-R 7/16/2014
谢谢,现在这是一个很好的解决方案。我会投赞成票。
2赞 fxi 7/15/2014 #2

源:

dat<-"userid    creation    date    status
0001    2014-01-01 03:30:50    2013-01-12    Red
0001    2014-01-01 12:31:12    2011-01-01    Blue
0001    2014-01-01 03:30:50    2014-05-01    Green
0002    2013-12-31 03:30:50    NA    NA
0003    2013-11-11 03:30:50    2013-11-11    Purple
0003    2013-11-11 03:30:50    2012-01-01    Red"
dat<-gsub(pattern = '\\s{4}',',',dat)
dat<-read.table(textConnection(dat),sep = ",",header = T)
dat$creation <-as.POSIXct(dat$creation)
dat$date <- as.POSIXct(dat$date)

使用 data.table,将 NA in date 保留为最高值。

library(data.table)
# convert to data.table
dat<-as.data.table(dat)
# sort and index
setkey(dat,userid,date,creation)
# ask for the status which have the max date, by userid.
dat2<-dat[date<creation | is.na(date)][,list(statusOut=
                                               if(anyNA(date)){'noValue'
                                               }else{
                                                 as.character(.SD[which.max(date)]$status)
                                               }
                                             ),by='userid']

输出

   userid statusOut
1:      1       Red
2:      2   noValue
3:      3    Purple

评论

0赞 Hack-R 7/16/2014
谢谢!这似乎是解决方案,因为它包含所有必要的逻辑。我感谢您的帮助,并将实施这一点。
0赞 fxi 7/16/2014
De nada.如果某些东西没有按预期工作,请随时寻求更多帮助:我无法访问您的所有数据,在某些情况下,此解决方案可能不是最佳解决方案。