2014-12-21 82 views
9

每n分鐘我有一個包含10個事件在某一時間在給定的一天存在的一個數據集,其中每個事件相應的值:分組與dplyr

d1 <- data.frame(date = as.POSIXct(c("21/05/2010 19:59:37", "21/05/2010 08:40:30", 
          "21/05/2010 09:21:00", "21/05/2010 22:29:50", "21/05/2010 11:27:34", 
          "21/05/2010 18:25:14", "21/05/2010 15:16:01", "21/05/2010 09:41:53", 
          "21/05/2010 15:01:29", "21/05/2010 09:02:06"), format ="%d/%m/%Y %H:%M:%S"), 
       value = c(11313,42423,64645,643426,1313313,1313,3535,6476,11313,9875)) 

欲聚合的結果,每3分鐘,以標準數據幀格式(從「21/05/2010 00:00:00」到「21/05/2010 23:57:00」,以便數據幀具有每個3分鐘的480個分檔)

第一個,我創建了一個包含每個分鐘爲3分鐘的數據幀:

d2 <- data.frame(date = seq(as.POSIXct("2010-05-21 00:00:00"), 
          by="3 min", length.out=(1440/3))) 

然後,我合併兩個dataframes在一起,並刪除來港:

library(dplyr) 
m <- merge(d1, d2, all=TRUE) %>% mutate(value = ifelse(is.na(value),0,value)) 

最後,我用period.apply()xts包值相加每個箱:

library(xts) 
a <- period.apply(m$value, endpoints(m$date, "minutes", 3), sum) 

有沒有更有效如何做到這一點?它感覺不到最佳。

更新#1

我調整我的代碼約書亞的答案後:

library(xts) 
startpoints <- function (x, on = "months", k = 1) { 
    head(endpoints(x, on, k) + 1, -1) 
} 

m <- seq(as.POSIXct("2010-05-21 00:00:00"), by="3 min", length.out=1440/3) 
x <- merge(value=xts(d1$value, d1$date), xts(,m)) 
y <- period.apply(x, c(0,startpoints(x, "minutes", 3)), sum, na.rm=TRUE) 

我不知道,na.rm=TRUE可以與period.apply()使用,現在讓我跳過mutate(value = ifelse(is.na(value),0,value))。這是一個進步,我對xts方法感到滿意,但我想知道是否有一個純粹的dplyr解決方案,我可以在這種情況下使用。

更新#2

試圖Khashaa的回答後,由於沒有指定我的時區是我有錯。所以我有:

> tail(d4) 
       interval sumvalue 
476 2010-05-21 23:45:00  NA 
477 2010-05-21 23:48:00  NA 
478 2010-05-21 23:51:00  NA 
479 2010-05-21 23:54:00  NA 
480 2010-05-21 23:57:00 11313 
481 2010-05-22 02:27:00 643426 
> d4[450,] 
       interval sumvalue 
450 2010-05-21 22:27:00  NA 

現在,在Sys.setenv(TZ="UTC")後,它一切正常。

回答

5

lubridate-dplyr -esque solution。

library(lubridate) 
library(dplyr) 
d2 <- data.frame(interval = seq(ymd_hms('2010-05-21 00:00:00'), by = '3 min',length.out=(1440/3))) 
d3 <- d1 %>% 
    mutate(interval = floor_date(date, unit="hour")+minutes(floor(minute(date)/3)*3)) %>% 
    group_by(interval) %>% 
    mutate(sumvalue=sum(value)) %>% 
    select(interval,sumvalue) 
d4 <- merge(d2,d3, all=TRUE) # better if left_join is used 
tail(d4) 
#    interval sumvalue 
#475 2010-05-21 23:42:00  NA 
#476 2010-05-21 23:45:00  NA 
#477 2010-05-21 23:48:00  NA 
#478 2010-05-21 23:51:00  NA 
#479 2010-05-21 23:54:00  NA 
#480 2010-05-21 23:57:00  NA 
d4[450,] 
#    interval sumvalue 
#450 2010-05-21 22:27:00 643426 

