2013-09-05 18 views
9

Tôi đang làm việc với mảng đa chiều cả trên R và MATLAB, các mảng này có năm chiều (tổng số 14,5 triệu phần tử). Tôi phải loại bỏ một kích thước áp dụng một trung bình số học trên nó và tôi phát hiện ra một sự khác biệt tuyệt vời của buổi biểu diễn bằng cách sử dụng hai phần mềm.Số học trung bình trên một mảng đa chiều trên R và MATLAB: sự khác biệt quyết liệt của biểu diễn

MATLAB:

>> a = rand([144 73 10 6 23]); 
>> tic; b = mean(a,3); toc 
Elapsed time is 0.014454 seconds. 

R:

> a = array(data = runif(144*73*6*23*10), dim = c(144,73,10,6,23)) 
> start <- Sys.time(); b = apply(a, c(1,2,4,5), mean); Sys.time() - start 
Time difference of 1.229083 mins 

Tôi biết rằng áp dụng chức năng là chậm vì là một cái gì đó giống như một chức năng mục đích chung, nhưng tôi không biết làm thế nào để đối phó với vấn đề này bởi vì sự khác biệt về buổi biểu diễn này thực sự là một giới hạn lớn đối với tôi. Tôi đã cố gắng để tìm kiếm một generalisation của colMeans/rowMeans chức năng nhưng tôi đã không thành công.

EDIT tôi sẽ hiển thị một ma trận mẫu nhỏ:

> dim(a) 
[1] 2 4 3 
> dput(aa) 
structure(c(7, 8, 5, 8, 10, 11, 9, 9, 6, 12, 9, 10, 12, 10, 14, 
12, 7, 9, 8, 10, 10, 9, 8, 6), .Dim = c(2L, 4L, 3L)) 
a_mean = apply(a, c(2,3), mean) 
> a_mean 
    [,1] [,2] [,3] 
[1,] 7.5 9.0 8.0 
[2,] 6.5 9.5 9.0 
[3,] 10.5 11.0 9.5 
[4,] 9.0 13.0 7.0 

EDIT (2):

tôi phát hiện ra rằng việc áp dụng chức năng tổng hợp và sau đó chia cho kích thước của loại bỏ kích thước chắc chắn nhanh hơn:

> start <- Sys.time(); aaout = apply(aa, c(1,2,4,5), sum); Sys.time() - start 
Time difference of 5.528063 secs 
+0

Bạn có thể làm giảm đầu vào/đầu ra mong muốn một mảng 3 chiều nhỏ cho mục đích minh họa, ví dụ ma trận 3 * 3 * 2? –

+0

@Matteodefelice xem http://stackoverflow.com/questions/18604406/why-is-mean-so-slow đặc biệt là câu trả lời của Joshua về độ chính xác. –

Trả lời

5

mean là đặc biệt chậm vì S3 phương pháp công văn. Đây là nhanh hơn:

set.seed(42) 
a = array(data = runif(144*73*6*23*10), dim = c(144,73,10,6,23)) 

system.time({b = apply(a, c(1,2,4,5), mean.default)}) 
# user system elapsed 
#16.80 0.03 16.94 

Nếu bạn không cần phải xử lý NA s bạn có thể sử dụng chức năng nội bộ:

system.time({b1 = apply(a, c(1,2,4,5), function(x) .Internal(mean(x)))}) 
# user system elapsed 
# 6.80 0.04 6.86 

Để so sánh:

system.time({b2 = apply(a, c(1,2,4,5), function(x) sum(x)/length(x))}) 
# user system elapsed 
# 9.05 0.01 9.08 

system.time({b3 = apply(a, c(1,2,4,5), sum) 
      b3 = b3/dim(a)[[3]]}) 
# user system elapsed 
# 7.44 0.03 7.47 

(Lưu ý rằng tất cả các timings chỉ là gần đúng. Điểm chuẩn thích hợp sẽ yêu cầu chạy này repreatedly, ví dụ, bằng cách sử dụng một trong các gói bechmarking. Nhưng tôi không đủ kiên nhẫn cho rằng ngay bây giờ.)

Có thể tăng tốc độ này với việc triển khai Rcpp.

+1

[** Xem tại đây **] (http://stackoverflow.com/a/18604487/1478381) để biết thêm thông tin. –

+0

Tôi cũng đã thử 'thư viện (data.table); system.time ({b3 = apply (a, c (1,2,4,5), hàm (x) .External ("Cfastmean", x, FALSE))}) ', nhưng nó không nhanh hơn. – Roland

+0

Cảm ơn bạn, bạn chắc chắn đã giúp tôi! Tôi cũng đã học được điều gì đó thực sự thú vị về cơ chế nội bộ R ... –

20

Trong R, apply không phải là công cụ phù hợp cho tác vụ. Nếu bạn có ma trận và cần hàng hoặc cột có nghĩa là, bạn sẽ sử dụng nhanh hơn nhiều, được vectorized rowMeanscolMeans.Bạn vẫn có thể sử dụng các cho một mảng đa chiều nhưng bạn cần phải có một chút sáng tạo:

Giả sử mảng của bạn có n kích thước, và bạn muốn tính toán phương tiện cùng chiều i:

  1. sử dụng aperm để di chuyển chiều i đến vị trí cuối cùng n
  2. sử dụng rowMeans với dims = n - 1

Tương tự, bạn có thể:

  1. sử dụng aperm để di chuyển chiều i đến vị trí đầu tiên
  2. sử dụng colMeans với dims = 1

a <- array(data = runif(144*73*6*23*10), dim = c(144,73,10,6,23)) 

means.along <- function(a, i) { 
    n <- length(dim(a)) 
    b <- aperm(a, c(seq_len(n)[-i], i)) 
    rowMeans(b, dims = n - 1) 
} 

system.time(z1 <- apply(a, c(1,2,4,5), mean)) 
# user system elapsed 
# 25.132 0.109 25.239 
system.time(z2 <- means.along(a, 3)) 
# user system elapsed 
# 0.283 0.007 0.289 

identical(z1, z2) 
# [1] TRUE 
+0

Chính xác. Luôn luôn sử dụng funcs vectorized trên vòng hoặc * áp dụng bất cứ khi nào có thể. –

+0

Điều này sẽ * chắc chắn * là câu trả lời được chấp nhận. 1 cho một lời giải thích tuyệt vời của trường hợp tổng quát. Tôi đã tìm kiếm 'aperm' nhưng không thể làm đúng. Cảm ơn! –

+0

Vì đầy đủ, 'rowMeans' không sử dụng cùng một thuật toán' mean' sử dụng; thứ nhất là tích lũy đơn lẻ và phân chia; sau này có một vượt qua thứ hai để cải thiện sự ổn định số. –

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