我有一个数据框,如:
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
我想要做的是在Category
为" 1"时选择+ -10分钟的时间范围。
对于这种情况,由于category = 1
位于2013-11-02 08:07:25 AM
,我想选择07:57:25 AM to 08:17:25 AM
中的所有行。
处理此任务的最佳方法是什么?
此外,可能有多个" 1"对于每个时间框架。 (真正的数据框架更复杂,它包含多个不同用户的TimeStamp,即另一列名为" UserID")
答案 0 :(得分:10)
在基础R中,没有润滑或其他任何东西(假设您将TimeStamp转换为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
,那么您必须像以下一样循环播放:
check <- with(df,
lapply(TimeStamp[Category==1], function(x) abs(difftime(x,TimeStamp,units="mins")) <= 10 )
)
df[do.call(pmax, check)==1,]
答案 1 :(得分: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)
然后,剩下要做的就是按匹配事件运行foverlaps
和子集
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
答案 2 :(得分: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。
答案 3 :(得分: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
答案 4 :(得分: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格式。
答案 5 :(得分:1)
以下是dplyr
和lubridate
的解决方案。以下是步骤:
使用category ==1
的{{1}}与+
进行简单-
,找出lubridate
,minutes
和c(-1, 1) * minutes(10)
10分钟的位置然后使用filter
基于存储在rang
向量中的两个区间进行子集化。
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