2015-06-24 130 views
7

内选择行我有这样一个数据帧:一个特定的时间范围

TimeStamp     Category 

2013-11-02 07:57:18 AM   0 
2013-11-02 08:07:19 AM   0 
2013-11-02 08:07:21 AM   0 
2013-11-02 08:07:25 AM   1 
2013-11-02 08:07:29 AM   0 
2013-11-02 08:08:18 AM   0 
2013-11-02 08:09:20 AM   0 
2013-11-02 09:04:18 AM   0 
2013-11-02 09:05:22 AM   0 
2013-11-02 09:07:18 AM   0 

我想要做的是选择+ -10分钟的时间框架时Category为“1”。

对于这种情况,因为category = 12013-11-02 08:07:25 AM,我想选择07:57:25 AM to 08:17:25 AM中的所有行。

处理此任务的最佳方法是什么?

此外,每个时间帧可能有多个“1”。 (真正的数据帧是更复杂的是,它包含多个时间戳和不同的用户,即有一个名为“用户名”的另一列)

+5

现在所有剩下的事情就是我猜的所有答案中的一些史诗般的benchamrk。 –

+3

@DavidArenburg - 我知道我的答案会落在哪里;-)我依靠计算能力呈指数增长,或者人们需要在代码运行期间每隔几个小时就喝一杯咖啡。 – thelatemail

回答

10

在基础R,而无需lubridate-ING或其他任何东西(假设你将时间戳转换为POSIXct对象),如:

df$TimeStamp <- as.POSIXct(TimeStamp, format = "%Y-%m-%d %I:%M:%S %p") 
df[with(df, abs(difftime(TimeStamp[Category==1],TimeStamp,units="mins")) <= 10),] 

#   TimeStamp Category 
#2 2013-11-02 08:07:19  0 
#3 2013-11-02 08:07:21  0 
#4 2013-11-02 08:07:25  1 
#5 2013-11-02 08:07:29  0 
#6 2013-11-02 08:08:18  0 
#7 2013-11-02 08:09:20  0 

如果你有多个1's,你必须循环它:

check <- with(df, 
    lapply(TimeStamp[Category==1], function(x) abs(difftime(x,TimeStamp,units="mins")) <= 10) 
) 
df[do.call(pmax, check)==1,] 
4

这似乎工作:

数据:

按@DavidArenburg “(和在他的回答中提到)的评论到timestamp列转换为POSIXct对象的正确方法是(如果没有的话):

df$TimeStamp <- as.POSIXct(df$TimeStamp, format = "%Y-%m-%d %I:%M:%S %p") 

解决方案:

library(lubridate) #for minutes 
library(dplyr)  #for between 
pickrows <- function(df) { 
    #pick category == 1 rows 
    df2 <- df[df$Category==1,] 
    #for each timestamp create two variables start and end 
    #for +10 and -10 minutes 
    #then pick rows between them 
    lapply(df2$TimeStamp, function(time) { 
     start <- time - minutes(10) 
     end <- time + minutes(10) 
     df[between(df$TimeStamp, start, end),] 
    }) 
} 

#run function 
pickrows(df) 

输出:

> pickrows(df) 
[[1]] 
      TimeStamp Category 
2 2013-11-02 08:07:19  0 
3 2013-11-02 08:07:21  0 
4 2013-11-02 08:07:25  1 
5 2013-11-02 08:07:29  0 
6 2013-11-02 08:08:18  0 
7 2013-11-02 08:09:20  0 

请记住,在多个Category==1行的情况下输出,我的函数的输出将是一个列表(在此ocassion它只有一个元素),所以do.call(rbind, pickrows(df))将需要将所有内容组合在一个data.frame中。

+0

Hi @DavidArenburg。是的,在我的R会话中,但自从他的时间戳列有确切的默认'POSIXct'格式,我认为它就像他的data.frame。在我们的案例中,我们将其作为文本阅读这就是为什么'输入'更好。 – LyzandeR

+0

@DavidArenburg是的,这是在我的脚本时,我构建了我的答案,它的工作原理:'df $ TimeStamp < - as.POSIXct(df $ TimeStamp)' – LyzandeR

+1