如果你是舒服Date工作(我不是),你可以用lubridate免除,並與left_join替換最終合併。

+1

有了這個解決方案,我收到了481th一行'2010-05-22 02:27:00'爲'interval'和'643426'爲'value' –

+0

我只要運行它在新的會議上,仍然有同樣的結果。我不明白你爲什麼得到不同的結果。 – Khashaa

+4

@StevenBeaupré這是一個時區問題。你在OP中沒有時區的時候調用'as.POSIXct',它將使用你的本地時區,但是Khashaa正在使用'lubridate :: ymd_hms',如果你沒有指定,它會採用'UTC'。如果你在定義'd1'的OP運行代碼之前調用'Sys.setenv(TZ =「UTC」)',你會得到與Khashaa相同的答案。 – GSee

8

我不知道有關dplyr解決方案,但這裏是一個XTS的解決方案:

startpoints <- function (x, on = "months", k = 1) { 
    head(endpoints(x, on, k) + 1, -1) 
} 
m3 <- seq(as.POSIXct("2010-05-21 00:00:00"), 
    by="3 min", length.out=1440/3) 
x <- merge(value=xts(d1$value, d1$date), xts(,m3)) 
y <- period.apply(x, c(0,startpoints(x, "minutes", 3)), sum, na.rm=TRUE) 

更新:這裏的另一個XTS的解決方案,是一個比較謹慎正確地對準聚合值。不建議先前的解決方案是錯誤的,但此解決方案更容易遵循並在其他分析中重複。

m3 <- seq(as.POSIXct("2010-05-20 23:59:59.999"), 
    by="3 min", length.out=1440/3) 
x <- merge(value=xts(d1$value, d1$date), xts(,m3)) 
y <- period.apply(x, endpoints(x, "minutes", 3), sum, na.rm=TRUE) 
y <- align.time(y, 60*3) 
2

最近,padr包已經開發出來,也可以用一種乾淨的方式解決這個問題。


library(lubridate) 
library(dplyr) 
library(padr) 

d1 <- data.frame(date = as.POSIXct(c("21/05/2010 19:59:37", "21/05/2010 08:40:30", 
            "21/05/2010 09:21:00", "21/05/2010 22:29:50", "21/05/2010 11:27:34", 
            "21/05/2010 18:25:14", "21/05/2010 15:16:01", "21/05/2010 09:41:53", 
            "21/05/2010 15:01:29", "21/05/2010 09:02:06"), format ="%d/%m/%Y %H:%M:%S"), 
       value = c(11313,42423,64645,643426,1313313,1313,3535,6476,11313,9875)) 

res <- d1 %>% 
    as_tibble() %>% 
    arrange(date) %>% 

    # Thicken the results to fall in 3 minute buckets 
    thicken(
    interval = '3 min', 
    start_val = as.POSIXct('2010-05-21 00:00:00'), 
    colname = "date_pad") %>% 

    # Pad the results to fill in the rest of the 3 minute buckets 
    pad(
    interval = '3 min', 
    by  = 'date_pad', 
    start_val = as.POSIXct('2010-05-21 00:00:00'), 
    end_val = as.POSIXct('2010-05-21 23:57:00')) %>% 

    select(date_pad, value) 

res 
#> # A tibble: 480 x 2 
#> date_pad   value 
#> <dttm>    <dbl> 
#> 1 2010-05-21 00:00:00 NA 
#> 2 2010-05-21 00:03:00 NA 
#> 3 2010-05-21 00:06:00 NA 
#> 4 2010-05-21 00:09:00 NA 
#> 5 2010-05-21 00:12:00 NA 
#> 6 2010-05-21 00:15:00 NA 
#> 7 2010-05-21 00:18:00 NA 
#> 8 2010-05-21 00:21:00 NA 
#> 9 2010-05-21 00:24:00 NA 
#> 10 2010-05-21 00:27:00 NA 
#> # ... with 470 more rows 

res[450,] 
#> # A tibble: 1 x 2 
#> date_pad    value 
#> <dttm>    <dbl> 
#> 1 2010-05-21 22:27:00 643426