簡體   English   中英

選擇特定時間范圍內的行

[英]Select rows within a particular time range

我有一個像這樣的數據框:

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 = 12013-11-02 08:07:25 AM ,所以我想選擇07:57:25 AM to 08:17:25 AM內的所有行。

處理此任務的最佳方法是什么?

此外,每個時間范圍可能會有多個“ 1”。 (實際數據幀更加復雜,它包含多個具有不同用戶的TimeStamp,即還有一個名為“ UserID”的列)

在基礎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,]

這是我將如何使用data.table::foverlaps來解決這個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

這似乎可行:

數據:

根據@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行,則輸出,我的函數的輸出將是一個列表(在這種情況下,它只有一個元素),因此需要do.call(rbind, pickrows(df))將所有內容組合到一個data.frame中。

使用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

我個人喜歡@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操作的功能data.table ...

PS:請參閱其他文章,以將TimeStamp轉換為POSIXct格式。

這是我用dplyrlubridate解決方案。 步驟如下:

發現其中category ==1 ,添加到這個, +- 10分鍾與lubridateminutes以簡單的c(-1, 1) * minutes(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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM