我可以在大型数据框上执行多次拆分操作吗?

时间:2013-04-29 17:50:40

标签: r split aggregate lapply sapply

我已经在这几个小时了,似乎无法找到解决方案。我有一个非常大的数据框(超过150万行),我想在其中进行相当具体的操作。首先,我的数据如下所示:

STATION       DATE      Precip
COOP 310     -7788        .24
COOP 310     -7788        .15
COOP 310     -6654        .59
COOP 310     -6654        .10
COOP 499     -7122        .64
COOP 499     -7122        .36
COOP 499     -7122        .14
COOP 499     -2350        .11
COOP 499     -2350        .85

我有一个weatehr station id(STATION),一个UNIX纪元形式的日期(DATE)和降水值(降雨时的15分钟数据间隔)。我一直在努力确定每站下雨的每日降雨量。所需的输出看起来像这样:

STATION       DATE        24-hour_PRECIP
COOP 310     -7788        0.39
COOP 310     -6654        0.69
COOP 499     -7122        1.14
COOP 499     -2350        0.96

这实际上意味着,我做了两次SPLIT操作,一次根据相同的STATION值拆分所有数据,然后再根据相同的DATE值。从理论上讲,此输出将通过SAPPLY操作运行,将SUM函数应用于每个唯一日期/工作站集中的数据集。我的方法(虽然错了):

数据框名称为“dfhour”:

sp1<-split(dfhour$Precip,dfhour$STATION)

我可以对这些数据做一个很好的sapply函数,但我想在使用sapply之前进一步拆分它。我知道那样做

sapply(split(split(dfhour$Precip, dfhour$STATION),dfhour$DATE),FUN=sum)

将无效,因为split函数的输出是一个列表,而下一个split函数将无法接受列表作为参数。有人对此问题有任何指导吗?还有哪些其他功能可以帮助我找到我需要去的地方?

3 个答案:

答案 0 :(得分:2)

我认为你只是在寻找aggregate。如果您的data.frame名为“mydf”:

> aggregate(Precip ~ ., mydf, sum)
   STATION  DATE Precip
1 COOP 310 -7788   0.39
2 COOP 499 -7122   1.14
3 COOP 310 -6654   0.69
4 COOP 499 -2350   0.96

但是,根据您的数据大小来判断,您可能希望使用data.table代替:

> library(data.table)
data.table 1.8.8  For help type: help("data.table")
> DT <- data.table(mydf, key = "STATION,DATE")
> DT[, list(Precip = sum(Precip)), by = key(DT)]
    STATION  DATE Precip
1: COOP 310 -7788   0.39
2: COOP 310 -6654   0.69
3: COOP 499 -7122   1.14
4: COOP 499 -2350   0.96

根据评论

中的讨论更新

想象一下您的数据如下(注意重复的日期,但在不同的站点):

mydf <- structure(list(STATION = c("COOP 310", "COOP 310", "COOP 310",                 
     "COOP 310", "COOP 499", "COOP 499", "COOP 499", "COOP 499", "COOP 499",            
     "COOP 499", "COOP 499"), DATE = c(-7788L, -7788L, -6654L, -6654L,                  
     -7122L, -7122L, -7122L, -2350L, -2350L, -7788L, -7788L), Precip = c(0.24,          
     0.15, 0.59, 0.1, 0.64, 0.36, 0.14, 0.11, 0.85, 0.35, 0.17)), .Names = c("STATION", 
     "DATE", "Precip"), row.names = c(NA, 11L), class = "data.frame")
mydf
#     STATION  DATE Precip
# 1  COOP 310 -7788   0.24
# 2  COOP 310 -7788   0.15
# 3  COOP 310 -6654   0.59
# 4  COOP 310 -6654   0.10
# 5  COOP 499 -7122   0.64
# 6  COOP 499 -7122   0.36
# 7  COOP 499 -7122   0.14
# 8  COOP 499 -2350   0.11
# 9  COOP 499 -2350   0.85
# 10 COOP 499 -7788   0.35
# 11 COOP 499 -7788   0.17

所提供的两种替代方案将生成“STATION”和“DATE”组合的总和。这是data.table流程和结果:

DT <- data.table(mydf, key = "STATION,DATE")
DT[, list(Precip = sum(Precip)), by = key(DT)]
#     STATION  DATE Precip
# 1: COOP 310 -7788   0.39
# 2: COOP 310 -6654   0.69
# 3: COOP 499 -7788   0.52
# 4: COOP 499 -7122   1.14
# 5: COOP 499 -2350   0.96

答案 1 :(得分:1)

“超过150万行”与简单的split-apply-combine相结合,表明data.table是解决问题的完美工具。

我想你想要的东西是:

DT[,sum(Precip),by="STATION,DATE"]

DTdata.table的{​​{1}}形式。

答案 2 :(得分:0)

您不需要嵌套的splits。您只需要提供一个单独的“拆分”参数来捕获交叉级别,可能使用interaction函数。

tapply( statfrm$Precip, interaction(statfrm$STATION, statfrm$DATE) , sum) 
#----------------
COOP-310.-7788 COOP-499.-7788 COOP-310.-7122 COOP-499.-7122 COOP-310.-6654 
          0.39             NA             NA           1.14           0.69 
COOP-499.-6654 COOP-310.-2350 COOP-499.-2350 
            NA             NA           0.96 

你也可以使用分裂 - 乐观策略来获得类似的答案,在你的cas中,零值可能比你用tapply得到的NA更合适:

 sapply(split(statfrm$Precip, interaction(statfrm$STATION, statfrm$DATE) ), sum) 
#-------
COOP-310.-7788 COOP-499.-7788 COOP-310.-7122 COOP-499.-7122 COOP-310.-6654 
          0.39           0.00           0.00           1.14           0.69 
COOP-499.-6654 COOP-310.-2350 COOP-499.-2350 
          0.00           0.00           0.96 

就这个向量的显示而言,我有时会围绕向量包裹as.matrix以显示“向下”:

as.matrix(sapply(split(statfrm$Precip, interaction(statfrm$STATION, statfrm$DATE) ), sum))
#_________________
               [,1]
COOP-310.-7788 0.39
COOP-499.-7788 0.00
COOP-310.-7122 0.00
COOP-499.-7122 1.14
COOP-310.-6654 0.69
COOP-499.-6654 0.00
COOP-310.-2350 0.00
COOP-499.-2350 0.96