2010-11-10 37 views
5

Tôi sẽ đánh giá cao sự hiểu biết về lý do tại sao điều này xảy ra và cách tôi có thể làm điều này một cách hùng hồn hơn.Tại sao sapply trả về ma trận mà tôi cần phải chuyển đổi, và sau đó ma trận transposed sẽ không đính kèm vào một khung dữ liệu?

Khi tôi sử dụng sapply, tôi muốn nó trả về ma trận 3x2, nhưng nó trả về ma trận 2x3. Tại sao điều này? Và tại sao khó gắn nó vào một khung dữ liệu khác?

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 
out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
#out is 3x2, but I would like it to be 2x3 
#I then want to append t(out) (out as a 2x3 matrix) to b, a 1x3 dataframe 
b <- data.frame(var3=c(0,0,0)) 

khi tôi cố gắng để đính kèm này,

b[,c('col2','col3')] <- t(out) 

Các lỗi mà tôi nhận được là:

Warning message: 
In `[<-.data.frame`(`*tmp*`, , c("col2", "col3"), value = list(1, : 
    provided 6 variables to replace 2 variables 

mặc dù sau xuất hiện để cung cấp cho các kết quả mong muốn:

rownames(out) <- c('col1', 'col2') 
b <- cbind(b, t(out)) 

Tôi không thể hoạt động vào ngày thứ biến e:

b$var1/b$var2 

lợi nhuận

Error in b$var1/b$var2 : non-numeric argument to binary operator 

Cảm ơn!

+1

Bạn đang cố gắng để làm với dữ liệu này? Ví dụ của bạn không thực sự làm bất cứ điều gì có ý nghĩa. – hadley

+2

@hadley: Ví dụ tuân theo nguyên tắc đăng bài R cung cấp ví dụ tối thiểu, khả thi. Trường hợp thực tế khá phức tạp và sự phức tạp sẽ làm giảm đi câu hỏi trung tâm. Hàm tôi đã ước tính độ nhạy của một mô hình với 20 tham số khác nhau bằng cách sử dụng mở rộng chuỗi taylor và chấp nhận khung dữ liệu 20x8 làm đầu vào. Tôi rất sẵn lòng gửi một ví dụ tái sản xuất đầy đủ nếu bạn muốn, mặc dù nó chưa sẵn sàng để được công khai. –

+1

Bạn cần phải phấn đấu để có một phương tiện vui vẻ giữa điều gì đó dễ hiểu và cái gì đó nắm bắt được bản chất của vấn đề mà bạn đang gặp khó khăn.Trong ví dụ hiện tại của bạn có vẻ như bạn đang cố gắng để có được 'b' bằng với' a'. – hadley

Trả lời

3

Để mở rộng câu trả lời của DWIN: nó sẽ giúp xem xét cấu trúc của đối tượng out của bạn. Nó giải thích lý do tại sao b$var1/b$var2 không làm những gì bạn mong đợi.

> out <- sapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> str(out) # this isn't a data.frame or a matrix... 
List of 6 
$ : num 1 
$ : num 3 
$ : num 2 
$ : num 2 
$ : num 3 
$ : num 1 
- attr(*, "dim")= int [1:2] 2 3 
- attr(*, "dimnames")=List of 2 
    ..$ : chr [1:2] "var1" "var2" 
    ..$ : NULL 

Gia đình apply các chức năng được thiết kế để làm việc trên vectơ và mảng, vì vậy bạn cần phải thực hiện cẩn thận khi sử dụng chúng với data.frames (mà thường là danh sách các vectơ). Bạn có thể sử dụng thực tế rằng data.frames là danh sách cho lợi thế của bạn với lapply.

> out <- lapply(a$id, function(x) a[x, c('var1', 'var2')]) # list of data.frames 
> out <- do.call(rbind, out) # data.frame 
> b <- cbind(b,out) 
> str(b) 
'data.frame': 3 obs. of 4 variables: 
$ var3: num 0 0 0 
$ var1: num 1 2 3 
$ var2: num 3 2 1 
$ var3: num 0 0 0 
> b$var1/b$var2 
[1] 0.3333333 1.0000000 3.0000000 
2

Đầu tiên một chút ký hiệu R. Nếu bạn nhìn vào mã cho sapply, bạn sẽ tìm thấy câu trả lời cho câu hỏi của bạn. Hàm sapply kiểm tra xem độ dài của danh sách có bằng nhau hay không, và nếu như vậy, nó đầu tiên "unlist()" và sau đó lấy chuỗi danh sách đó làm đối số dữ liệu cho mảng(). Vì mảng (như ma trận()) theo mặc định sắp xếp các giá trị của nó theo thứ tự cột lớn, đó là những gì bạn nhận được. Các danh sách được bật về phía họ. Nếu bạn không thích nó thì bạn có thể xác định hàm tsapply mới sẽ trả lại giá trị được chuyển đổi:

> tsapply <- function(...) t(sapply(...)) 
> out <- tsapply(a$id, function(x) out = a[x, c('var1', 'var2')]) 
> out 
    var1 var2 
[1,] 1 3 
[2,] 2 2 
[3,] 3 1 

... ma trận 3 x 2.

+1

Về mặt kỹ thuật, 'out' không phải là ma trận. Đó là danh sách có thuộc tính 'dim' và' dimnames'. Ví dụ. 'out% *% t (out)' không thành công. –

+0

Ngoại trừ R nghĩ rằng đó là ma trận:> is.matrix (out) [1] TRUE –

1

Có một cái nhìn tại ddply từ gói plyr

a <- data.frame(id=c('a','b','c'), var1 = c(1,2,3), var2 = c(3,2,1)) 

library(plyr) 
ddply(a, "id", function(x){ 
    out <- cbind(O1 = rnorm(nrow(x), x$var1), O2 = runif(nrow(x))) 
    out 
}) 
Các vấn đề liên quan