2013-06-13 63 views
24

Tôi có ma trận m và một vector v. Tôi muốn nhân cột đầu tiên của ma trận m bởi phần tử đầu tiên của vector v và nhân cột thứ hai của ma trận m bởi phần tử thứ hai của vector v, v.v. Tôi có thể làm điều đó với các mã sau đây, nhưng tôi đang tìm một cách mà không yêu cầu hai cuộc gọi transpose. Làm thế nào tôi có thể làm điều này nhanh hơn trong R?Cách nhanh nhất để nhân các cột ma trận với các phần tử vectơ trong R

m <- matrix(rnorm(120000), ncol=6) 
v <- c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5) 

system.time(t(t(m) * v)) 

# user system elapsed 
# 0.02 0.00 0.02 
+0

liên quan: http://stackoverflow.com/q/3643555/946850 – krlmlr

Trả lời

33

Sử dụng một số đại số tuyến tính và thực hiện phép nhân ma trận, đó là khá nhanh trong R.

ví dụ

m %*% diag(v)

một số điểm chuẩn

m = matrix(rnorm(1200000), ncol=6) 

v=c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5) 
library(microbenchmark) 
microbenchmark(m %*% diag(v), t(t(m) * v)) 
## Unit: milliseconds 
##   expr  min  lq median  uq  max neval 
## m %*% diag(v) 16.57174 16.78104 16.86427 23.13121 109.9006 100 
##  t(t(m) * v) 26.21470 26.59049 32.40829 35.38097 122.9351 100 
+0

Quyền của Tha, chỉ cần là microbenchmark (m% *% diag (v), t (t (m) * v)) – rose

+0

Thực vậy, Thay đổi được thực hiện @rose – mnel

+1

Tôi đã thấy rằng kết quả phụ thuộc nhiều vào độ dài của 'v'. Đối với 'v' ngắn hơn, tùy chọn' diag() 'là nhanh hơn, nhưng cuối cùng thì chuyển đổi kép sẽ thắng. – krlmlr

3

Vì @Arun chỉ ra, tôi không biết rằng bạn sẽ đánh bại giải pháp của mình về hiệu quả thời gian. Về mã dễ hiểu, có những lựa chọn khác mặc dù:

Một lựa chọn:

> mapply("*",as.data.frame(m),v) 
     V1 V2 V3 
[1,] 0.0 0.0 0.0 
[2,] 1.5 0.0 0.0 
[3,] 1.5 3.5 0.0 
[4,] 1.5 3.5 4.5 

Và khác:

sapply(1:ncol(m),function(x) m[,x] * v[x]) 
+0

tôi nghi ngờ điều này sẽ được nhanh hơn so với làm việc trên ma trận (giải pháp đầu tiên của bạn, đặc biệt là). – Arun

+0

khi tôi kiểm tra hệ thống. Thời gian cho mẫu lớn không có sự khác biệt giữa chúng và nó không nhanh hơn. – rose

+0

@rose - Mặc dù cung cấp các lựa chọn thay thế, tôi đồng ý với Arun ở đây. Tôi không chắc chắn những gì là sai với 't (t (..' giải pháp – thelatemail

15

Nếu bạn có một số lượng lớn các cột t của bạn (t (m) * v) giải pháp nhanh hơn so với các giải pháp nhân ma trận bởi một rộng lề. Tuy nhiên, có một giải pháp nhanh hơn, nhưng nó đi kèm với chi phí cao trong việc sử dụng bộ nhớ. Bạn tạo một ma trận lớn như m bằng cách sử dụng rep() và nhân yếu tố. Dưới đây là ví dụ về so sánh, sửa đổi của mnel:

m = matrix(rnorm(1200000), ncol=600) 
v = rep(c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5), length = ncol(m)) 
library(microbenchmark) 

microbenchmark(t(t(m) * v), 
    m %*% diag(v), 
    m * rep(v, rep.int(nrow(m),length(v))), 
    m * rep(v, rep(nrow(m),length(v))), 
    m * rep(v, each = nrow(m))) 

