【问题标题】:R: using for loops, apply, and which to select data based on dateR:使用for循环,应用,以及根据日期选择数据
【发布时间】:2014-09-24 18:44:46
【问题描述】:

假设我有一个由以下命令生成的日期向量:

dts<-seq(as.Date("2014-09-10"),as.Date("2014-09-20"),by="Days")

我还有一个用户 ID 和日期的数据框(其中时间戳列属于 Date 类):

>df
respondent_id  timestamp
           12 2014-09-19
           13 2014-09-11
           12 2014-09-20
            9 2014-09-16
           13 2014-09-15
           12 2014-09-18
           9  2014-09-15
           9  2014-09-16
           12 2014-09-20
           13 2014-09-14

我在这里的最终目标是在 dts 范围内统计所有在 24 小时内具有另一个时间戳的时间戳的用户。最后我会得到这样的东西:

>final

Date        Count
2014-09-10   0
2014-09-11   0
2014-09-12   0
2014-09-13   0
2014-09-14   0
2014-09-15   1
2014-09-16   2
2014-09-17   0
2014-09-18   0
2014-09-19   1
2014-09-20   1 

我最初的方法是遍历 dts 并使用 apply()which() 的组合来选择数据:

for (i in 1:length(dts)){
day1         <- apply(as.data.frame(df$timestamp),1,function(x) which(x>=dts[i]-1 & x<=dts[i],arr.ind=TRUE))
}
tmp1         <- df[day1,]
tmp11        <- as.data.frame(table(tdf$timestamp))
names(tmp11) <- c("Date","Count")
tmp11$Date   <- as.Date(tmp11$Date)

但这并不成功。变量 day1 是一个列表,因此不能用于子集数据框。使用命令unlist()as.data.frame() 会生成一个包含df 正确索引的数据框。我仍在过渡到使用 apply() 代替循环,因此非常感谢任何反馈。

【问题讨论】:

    标签: r for-loop apply


    【解决方案1】:
    library(data.table)
    dts<-data.table(timestamp=seq(as.POSIXct("2014-09-10"),as.POSIXct("2014-09-20"),by=60*60*24),key="timestamp")
    df<-data.table(respondent_id=c(12,13,12,9,13,12,9,9,12,13),timestamp=as.POSIXct(c("2014-09-19",
                                                                       "2014-09-11",
                                                                       "2014-09-20",
                                                                       "2014-09-16",
                                                                       "2014-09-15",
                                                                       "2014-09-18",
                                                                       "2014-09-15",
                                                                       "2014-09-16",
                                                                       "2014-09-20",
                                                                       "2014-09-14")),key="timestamp")
    
    #don't do this: df[dts,allow.cartesian=TRUE][,.N-1,by=timestamp]
    
    #do this:
    df[,.N,by=timestamp] # this gets you the nonzero counts
    dts[!(timestamp %in% df[,timestamp]),list(timestamp,N=0)] #this gives you all the missing dates where count is 0
    
    rbindlist(list(df[,.N,by=timestamp],dts[!(timestamp %in% df[,timestamp]),list(timestamp,count=0)]))[order(timestamp)] #this puts them all together.
    

    【讨论】:

    • 感谢您的回答。虽然我要在我提供的示例数据上成功运行您的解决方案,但我认为存在一些我不理解的细微差别,因为我无法将此解决方案推广到更大的数据集。在您的最后一行中,.N-1 表示什么? 1 代表一天(24 小时)吗?此外,当我使用tmp&lt;-data.table(df,key=timestamp) 后跟tmp$timestamp&lt;-as.POSIXct(tmp$timestamp) 时,我的时间戳实例是一个日期后跟一个时间,所有条目的时间都相同(太平洋夏令时间17:00:00)。这会导致子集问题吗?
    • @JMeo data.table 是一个非常强大的包,所以我建议阅读它的小插图和手册。语法是这样的[条件、列、分组]。 .N 表示计算分组中有多少行。
    • @JMeo 我假设您使用lubridate 来处理我认为data.table 可以使用的日期,所以不要同时将您的日期转换为POSIXct。我知道 data.table 无法处理 POSIXlt 对象,因为这些是列表。如果您想使用 POSIXct 对象并且它会将时间转移到 1700,那么我猜它与时区和本地化有关,所以将 tz="UTC" 添加到 as.POSIXct() 的末尾
    猜你喜欢
    • 2023-03-17
    • 2016-08-19
    • 2017-12-15
    • 1970-01-01
    • 1970-01-01
    • 2012-02-26
    • 2023-03-23
    • 1970-01-01
    • 2022-06-22
    相关资源
    最近更新 更多