2012-01-18 19 views
3

我想聚合3個類別的數據框架,其中一個不同。不幸的是,這一個不同的類別包含了NAs(實際上這是它需要改變的原因)。因此我創建了一個data.frames的列表。此列表中的每個data.frame都只包含三個變量的完整情況(只有其中一個變化)。聚合包含ddply和lapply的NAs的類別?

讓我們重現此:

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 

等等。我如何向lapply添加名稱(x),還是我需要一個循環或環境?

編輯: 請注意,我希望任何類別或類別A添加到混合。實際上我有大約15個互斥的絕對變量。

+0

在某種意義上,這是一個後續問題此主題:http://stackoverflow.com/questions/8897927/how-can-i-use-ddply-with-varying-variables – 2012-01-18 16:25:25

+2

'RM( list = ls())是一個非常迂迴的行,它包含在代碼中,人們可能會複製粘貼到他們的會話中,試圖幫助你。 ;) – joran 2012-01-18 18:16:35

+0

關於古蘭經,我希望它不會爲你迷戀本週的工作。刪除它。 – 2012-01-18 18:37:35

回答

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 
+0

@ ran2 - 如果您認爲這會更好地迴應您之前詢問的問題,請告訴我,我會將其移至此處。乾杯。 – 2012-01-18 19:30:31

+0

黑暗的一面......現在我們在說話! – 2012-01-18 19:30:38

+0

我會檢查它,在基於list2env和eval的製作中獲得自己的解決方案,並在它出現在這裏後,如果它工作。不知道你的建議(還)。此刻,我寧願刪除第一個問題,繼續這個問題,因爲我覺得我的解釋更好,討論也是如此。謝謝你的提議,但我會回到你身邊:) – 2012-01-18 19:33:48

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),]) 
+0

+1幫助selectDF,沒有想到這一點。不過,你錯過了這裏的一些東西:我有2個固定的分類變量和一個變量變量。當有3個代碼時,你的代碼需要3個代碼,當有4個代碼時,代碼需要4個。在真實數據集中,除了固定數據集之外,我還有大約15個分類變量。而且我需要爲他們每個人提供額外的聚合。編輯這個問題來說明這一點。 – 2012-01-18 18:32:27

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) 
+0

感謝您抽出時間。如果我的例子不好,也許喬希的例子有所幫助。運行他的代碼正是我想要的。它完美地解決了這個問題。 – 2012-01-18 20:50:34

1

最後,我發現,可能不會像喬希一樣光滑的解決方案,但它工作沒有任何黑暗勢力(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) 

}