2011-12-20 45 views
16

Vì vậy, tôi muốn áp dụng một hàm trên một ma trận trong R. này hoạt động thực sự trực giác cho các chức năng đơn giản:R: áp dụng chức năng trên ma trận và giữ kích thước ma trận

> (function(x)x*x)(matrix(1:10, nrow=2)) 
[,1] [,2] [,3] [,4] [,5] 
[1,] 1 9 25 49 81 
[2,] 4 16 36 64 100 

... nhưng rõ ràng tôi không hiểu tất cả các hoạt động của nó:

> m = (matrix(1:10, nrow=2)) 
> (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) })(m) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 4 6 8 10 
[2,] 3 5 7 9 11 
Warning message: 
In if (x == 3) { : 
    the condition has length > 1 and only the first element will be used 

tôi đọc lên về vấn đề này và phát hiện ra về Vectorize và sapply, mà cả hai có vẻ tuyệt vời và giống như những gì tôi muốn, ngoại trừ việc cả trong số họ chuyển đổi ma trận của tôi vào một danh sách:

> y = (function(x) if (x %% 3 == 0) { return(NA) } else { return(x+1) }) 
> sapply(m, y) 
[1] 2 3 NA 5 6 NA 8 9 NA 11 
> Vectorize(y)(m) 
[1] 2 3 NA 5 6 NA 8 9 NA 11 

... trong khi tôi muốn giữ nó trong ma trận với kích thước hiện tại của nó. Làm thế nào tôi có thể làm điều này? Cảm ơn!

+0

Ngoài ra kiểm tra bài này hữu ích trên các phiên bản khác nhau của ứng dụng: http://nsaunders.wordpress.com/2010/08/20/a-brief-introduction-to-apply-in-r/ – patrickmdnet

Trả lời

15

@Joshua Ulrich (và Dason) có một câu trả lời tuyệt vời. Và làm điều đó trực tiếp mà không cần chức năng y là giải pháp tốt nhất. Nhưng nếu bạn thực sự cần cần để gọi hàm, bạn có thể làm cho nó nhanh hơn bằng cách sử dụng vapply. Nó tạo ra một vector mà không kích thước (như sapply, nhưng nhanh hơn), nhưng sau đó bạn có thể thêm chúng lại sử dụng structure:

# Your function (optimized) 
y = function(x) if (x %% 3) x+1 else NA 

m <- matrix(1:1e6,1e3) 
system.time(r1 <- apply(m,1:2,y)) # 4.89 secs 
system.time(r2 <- structure(sapply(m, y), dim=dim(m))) # 2.89 secs 
system.time(r3 <- structure(vapply(m, y, numeric(1)), dim=dim(m))) # 1.66 secs 
identical(r1, r2) # TRUE 
identical(r1, r3) # TRUE 

... Như bạn thấy, cách tiếp cận vapply khoảng 3x nhanh hơn apply ... Và lý do vapply nhanh hơn sapplysapply phải phân tích kết quả để tìm ra rằng nó có thể được đơn giản hóa thành một vector số. Với vapply, bạn chỉ định loại kết quả (numeric(1)), vì vậy nó không phải đoán ...

CẬP NHẬT tôi đã tìm ra khác (ngắn hơn) cách bảo quản cấu trúc ma trận:

m <- matrix(1:10, nrow=2) 
m[] <- vapply(m, y, numeric(1)) 

Bạn chỉ cần gán các giá trị mới cho đối tượng sử dụng m[] <-. Sau đó, tất cả các thuộc tính khác được giữ nguyên (như dim, dimnames, class v.v.).

+0

Cảm ơn rất nhiều vì điều này.Tôi đồng ý nhìn lại rằng với ví dụ đồ chơi tôi đã bỏ qua chức năng thực tế là cuộc gọi đúng, nhưng tôi thực sự muốn biết làm thế nào điều này nên được xử lý khi nó thực sự là một chức năng. (Tôi đã cố gắng tạo ra một hiệu ứng đơn giản hơn cái mà tôi đã thực sự đối phó, nhưng rõ ràng đã bỏ lỡ dấu.) Dù sao thì thông tin định thời cũng cực kỳ hữu ích vì tôi cũng cố gắng tối ưu hóa điều này - cảm ơn! –

12

Một cách là sử dụng apply trên cả hàng và cột:

apply(m,1:2,y) 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 NA 6 8 NA 
[2,] 3 5 NA 9 11 

Bạn cũng có thể làm điều đó với subscripting vì == đã được vector hóa:

m[m %% 3 == 0] <- NA 
m <- m+1 
m 
    [,1] [,2] [,3] [,4] [,5] 
[1,] 2 NA 6 8 NA 
[2,] 3 5 NA 9 11 
7

Ví dụ cụ thể này, bạn có thể chỉ làm điều gì đó như thế này

> # Create some fake data 
> mat <- matrix(1:16, 4, 4) 
> # Set all elements divisible by 3 to NA 
> mat[mat %% 3 == 0] <- NA 
> # Add 1 to all non NA elements 
> mat <- mat + 1 
> mat 
    [,1] [,2] [,3] [,4] 
[1,] 2 6 NA 14 
[2,] 3 NA 11 15 
[3,] NA 8 12 NA 
[4,] 5 9 NA 17 
+0

Một đồng nghiệp đã chỉ ra cách tiếp cận này với tôi. Nó thực hiện nhu cầu của tôi và tôi đánh giá cao nó, nhưng nó thực sự có vẻ như có nên có một số cách để áp dụng một chức năng có sẵn trên một ma trận. –

6

Có một chút tinh tế của dung dịch Dason và Josh sử dụng ifelse.

mat <- matrix(1:16, 4, 4) 
ifelse(mat %% 3 == 0, NA, mat + 1) 
    [,1] [,2] [,3] [,4] 
[1,] 2 6 NA 14 
[2,] 3 NA 11 15 
[3,] NA 8 12 NA 
[4,] 5 9 NA 17 
+0

Đẹp nhất. đây sẽ là nhanh nhất. một kiểm tra nhanh bằng cách sử dụng 'rbenchmark' cho thấy rằng nó là khoảng 8x nhanh hơn so với giải pháp' vapply'. Vectorization luôn triumpsh !! – Ramnath

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