2013-02-07 23 views
7

Tôi muốn chia khung dữ liệu của mình bằng một vài cột và gọi fivenum trên mỗi nhóm.Làm cách nào để sử dụng các hàm trả về vectơ (như fivenum) với ddply hoặc aggregate?

aggregate(Petal.Width ~ Species, iris, function(x) summary(fivenum(x))) 

Giá trị trả lại là một data.frame chỉ có 2 cột và thứ hai là ma trận. Làm thế nào tôi có thể biến nó thành các cột bình thường của một data.frame?

Cập nhật

Tôi muốn một cái gì đó như sau với ít mã sử dụng fivenum

ddply(iris, .(Species), summarise, 
     Min = min(Petal.Width), 
     Q1 = quantile(Petal.Width, .25), 
     Med = median(Petal.Width), 
     Q3 = quantile(Petal.Width, .75), 
     Max = max(Petal.Width) 
    ) 
+0

Các giá trị trả về là 'data.frame' của bảy cột. Nó không liên quan gì đến 'ma trận'. Có thể nếu bạn cho thấy kết quả bạn mong đợi, sẽ dễ dàng hơn để trả lời câu hỏi này. – nograpes

+2

@nograpes Hãy thử gói dòng mẫu vào 'length()' – mlt

+0

Ha. bạn đúng! – nograpes

Trả lời

5

Bạn có thể sử dụng do.call gọi data.frame trên mỗi yếu tố ma trận đệ quy để có được một data.frame với các yếu tố vector:

dim(do.call("data.frame",dfr)) 
[1] 3 7 

str(do.call("data.frame",dfr)) 
'data.frame': 3 obs. of 7 variables: 
$ Species   : Factor w/ 3 levels "setosa","versicolor",..: 1 2 3 
$ Petal.Width.Min. : num 0.1 1 1.4 
$ Petal.Width.1st.Qu.: num 0.2 1.2 1.8 
$ Petal.Width.Median : num 0.2 1.3 2 
$ Petal.Width.Mean : num 0.28 1.36 2 
$ Petal.Width.3rd.Qu.: num 0.3 1.5 2.3 
$ Petal.Width.Max. : num 0.6 1.8 2.5 
4

Theo như tôi biết, có không phải là một cách chính xác để làm những gì bạn đang yêu cầu, vì hàm bạn đang sử dụng (fivenum) không trả về dữ liệu theo cách có thể dễ dàng liên kết với các cột từ bên trong hàm 'ddply'. Điều này là dễ dàng để làm sạch, mặc dù, một cách có lập trình.

Bước 1: Thực hiện chức năng fivenum trên từng giá trị 'Loài' sử dụng hàm 'ddply'.

data <- ddply(iris, .(Species), summarize, value=fivenum(Petal.Width)) 

#  Species value 
# 1  setosa 0.1 
# 2  setosa 0.2 
# 3  setosa 0.2 
# 4  setosa 0.3 
# 5  setosa 0.6 
# 6 versicolor 1.0 
# 7 versicolor 1.2 
# 8 versicolor 1.3 
# 9 versicolor 1.5 
# 10 versicolor 1.8 
# 11 virginica 1.4 
# 12 virginica 1.8 
# 13 virginica 2.0 
# 14 virginica 2.3 
# 15 virginica 2.5 

Bây giờ, hàm 'fivenum' trả về danh sách, vì vậy chúng tôi kết thúc với 5 mục dòng cho mỗi loài. Đó là phần mà chức năng 'fivenum' đang chiến đấu với chúng ta.

Bước 2: Thêm cột nhãn. Chúng ta biết năm con số của Tukey là gì, vì vậy chúng ta chỉ gọi chúng theo thứ tự mà hàm 'fivenum' trả về chúng. Danh sách sẽ lặp lại cho đến khi nó kết thúc dữ liệu.

Tukeys_five <- c("Min","Q1","Med","Q3","Max") 
data$label <- Tukeys_five 

#  Species value label 
# 1  setosa 0.1 Min 
# 2  setosa 0.2 Q1 
# 3  setosa 0.2 Med 
# 4  setosa 0.3 Q3 
# 5  setosa 0.6 Max 
# 6 versicolor 1.0 Min 
# 7 versicolor 1.2 Q1 
# 8 versicolor 1.3 Med 
# 9 versicolor 1.5 Q3 
# 10 versicolor 1.8 Max 
# 11 virginica 1.4 Min 
# 12 virginica 1.8 Q1 
# 13 virginica 2.0 Med 
# 14 virginica 2.3 Q3 
# 15 virginica 2.5 Max 

Bước 3: Với các nhãn tại chỗ, chúng tôi nhanh chóng có thể cast dữ liệu này vào một hình dạng mới bằng cách sử dụng chức năng 'dcast' từ gói 'reshape2'.

library(reshape2) 
dcast(data, Species ~ label)[,c("Species",Tukeys_five)] 

