3

我想聚合一个超过 3 个类别的 data.frame,其中一个是不同的。不幸的是,这个不同的类别包含 NA(实际上这就是它需要变化的原因)。因此,我创建了一个data.frames. 此列表中的每个 data.frame 仅包含关于三个变量的完整案例(其中只有一个变量发生变化)。

让我们重现这个:

library(plyr)

mydata <- warpbreaks
names(mydata) <- c("someValue","group","size")
mydata$category <- c(1,2,3)
mydata$categoryA <- c("A","A","X","X","Z","Z")
# add some NA
mydata$category[c(8,10,19)] <- NA
mydata$categoryA[c(14,1,20)] <- NA 

# create a list of dfs that contains TRUE FALSE
noNAList <- function(vec){
res <- !is.na(vec)
return(res)
}

testTF <- lapply(mydata[,c("category","categoryA")],noNAList)

# create a list of data.frames
selectDF <- function(TFvec){
res <- mydata[TFvec,]
return(res)
}

# check x and see that it may contain NAs as long
# as it's not in one of the 3 categories I want to aggregate over    
x <-lapply(testTF,selectDF)

## let's ddply get to work
doddply <- function(df){
ddply(df,.(group,size),summarize,sumTest = sum(someValue))
}

y <- lapply(x, doddply);y

y非常接近我想要得到的

$category
group size sumTest
1     A    L     375
2     A    M     198
3     A    H     185
4     B    L     254
5     B    M     259
6     B    H     169

$categoryA
group size sumTest
1     A    L     375
2     A    M     204
3     A    H     200
4     B    L     254
5     B    M     259
6     B    H     169

但是我需要在第三个变量上实现聚合,在这种情况下是categorycategoryA. 就像:

group size category sumTest sumTestTotal      
1      A    H        1      46          221 
2      A    H        2      46          221 
3      A    H        3      93          221 

等等。如何将名称(x)添加到 lapply,或者我需要一个循环或环境?

编辑:请注意,我希望将类别或类别 A 添加到组合中。实际上,我有大约 15 个互斥的分类变量。

4

4 回答 4

4

如果我正确理解您的问题,我认为您可能会让自己很难受。

如果您想通过三个(或四个)变量聚合 data.frame 'myData',您只需执行以下操作:

aggregate(someValue ~ group + size + category + categoryA, sum, data=mydata)

   group size category categoryA someValue
1      A    L        1         A        51
2      B    L        1         A        19
3      A    M        1         A        17
4      B    M        1         A        63

aggregate将自动删除包含NA在任何类别中的行。如果 someValue 有时是NA,则可以添加参数 na.rm=T。

我还注意到您将许多不必要的代码放入函数中。例如:

# create a list of data.frames
selectDF <- function(TFvec){
    res <- mydata[TFvec,]
    return(res)
}

可以写成:

selectDF <- function(TFvec) mydata[TFvec,] 

此外,使用lapply创建两个数据框的列表而没有NA是矫枉过正。试试这个代码:

x = list(mydata[!is.na(mydata$category),],mydata[!is.na(mydata$categoryA),])
于 2012-01-18T17:32:21.130 回答
3

我知道这个问题明确要求ddply()/lapply()解决方案。

但是......如果你愿意来到黑暗的一面,这里有一个data.table()基于 - 的函数应该可以解决问题:

# Convert mydata to a data.table
library(data.table)
dt <- data.table(mydata, key = c("group", "size"))

# Define workhorse function
myfunction <- function(dt, VAR) {
    E <- as.name(substitute(VAR))
    dt[i = !is.na(eval(E)), 
       j = {n <- sum(.SD[,someValue]) 
            .SD[, list(sumTest = sum(someValue),
                       sumTestTotal = n,
                       share = sum(someValue)/n), 
                by = VAR]
           }, 
       by = key(dt)]
}

# Test it out
s1 <- myfunction(dt, "category")
s2 <- myfunction(dt, "categoryA")

添加在编辑

以下是如何为不同分类变量的向量运行它:

catVars <- c("category", "categoryA")

ll <- lapply(catVars, 
             FUN = function(X) {
                       do.call(myfunction, list(dt, X))
                   })
names(ll) <- catVars

lapply(ll, head, 3)
# $category
#      group size category sumTest sumTestTotal     share
# [1,]     A    H        2      46          185 0.2486486
# [2,]     A    H        3      93          185 0.5027027
# [3,]     A    H        1      46          185 0.2486486
# 
# $categoryA
#      group size categoryA sumTest sumTestTotal share
# [1,]     A    H         A      79          200 0.395
# [2,]     A    H         X      68          200 0.340
# [3,]     A    H         Z      53          200 0.265
于 2012-01-18T19:17:57.440 回答
1

最后,我找到了一个可能不像 Josh 那样巧妙的解决方案,但它可以在没有黑暗力量的情况下工作(data.table)。你可能会笑——这是我使用与问题中相同的样本数据的可重现示例。

qual <- c("category","categoryA")

# get T / F vectors
noNAList <- function(vec){
res <- !is.na(vec)
return(res)
}

selectDF <- function(TFvec) mydata[TFvec,]

NAcheck <- lapply(mydata[,qual],noNAList)

# create a list of data.frames
listOfDf <- lapply(NAcheck,selectDF)

workhorse <- function(charVec,listOfDf){
dfs <- list2env(listOfDf)
# create expression list
exlist <- list()
for(i in 1:length(qual)){
exlist[[qual[i]]] <- parse(text=paste("ddply(",qual[i],
                                  ",.(group,size,",qual[i],"),summarize,sumTest =    sum(someValue))",
                                  sep=""))
}

res <- lapply(exlist,eval,envir=dfs)
return(res)

}
于 2012-01-19T11:10:12.953 回答
0

这更像你的意思吗?我发现您的示例非常难以理解。在下面的代码中,该方法可以采用任何列,然后按它进行聚合。它可以返回 someValue 的多个聚合函数。然后我找到您想要聚合的所有列名,然后将该函数应用于该向量。

# Build a method to aggregate by column.
agg.by.col = function (column) {
    by.list=list(mydata$group,mydata$size,mydata[,column])
    names(by.list) = c('group','size',column)
    aggregate(mydata$someValue, by=by.list, function(x) c(sum=sum(x),mean=mean(x)))
}

# Find all the column names you want to aggregate by
cols = names(mydata)[!(names(mydata) %in% c('someValue','group','size'))]

# Apply the method to each column name.
lapply (cols, agg.by.col)
于 2012-01-18T20:23:50.117 回答