2012-07-22 78 views
5

我想按時間間隔聚合一個數據框,對每列應用不同的功能。我想我幾乎有aggregate下來,並已將我的數據與chron包的間隔分開,這很容易。R:具有列特定功能的聚合

但我不知道如何處理子集。所有的映射函數*apply,*ply都帶有一個函數(我希望某些東西需要一個函數向量應用每列或變量,但沒有找到),所以我正在編寫一個函數我的數據框子集,並給我所有變量的意思,除了「時間」,這是指數,和「徑流」應該是總和。

我嘗試這樣做:

aggregate(d., list(Time=trunc(d.$time, "00:10:00")), function (dat) with(dat, 
list(Time=time[1], mean(Port.1), mean(Port.1.1), mean(Port.2), mean(Port.2.1), 
mean(Port.3), mean(Port.3.1), mean(Port.4), mean(Port.4.1), Runoff=sum(Port.5)))) 

這將是醜陋足夠,即使它沒有給我這個錯誤:

Error in eval(substitute(expr), data, enclos = parent.frame()) : 
    not that many frames on the stack 

還告訴我,我真的做錯了什麼。從我見過的R中我認爲必須有一種優雅的方式來做到這一點,但它是什麼?

dput:

d. <- structure(list(time = structure(c(15030.5520833333, 15030.5555555556, 
15030.5590277778, 15030.5625, 15030.5659722222), format = structure(c("m/d/y", 
"h:m:s"), .Names = c("dates", "times")), origin = structure(c(1, 
1, 1970), .Names = c("month", "day", "year")), class = c("chron", 
"dates", "times")), Port.1 = c(0.359747, 0.418139, 0.417459, 
0.418139, 0.417459), Port.1.1 = c(1.3, 11.8, 11.9, 12, 12.1), 
    Port.2 = c(0.288837, 0.335544, 0.335544, 0.335544, 0.335544 
    ), Port.2.1 = c(2.3, 13, 13.2, 13.3, 13.4), Port.3 = c(0.253942, 
    0.358257, 0.358257, 0.358257, 0.359002), Port.3.1 = c(2, 
    12.6, 12.7, 12.9, 13.1), Port.4 = c(0.352269, 0.410609, 0.410609, 
    0.410609, 0.410609), Port.4.1 = c(5.9, 17.5, 17.6, 17.7, 
    17.9), Port.5 = c(0L, 0L, 0L, 0L, 0L)), .Names = c("time", 
"Port.1", "Port.1.1", "Port.2", "Port.2.1", "Port.3", "Port.3.1", 
"Port.4", "Port.4.1", "Port.5"), row.names = c(NA, 5L), class = "data.frame") 

回答

8

你的方法有很多錯誤。一般的建議是不要直截了當地認爲最終的陳述應該是這樣的,而是一步一步地做事,否則就會使調試(理解和修復錯誤)變得相當困難。

例如,你可以有開始:

aggregate(d., list(Time=trunc(d.$time, "00:10:00")), identity) 

注意到有什麼不對您的拆分變量。顯然aggregate不喜歡使用這類數據。您可以通過轉換Time到數字解決這個問題:

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), identity) 

這時可以嘗試

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), apply.fun) 

其中apply.fun是用戶定義的函數。這種失敗,相當criptic消息,但運行

aggregate(d., list(Time=as.numeric(trunc(d.$time, "00:10:00"))), print) 

有助於實現這裏面aggregateFUN功能不是針對每個數據塊調用一次(並通過了data.frame),但它是爲每一列調用一次(並傳遞了一個未命名的向量),因此您無法使用aggregate獲得想要的結果。

取而代之,您可以使用plyr包中的ddply函數。在那裏,應用於每件作品的功能確實收到數據。框架所以你可以做這樣的事情:

apply.fun <- function(dat) with(dat, data.frame(Time=time[1], 
               mean(Port.1), 
               mean(Port.1.1), 
               mean(Port.2), 
               mean(Port.2.1), 
               mean(Port.3), 
               mean(Port.3.1), 
               mean(Port.4), 
               mean(Port.4.1), 
               Runoff=sum(Port.5))) 

d.$Time <- as.numeric(trunc(d.$time, "00:10:00")) 
library(plyr) 
ddply(d., "Time", apply.fun) 

#   Time mean.Port.1. mean.Port.1.1. mean.Port.2. mean.Port.2.1. 
# 1 15030.5520833 0.4061886   9.82 0.3262026   11.04 
# mean.Port.3. mean.Port.3.1. mean.Port.4. mean.Port.4.1. Runoff 
# 1  0.337543   10.66  0.398941   15.32  0 

編輯:在下面的第一個評論@roysc問題後續行動,你可以這樣做:

apply.fun <- function(dat) { 
    out <- as.data.frame(lapply(dat, mean)) 
    out$Time <- dat$time[1] 
    out$Runoff <- sum(dat$Port.5) 
    return(out) 
} 
+0

好吧,我想我明白這一點更好一點。我習慣於強類型語言,並發現R的類強制方案令人困惑。我也想知道的是,如果有一種簡單的方法來採取大多數colums的意思,但是專門對待一個,而不是明確地做。我是否必須將df分開然後重新組合列? – scry 2012-07-22 19:10:58

1

這個怎麼樣?

library(plyr) 
ddply(d., .(time), colMeans) 
+0

這錯過了這樣的事實,其中一列不應該有意思,而是總和 – Chase 2012-07-22 20:15:32

+0

我注意到,但更有用的答案來了。我會更新這個。 – Maiasaura 2012-07-22 22:28:00

5

使用by而不是aggregate

如果f是samee,除了list您的匿名函數內部它被替換data.frame使f <- function(dat) with(dat, data.frame(...whatever...))則:

d.by <- by(d., list(Time = trunc(d.$time, "00:10:00")), f) 
d.rbind <- do.call("rbind", d.by) # bind rows together 

# fix up row and column names 
rownames(d.rbind) <- NULL 
colnames(d.rbind) <- colnames(d.) 

我們可以刪除其指定的列名,如果f添加的名稱本身的最後一條語句而不僅僅是Time