#  Species Min Q1 Med Q3 Max 
# 1  setosa 0.1 0.2 0.2 0.3 0.6 
# 2 versicolor 1.0 1.2 1.3 1.5 1.8 
# 3 virginica 1.4 1.8 2.0 2.3 2.5 

Tất cả thư rác đó ở cuối chỉ chỉ định thứ tự cột, vì chức năng 'dcast' tự động đặt mọi thứ theo thứ tự bảng chữ cái.

Hy vọng điều này sẽ hữu ích.

Cập nhật: Tôi quyết định quay lại, vì tôi nhận ra có một tùy chọn khác có sẵn cho bạn. Bạn luôn có thể ràng buộc một ma trận như một phần của một định nghĩa khung dữ liệu, vì vậy bạn có thể giải quyết 'tổng hợp' chức năng của bạn như sau:

data <- aggregate(Petal.Width ~ Species, iris, function(x) summary(fivenum(x))) 
result <- data.frame(Species=data[,1],data[,2]) 

#  Species Min. X1st.Qu. Median Mean X3rd.Qu. Max. 
# 1  setosa 0.1  0.2 0.2 0.28  0.3 0.6 
# 2 versicolor 1.0  1.2 1.3 1.36  1.5 1.8 
# 3 virginica 1.4  1.8 2.0 2.00  2.3 2.5 
+0

Tôi đã suy nghĩ về việc truyền dữ liệu. Tôi thường sử dụng * reshape * cho điều đó nhưng thật tuyệt khi thấy nó có thể được thực hiện với plyr như thế nào. Câu trả lời cập nhật của bạn về bản chất là những gì James đề xuất. Tôi quên rằng người ta có thể "cbind" data.frames bao gồm chuyển đổi ngầm từ ma trận như thế. – mlt

9

đây là một giải pháp sử dụng data.table (trong khi không yêu cầu cụ thể, đó là một lời khen rõ ràng hoặc thay thế cho aggregate hoặc ddply.Cũng như là hơi dài để mã, liên tục gọi quantile sẽ không hiệu quả, như đối với mỗi cuộc gọi mà bạn sẽ được sắp xếp dữ liệu

library(data.table) 
Tukeys_five <- c("Min","Q1","Med","Q3","Max") 

IRIS <- data.table(iris) 
# this will create the wide data.table 
lengthBySpecies <- IRIS[,as.list(fivenum(Sepal.Length)), by = Species] 

# and you can rename the columns from V1, ..., V5 to something nicer 

setnames(lengthBySpecies, paste0('V',1:5), Tukeys_five) 


lengthBySpecies 



     Species Min Q1 Med Q3 Max 
1:  setosa 4.3 4.8 5.0 5.2 5.8 
2: versicolor 4.9 5.6 5.9 6.3 7.0 
3: virginica 4.9 6.2 6.5 6.9 7.9 

Hoặc, sử dụng một cuộc gọi duy nhất để quantile sử dụng prob lập luận thích hợp.

IRIS[,as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25))), by = Species] 


     Species 0% 25% 50% 75% 100% 
1:  setosa 4.3 4.800 5.0 5.2 5.8 
2: versicolor 4.9 5.600 5.9 6.3 7.0 
3: virginica 4.9 6.225 6.5 6.9 7.9 

Lưu ý rằng tên của các cột được tạo ra không phải là cú pháp hợp lệ, mặc dù bạn có thể đi qua một đổi tên tương tự sử dụng setnames


EDIT

Điều thú vị là, quantile sẽ thiết lập tên của các vector kết quả nếu bạn đặt names = TRUE, và điều này sẽ sao chép (làm chậm số crunching và tiêu thụ bộ nhớ - nó thậm chí còn cảnh báo bạn trong sự giúp đỡ, ưa thích đó!)

Do đó, có lẽ bạn nên sử dụng

IRIS[,as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25), names = FALSE)), by = Species] 

Hoặc, nếu bạn muốn quay trở lại danh sách tên, mà không R sao chép nội

IRIS[,{quant <- as.list(quantile(Sepal.Length, prob = seq(0,1, by = 0.25), names = FALSE)) 
     setattr(quant, 'names', Tukeys_five) 
     quant}, by = Species] 
+0

Điều này đã thuyết phục tôi cuối cùng tìm hiểu cách sử dụng 'data.table' –

0

Đây là giải pháp của tôi:

ddply(iris, .(Species), summarize, value=t(fivenum(Petal.Width))) 
+0

Và nó khác với những gì * Dinre * đã viết? – mlt

+0

Nó đơn giản, ngắn gọn và mượt mà. Ở đây, các giá trị vector của "fivenum" tạo thành một ma trận. Vì vậy, kết quả có hai cột, một là các nhãn và một là một ma trận của năm cột – pmjn6

+0

Bạn sẽ ngạc nhiên bằng cách gọi * ncol * trên đó. – mlt

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