2016-03-28 36 views
2

來自基礎R的by函數具有其自己的特殊輸出類「by」,它具有特殊的打印格式。爲了便於把成果轉化爲表,我真的想「借」來安排的結果與指示用於子集因子水平列的數據幀:如何以長格式顯示「by」對象

b <- by(mtcars$mpg, list(mtcars$vs, mtcars$am), function(x) c(length(x), mean(x))) 
some_reformatting_function(b) 
# am vs length  mean 
#1 0 0  12 15.05000 
#2 0 1  7 20.74286 
#3 1 0  6 19.75000 
#4 1 1  7 28.37143 

FUN參數by是長度爲1的,我可以通過強制b的類爲數字,然後melt ing一起破解。但是當FUN返回更長的矢量時,此方法不起作用。有什麼建議麼?

+1

請用'dplyr'代替? – Gregor

+0

@Gregor實際上,我自己使用'ddply',但感謝您的建議。我一直想學習'dplyr'一段時間,這又增加了另一個原因。 – Empiromancer

回答

1

當我發佈這個答案後,可能會「僅僅使用(Hadley的一個包)之一」,當然,ddply的默認輸出格式是更合理的數據幀我想了。

plyr::ddply(mtcars, .variables = c("vs", "am"), function(x) c(nrow(x), mean(x[["mpg"]]))) 
# vs am V1  V2 
#1 0 0 12 15.05000 
#2 0 1 6 19.75000 
#3 1 0 7 20.74286 
#4 1 1 7 28.37143 
+1

而不是一個匿名函數,你可以這樣做,......,總結,n = nrow(mpg),mean = mean(mpg))'。 – Gregor

+0

評論更正:您需要'n =長度(mpg)',而不是'nrow(mpg)'。 – Gregor

3

dplyr很適合這些任務,而且非常容易學習。

by產生一個棘手的格式來處理。從by獲得沒有其他包裹的位置的一種方法是再次使用by以一致的方式組合這些因子。

b <- by(mtcars$mpg, list(mtcars$vs, mtcars$am), function(x) c(length(x), mean(x))) 
i <- by(cbind(mtcars$vs, mtcars$am), list(mtcars$vs, mtcars$am), function(x) c(x[1,1], x[1,2])) 
i <- unlist(i) 
b <- unlist(b) 
i <- matrix(i, ncol = 2) 
b <- matrix(b, ncol = 2) 
d <- data.frame(i, b) 
names(d) <- c("am", "vs", "length", "mean") 

d 
# am vs length  mean 
# 1 0 0 12.00000 6.00000 
# 2 0 1 15.05000 19.75000 
# 3 1 1 7.00000 7.00000 
# 4 0 1 20.74286 28.37143 

您還可以結合上面的by函數調用。

0

dplyr版本是:

group_by(mtcars, am, vs) %>% 
    summarize(n = n(), 
       mean_mpg = mean(mpg)) 
2

1)骨料對於問題的具體例子一個通常會使用在基礎R aggregate而非by

aggregate(mpg ~ vs + am, mtcars, function(x) c(length = length(x), mean = mean(x))) 

給出:

vs am mpg.length mpg.mean 
1 0 0 12.00000 15.05000 
2 1 0 7.00000 20.74286 
3 0 1 6.00000 19.75000 
4 1 1 7.00000 28.37143 

2)通過如果實際問題更復雜,而且您確實需要使用by,則格式化by對象,因爲by語句應該重寫爲在整個數據框上運行幷包含邊距變量在功能:

fun <- function(x) with(x, 
      data.frame(vs = vs[1], am = am[1], length = length(mpg), mean = mean(mpg))) 

do.call("rbind", by(mtcars, mtcars[c("vs", "am")], fun)) 

給予:

vs am length  mean 
1 0 0  12 15.05000 
2 1 0  7 20.74286 
3 0 1  6 19.75000 
4 1 1  7 28.37143 

3)通過使用從問題 b儘管這不是recommmended將有可能噸o在問題中改革b。我們稍微重申了b使用更簡潔的符號和添加名稱。在意識到"by"對象b也正是在這種情況下,一個2x2矩陣,我們可以將其轉換成數據幀,調換它給矩陣m,得到b的行名的利潤給marginscbind一切融合在一起:

b <- by(mtcars$mpg, mtcars[c("vs", "am")], function(x) c(length=length(x), mean=mean(x))) 

m <- t(do.call("data.frame", c(as.data.frame.matrix(b), check.names = FALSE))) 
margins <- read.table(text = rownames(m), sep = ".", col.names = rev(names(dimnames(b)))) 
cbind(margins, m) 

給予:

am vs length  mean 
0.0 0 0  12 15.05000 
0.1 0 1  7 20.74286 
1.0 1 0  6 19.75000 
1.1 1 1  7 28.37143 

4)sqldf它也將是可能的解決使用任何許多包例如data.table,doBy,dplyr和sqldf的這個特定問題。在這裏,我們表現出sqldf解決方案:

library(sqldf) 
sqldf("select vs, am, count(*) length, avg(mpg) mean 
     from mtcars 
     group by vs, am") 

,並提供:

vs am length  mean 
1 0 0  12 15.05000 
2 0 1  6 19.75000 
3 1 0  7 20.74286 
4 1 1  7 28.37143 
+0

你的'2)'就是我要做的事情,如果我只是'通過'來處理。對於dplyr/group_by或data.table操作的邏輯來說,它實際上仍然是一個方便的函數,因爲它允許返回列表和難看的中間步驟。 – thelatemail

1

data.table解決方案是

library(data.table) 
mtcars <- as.data.table(mtcars) 
mtcars[, .(length = .N, mean = mean(mpg)), by = .(vs, am)][order(am,vs)] 

(感謝@ thelatemail的建議,這是整潔。)

以下是輸出,

vs am length  mean 
1: 0 0  12 15.05000 
2: 1 0  7 20.74286 
3: 0 1  6 19.75000 
4: 1 1  7 28.37143 
+1

通用邏輯是好的,但你可以減少一點SD參考 - 'mtcars [,。(length = .N,mean = mean(mpg)),by = list(vs,am)] [order(am ,vs)]' – thelatemail

+0

@thelatemail謝謝!我修改了我的答案。 – kitman0804

相關問題