2012-12-17 40 views
10

Tôi cần tính giá trị trung bình của từng phần tử đường chéo trong ma trận n × n. Hình tam giác phía dưới và phía trên là thừa. Đây là mã tôi hiện đang sử dụng:Cách tính trung bình đường chéo nhanh hơn trong ma trận lớn

A <- replicate(500, rnorm(500)) 
sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)])) 

Có vẻ như nó hoạt động nhưng không có quy mô tốt với ma trận lớn hơn. Những cái tôi không có lớn, khoảng 2-5000^2, nhưng thậm chí với 1000^2 nó mất nhiều thời gian hơn tôi muốn:

A <- replicate(1000, rnorm(1000)) 
system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)]))) 
> user system elapsed 
> 26.662 4.846 31.494 

Có cách nào thông minh hơn không?

chỉnh sửa Để làm rõ, tôi muốn ý nghĩa của từng đường chéo một cách độc lập, ví dụ: cho:

1 2 3 4 
1 2 3 4 
1 2 3 4 
1 2 3 4 

Tôi muốn:

mean(c(1,2,3)) 
mean(c(1,2)) 
mean(1) 

Trả lời

14

Bạn có thể nhận được đáng kể nhanh hơn chỉ bằng cách chiết xuất đường chéo trực tiếp sử dụng tuyến tính giải quyết: superdiag đây trích xuất thứ i superdiagonal từ A (i = 1 là đường chéo chính)

superdiag <- function(A,i) { 
    n<-nrow(A); 
    len<-n-i+1; 
    r <- 1:len; 
    c <- i:n; 
    indices<-(c-1)*n+r; 
    A[indices] 
} 

superdiagmeans <- function(A) { 
    sapply(2:nrow(A), function(i){mean(superdiag(A,i))}) 
} 

Chạy này trên một ma trận vuông 1K cho một ~ 800x tăng tốc:

> A <- replicate(1000, rnorm(1000)) 

> system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)]))) 
    user system elapsed 
26.464 3.345 29.793 

> system.time(superdiagmeans(A)) 
    user system elapsed 
    0.033 0.006 0.039 

này mang đến cho bạn kết quả theo thứ tự như bản gốc.

+1

Sử dụng tốt các chỉ số. Tôi bỏ phiếu cho câu trả lời này là câu trả lời được chấp nhận, vì nó minh họa các chỉ số mạnh mẽ như thế nào. –

+1

Cảm ơn bạn, nhưng bạn rõ ràng hơn nhiều, @ JorisMeys; cách tiếp cận này sẽ có giá trị thêm biến chứng chỉ khi đó là một cái gì đó bạn phải làm một _lot_ và mỗi thứ mười của một quảng cáo thứ hai lên. –

+0

Rất thông minh - tôi phải làm việc thông qua việc tạo các chỉ mục để hiểu những gì đang diễn ra. Cảm ơn câu trả lời – blmoore

10

Bạn có thể sử dụng chức năng sau:

diagmean <- function(x){ 
    id <- row(x) - col(x) 
    sol <- tapply(x,id,mean) 
    sol[names(sol)!='0'] 
} 

Nếu chúng tôi kiểm tra này trên ma trận của bạn, mức tăng tốc độ đáng kể:

> system.time(diagmean(A)) 
    user system elapsed 
    2.58 0.00 2.58 

> system.time(sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)]))) 
    user system elapsed 
    38.93 4.01 42.98 

Lưu ý rằng chức năng này tính cả hình tam giác trên và dưới. Bạn có thể tính toán ví dụ: chỉ có hình tam giác dưới bằng cách sử dụng:

diagmean <- function(A){ 
    id <- row(A) - col(A) 
    id[id>=0] <- NA 
    tapply(A,id,mean) 
} 

Kết quả này đạt được tốc độ khác. Lưu ý rằng các giải pháp sẽ bị đảo ngược so với bạn:

> A <- matrix(rep(c(1,2,3,4),4),ncol=4) 

> sapply(1:(nrow(A)-1), function(x) mean(A[row(A) == (col(A) - x)])) 
[1] 2.0 1.5 1.0 

> diagmean(A) 
-3 -2 -1 
1.0 1.5 2.0 
+0

Tuyệt vời, ít hơn 1 giây cho ma trận 1k^2 trên máy của tôi. Cảm ơn rất nhiều – blmoore

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