簡體   English   中英

如何根據每周日期創建移動平均值,並按data.table中的多列分組?

[英]How do I create a moving average based on weekly dates, grouped by multiple columns in data.table?

我正在讀取一個非常大的數據集作為data.table以獲取速度。 相關列為DATE (年月日字符串中的每周數據,例如“ 2017-12-25”), V1 (整數), V2 (字符串), V3 (數值)。 我想產生V4 ,這是最近3周( DATEDATE -7和DATE -14)的V3的移動平均值,這是一個幼稚的嘗試/解決方案,效率非常低:

dt <- fread("largefile.csv")

dt$DATE <- as.IDate(dt$DATE) //convert dates to date format

V1_list <- sort(unique(dt$V1))

V2_list <- sort(unique(dt$V2))

DATE_list <- sort(unique(dt$DATE))

for(i in 1:length(V1_list)){
for(j in 1:length(V2_list)){
for(k in 3:length(DATE_list){
dt[which(dt$V1 == V1_list[i] && dt$V2 == V2_list[j] && dt$DATE == DATE_list[k]),"V4"] 
<- mean(dt[which(dt$V1 == V1_list[i] && dt$V2 == V2_list[j] && dt$DATE %in% DATE_list[k-2:k]),"V3"])
}
}
}

我避免使用plyr部分是由於給定我使用的50M行的計算限制。 我已經研究了setkey()zoo / rolling函數的選項,但是我無法弄清楚如何對日期部分進行分層(假設我按V1V2和平均V3分組)。 不提供示例代碼的道歉。

OP要求添加一個新列,該列是過去3周內V3的滾動平均值,由V1V2分組,構成一個5000萬行的data.table

如果DATE值沒有間隙 ,即在所有組中都沒有丟失星期,則一種可能的方法是使用zoo包中的rollmeanr()函數:

DT[order(DATE), V4 := zoo::rollmeanr(V3, 3L, fill = NA), by = .(V1, V2)]
DT[order(V1, V2, DATE)]
  DATE V1 V2 V3 V4 1: 2017-12-04 1 A 1 NA 2: 2017-12-11 1 A 2 NA 3: 2017-12-18 1 A 3 2 4: 2017-12-25 1 A 4 3 5: 2017-12-04 1 B 5 NA 6: 2017-12-11 1 B 6 NA 7: 2017-12-18 1 B 7 6 8: 2017-12-25 1 B 8 7 9: 2017-12-04 2 A 9 NA 10: 2017-12-11 2 A 10 NA 11: 2017-12-18 2 A 11 10 12: 2017-12-25 2 A 12 11 13: 2017-12-04 2 B 13 NA 14: 2017-12-11 2 B 14 NA 15: 2017-12-18 2 B 15 14 16: 2017-12-25 2 B 16 15 

請注意,有意引入了NA因為對於每個組中的前兩行,我們沒有DATE -7DATE -14值。

另外請注意,這種方法不需要字符日期的類型轉換。

數據

根據OP的描述, data.table有4列: DATE是標准字符格式%Y-%m-%d每周字符日期, V1是整數類型, V2是字符類型, V3是double類型(數字)。 V1V2用於分組。

library(data.table)
# create data
n_week = 4L
n_V1 = 2L
# cross join
DT <- CJ(
  DATE = as.character(rev(seq(as.Date("2017-12-25"), length.out = n_week, by = "-1 week"))),
  V1 = seq_len(n_V1),
  V2 = LETTERS[1:2]
)
DT[order(V1, V2, DATE), V3 := as.numeric(seq_len(.N))][]
  DATE V1 V2 V3 1: 2017-12-04 1 A 1 2: 2017-12-04 1 B 5 3: 2017-12-04 2 A 9 4: 2017-12-04 2 B 13 5: 2017-12-11 1 A 2 6: 2017-12-11 1 B 6 7: 2017-12-11 2 A 10 8: 2017-12-11 2 B 14 9: 2017-12-18 1 A 3 10: 2017-12-18 1 B 7 11: 2017-12-18 2 A 11 12: 2017-12-18 2 B 15 13: 2017-12-25 1 A 4 14: 2017-12-25 1 B 8 15: 2017-12-25 2 A 12 16: 2017-12-25 2 B 16 

因此,我嘗試使用dplyr包中的兩個inner_joins解決您的問題:

首先,我創建了一個示例data.frame(1.000.000行):

V3 <- seq(from=1, to=1000000, by =1 )
DATE <- seq(from=1, to= 7000000, by =7)
dt <- data.frame(V3, DATE)

看起來正確嗎? 我刪除了所有不必要的內容,並忽略了日期格式(您可以用與整數相同的方式減去日期)

接下來,我在DATE列上執行了兩個內部聯接,但是第二個data.frame包含DATE +7和DATE +14,因此您在正確的Date上聯接。 最后,我選擇了3個有趣的列並計算了rowMean。 我在糟糕的MacBook上花了大約5秒鍾的時間。

inner_join(
    inner_join(x= dt, y=mutate(dt, DATE=DATE+7), by= 'DATE'),
    y = mutate(dt, DATE= DATE+14), by= 'DATE')  %>% 
    select(V3 , V3.y, V3.x) %>% 
    rowMeans()

如果要將其添加到dt中,請記住前兩個日期沒有平均值,因為不存在DATE-14和DATE-7。

dt$V4 <-   c(NA, NA, inner_join(
        inner_join(x= dt, y=mutate(dt, DATE=DATE+7), by= 'DATE'),
        y = mutate(dt, DATE= DATE+14), by= 'DATE')  %>% 
        select(V3 , V3.y, V3.x) %>% 
        rowMeans())

暫無
暫無

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

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