2012-01-17 22 views
9

tôi sử dụng ddply để tóm tắt một số data.frame theo thể loại khác nhau, như thế này:Tôi làm cách nào để sử dụng ddply với các biến .variables khác nhau?

# with both group and size being factors/categorical 
split.df <- ddply(mydata,.(group,size),summarize, 
        sumGroupSize = sum(someValue)) 

này hoạt động trơn tru, nhưng thường tôi thích để tính toán tỷ lệ mà ngụ ý rằng tôi cần phải chia cho tổng của nhóm. Làm thế nào tôi có thể tính toán tổng số như vậy trong cùng một cuộc gọi ddply?

Giả sử tôi muốn chia sẻ các quan sát trong nhóm A có kích thước lớp 1. Rõ ràng tôi phải tính tổng của tất cả các quan sát ở kích thước lớp 1 trước tiên. Chắc chắn tôi có thể làm điều này với hai cuộc gọi ddply, nhưng sử dụng tất cả một cuộc gọi sẽ thoải mái hơn. Có cách nào để làm vậy không?

EDIT: Tôi không có ý định hỏi quá cụ thể, nhưng tôi nhận ra rằng tôi đang làm phiền mọi người ở đây. Đây là vấn đề cụ thể của tôi. Trong thực tế, tôi có một ví dụ mà làm việc, nhưng tôi không xem xét nó thực sự tiện lợi. Thêm vào đó nó có một thiếu sót mà tôi cần phải vượt qua: nó không hoạt động đúng với áp dụng.

library(plyr) 

# make the dataset more "realistic" 
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 


# someValue is summarized ! 
# note we have a another, varying category hence we need the a parameter 
calcShares <- function(a, data) { 
# !is.na needs to be specific! 
tempres1 <- eval(substitute(ddply(data[!is.na(a),],.(group,size,a),summarize, 
       sumTest = sum(someValue,na.rm=T))), 

       envir=data, enclos=parent.frame()) 
tempres2 <- eval(substitute(ddply(data[!is.na(a),],.(group,size),summarize, 
       sumTestTotal = sum(someValue,na.rm=T))), 
       envir=data, enclos=parent.frame()) 

res <- merge(tempres1,tempres2,by=c("group","size")) 
res$share <- res$sumTest/res$sumTestTotal 
return(res) 

} 

test <- calcShares(category,mydata) 
test2 <- calcShares(categoryA,mydata) 
head(test) 
head(test2) 

Như bạn có thể thấy tôi định chạy điều này qua các biến phân loại khác nhau. Trong ví dụ tôi chỉ có hai (category, categoryA) nhưng trên thực tế tôi có nhiều hơn, vì vậy việc sử dụng với hàm của tôi sẽ thực sự tốt đẹp, nhưng bằng cách nào đó nó không hoạt động chính xác.

applytest <- head(apply(mydata[grep("^cat", 
      names(mydata),value=T)],2,calcShares,data=mydata)) 

.. trả về thông báo cảnh báo và tên lạ (newX [, i]) cho danh mục var.

Vậy làm cách nào tôi có thể thực hiện điều này a) thanh lịch hơn và b) khắc phục sự cố áp dụng?

+0

Tốt Q. Tôi luôn làm điều đó với ddply được bao bọc trong một ddply khác như bạn đã nói, vì vậy tôi cũng quan tâm đến giải pháp này. Sẽ 'table' +' prop.table' + 'addmargins' làm việc cho bạn, hay bạn cần thêm tính linh hoạt của ddply? –

+0

Bạn sẽ không sử dụng hàm 'count' cho điều đó? Bộ nhớ của tôi là nó chỉ là một đổi tên của 'chiều dài' mà một trong những cần thiết để sử dụng với 'ave' trong cơ sở R. –

+0

Hmm. tốt đẹp, không biết prop.table, nhưng tôi vẫn có thể sử dụng tính linh hoạt của ddply mặc dù. –

Trả lời

3

Điều này có vẻ đơn giản, vì vậy tôi có thể thiếu một số khía cạnh của câu hỏi của bạn.

Đầu tiên, xác định hàm tính giá trị bạn muốn bên trong mỗi cấp độ group. Sau đó, thay vì sử dụng .(group, size) để chia dữ liệu.frame, hãy sử dụng .(group) và áp dụng hàm mới được xác định cho từng phần tách.

library(plyr) 

# Create a dataset with the names in your example 
mydata <- warpbreaks 
names(mydata) <- c("someValue", "group", "size") 

# A function that calculates the proportional contribution of each size class 
# to the sum of someValue within a level of group 
getProps <- function(df) { 
    with(df, ave(someValue, size, FUN=sum)/sum(someValue)) 
} 

# The call to ddply() 
res <- ddply(mydata, .(group), 
      .fun = function(X) transform(X, PROPS=getProps(X))) 

head(res, 12) 
# someValue group size  PROPS 
# 1   26  A L 0.4785203 
# 2   30  A L 0.4785203 
# 3   54  A L 0.4785203 
# 4   25  A L 0.4785203 
# 5   70  A L 0.4785203 
# 6   52  A L 0.4785203 
# 7   51  A L 0.4785203 
# 8   26  A L 0.4785203 
# 9   67  A L 0.4785203 
# 10  18  A M 0.2577566 
# 11  21  A M 0.2577566 
# 12  29  A M 0.2577566 
+0

+1 để mang lại một số suy nghĩ mới (với/ave/transform) vào bảng. Tôi nhận ra, tôi là một chút không chính xác và đăng một ví dụ tái sản xuất cụ thể hơn. Những gì giải pháp của bạn thiếu là tóm tắt (tức là tổng hợp). Nhưng có lẽ bạn có thể thêm điều này bằng cách nào đó để giải pháp của bạn. Tôi không tập trung vào ddply chỉ :) –

+0

Tôi thích điều này quá, nhưng tôi không biết nếu nó đơn giản hơn là chỉ làm 2x ddply từ nhận được đi. –

Các vấn đề liên quan