@DavidArenburg我会假设他的时间戳是正确的,以后没有PM(上午)。您在回答中添加了数据清理过程,但这并不是必需的。没有证据表明他的时间格式后来出问题了。 – LyzandeR

7

这是我将如何处理这一使用data.table::foverlaps

首先,转换TimeStamp到一个适当的POSIXct

library(data.table) 
setDT(df)[, TimeStamp := as.POSIXct(TimeStamp, format = "%Y-%m-%d %I:%M:%S %p")] 

然后我们将创建一个临时的数据集,其中Category == 1加入反对。我们也将通过这两个“开始”和“结束”列上创建一个“终点”栏和key

df2 <- setkey(df[Category == 1L][, TimeStamp2 := TimeStamp], TimeStamp, TimeStamp2) 

然后,我们会做同样的df但将设置间隔10分钟

setkey(df[, `:=`(start = TimeStamp - 600, end = TimeStamp + 600)], start, end) 

于是,所有剩下的工作是匹配的发生率

indx <- foverlaps(df, df2, which = TRUE, nomatch = 0L)$xid 
df[indx, .(TimeStamp, Category)] 
#    TimeStamp Category 
# 1: 2013-11-02 08:07:19  0 
# 2: 2013-11-02 08:07:21  0 
# 3: 2013-11-02 08:07:25  1 
# 4: 2013-11-02 08:07:29  0 
# 5: 2013-11-02 08:08:18  0 
# 6: 2013-11-02 08:09:20  0 
1

这是我与dplyr和解决方案来运行foverlaps和子集。下面是步骤:

查找其中category ==1,与lubridateminutes使用filter简单c(-1, 1) * minutes(10)然后到子集基于存储在rang矢量两个间隔添加到此,+- 10分钟。

library(lubridate) 
library(dplyr) 
wi1 <- which(dat$Category == 1) 
rang <- dat$TimeStamp[wi1] + c(-1,1) * minutes(10) 
dat %>% filter(TimeStamp >= rang[1] & TimeStamp <= rang[2]) 
      TimeStamp Category 
1 2013-11-02 08:07:19  0 
2 2013-11-02 08:07:21  0 
3 2013-11-02 08:07:25  1 
4 2013-11-02 08:07:29  0 
5 2013-11-02 08:08:18  0 
6 2013-11-02 08:09:20  0 
4

使用lubridate:

df$TimeStamp <- ymd_hms(df$TimeStamp) 
span10 <- (df$TimeStamp[df$Category == 1] - minutes(10)) %--% (df$TimeStamp[df$Category == 1] + minutes(10)) 
df[df$TimeStamp %within% span10,] 
      TimeStamp Category 
2 2013-11-02 08:07:19  0 
3 2013-11-02 08:07:21  0 
4 2013-11-02 08:07:25  1 
5 2013-11-02 08:07:29  0 
6 2013-11-02 08:08:18  0 
7 2013-11-02 08:09:20  0 
+0

我真的很喜欢你的解决方案!感谢您发帖,我甚至不知道% - %。 – SabDeM

+0

thx。非常有用的速记创建间隔。 –

3

我个人很喜欢@thelatemail基本R答案的简单性。但只是为了好玩,我会提供另一个答案,使用滚动连接data.table,而不是重叠范围连接由@DavidArenburg提供的解决方案。

require(data.table) 
dt_1 = dt[Category == 1L] 
setkey(dt, TimeStamp) 

ix1 = dt[.(dt_1$TimeStamp - 600L), roll=-Inf, which=TRUE] # NOCB 
ix2 = dt[.(dt_1$TimeStamp + 600L), roll= Inf, which=TRUE] # LOCF 

indices = data.table:::vecseq(ix1, ix2-ix1+1L, NULL) # not exported function 
dt[indices] 
#    TimeStamp Category 
# 1: 2013-11-02 08:07:19  0 
# 2: 2013-11-02 08:07:21  0 
# 3: 2013-11-02 08:07:25  1 
# 4: 2013-11-02 08:07:29  0 
# 5: 2013-11-02 08:08:18  0 
# 6: 2013-11-02 08:09:20  0 

这应该只是罚款,即使你有一个以上的小区,其中Category是1,AFAICT。将此作为data.table这种类型的操作的功能包装起来会很棒......

PS:参考将TimeStamp转换为POSIXct格式的其他帖子。

相关问题