# Unit: milliseconds 
#         expr  min   lq  mean  median   uq  max neval 
#       t(t(m) * v) 17.682257 18.807218 20.574513 19.239350 19.818331 62.63947 100 
#       m %*% diag(v) 415.573110 417.835574 421.226179 419.061019 420.601778 465.43276 100 
# m * rep(v, rep.int(nrow(m), ncol(m))) 2.597411 2.794915 5.947318 3.276216 3.873842 48.95579 100 
#  m * rep(v, rep(nrow(m), ncol(m))) 2.601701 2.785839 3.707153 2.918994 3.855361 47.48697 100 
#    m * rep(v, each = nrow(m)) 21.766636 21.901935 23.791504 22.351227 23.049006 66.68491 100 

Như bạn có thể thấy, sử dụng "mỗi" trong rep() hy sinh tốc độ cho sự rõ ràng. Sự khác biệt giữa rep.int và đại diện dường như không thể bỏ qua, cả hai triển khai hoán đổi vị trí trên các lần chạy lặp lại của microbenchmark(). Hãy nhớ rằng, ncol (m) == chiều dài (v).

autoplot

+0

Lưu ý rằng transpose kép cũng nhân đôi ma trận ít nhất một lần, không chắc chắn nếu sử dụng bộ nhớ tốt hơn nhiều so với việc mở rộng ma trận, bản thân mở rộng có thể được thực hiện dễ đọc hơn bằng cách sử dụng 'ma trận (v, nrow = nrow (m) , ncol = ncol (m), byrow = TRUE) '. – krlmlr

+0

Về giải pháp 'rep' bạn viết" ... đi kèm với chi phí cao trong việc sử dụng bộ nhớ ". Không phải 't (m)' có cùng chi phí, bởi vì điều này tạo ra một ma trận mới với cùng số lượng các phần tử như 'm'? – jochen

1

Như thực hiện bằng cách bluegrue, một đại diện đơn giản sẽ đủ cũng như để thực hiện phép nhân tố khôn ngoan.

Số phép nhân và tổng số được giảm bằng lề rộng như thể nhân ma trận đơn giản với diag() được thực hiện, trong trường hợp này có thể tránh được nhiều phép nhân.

m = matrix(rnorm(1200000), ncol=6) 
v=c(1.5, 3.5, 4.5, 5.5, 6.5, 7.5) 
v2 <- rep(v,each=dim(m)[1]) 
library(microbenchmark) 
microbenchmark(m %*% diag(v), t(t(m) * v), m*v2) 

Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
m %*% diag(v) 11.269890 13.073995 16.424366 16.470435 17.700803 95.78635 100 b 
    t(t(m) * v) 9.794000 11.226271 14.018568 12.995839 15.010730 88.90111 100 b 
     m * v2 2.322188 2.559024 3.777874 3.011185 3.410848 67.26368 100 a 
1

Vì mục đích hoàn chỉnh, tôi đã thêm sweep vào điểm chuẩn. Mặc dù tên thuộc tính một chút sai lầm của mình, tôi nghĩ rằng nó có thể dễ đọc hơn so lựa chọn thay thế khác, và cũng khá nhanh:

n = 1000 
M = matrix(rnorm(2 * n * n), nrow = n) 
v = rnorm(2 * n) 

microbenchmark::microbenchmark(
    M * rep(v, rep.int(nrow(M), length(v))), 
    sweep(M, MARGIN = 2, STATS = v, FUN = `*`), 
    t(t(M) * v), 
    M * rep(v, each = nrow(M)), 
    M %*% diag(v) 
) 

Unit: milliseconds 
             expr   min   lq  mean 
    M * rep(v, rep.int(nrow(M), length(v))) 5.259957 5.535376 9.994405 
sweep(M, MARGIN = 2, STATS = v, FUN = `*`) 16.083039 17.260790 22.724433 
           t(t(M) * v) 19.547392 20.748929 29.868819 
       M * rep(v, each = nrow(M)) 34.803229 37.088510 41.518962 
           M %*% diag(v) 1827.301864 1876.806506 2004.140725 
     median   uq  max neval 
    6.158703 7.606777 66.21271 100 
    20.479928 23.830074 85.24550 100 
    24.722213 29.222172 92.25538 100 
    39.920664 42.659752 106.70252 100 
1986.152972 2096.172601 2432.88704 100 
Các vấn đề liên quan