2017-09-02 45 views
5

Tôi gặp vấn đề sau: Tôi cần nhiều tập hợp con của một ma trận lớn. Trên thực tế tôi chỉ cần xem như đầu vào cho một hàm f(), vì vậy tôi không cần phải thay đổi các giá trị. Tuy nhiên có vẻ như, R là rất chậm cho nhiệm vụ này, hoặc tôi đang làm một cái gì đó sai (có vẻ như nhiều khả năng). Ví dụ đồ chơi minh họa lượng thời gian cần để chọn các cột và sau đó sử dụng chúng trong một hàm khác (trong ví dụ đồ họa này là hàm tổng hợp nguyên thủy()). Là 'điểm chuẩn', tôi cũng kiểm tra thời gian tính toán để tổng hợp toàn bộ ma trận, nhanh hơn đáng ngạc nhiên. Tôi cũng đã thử nghiệm với gói ref, tuy nhiên không thể đạt được bất kỳ đạt được hiệu suất. Vì vậy, câu hỏi quan trọng là làm thế nào để subset ma trận mà không cần sao chép nó? Tôi đánh giá cao sự giúp đỡ nào, Cảm ơn!Việc nạp nhanh ma trận trong R

library(microbenchmark) 
library(ref) 

m0 <- matrix(rnorm(10^6), 10^3, 10^3) 
r0 <- refdata(m0) 
microbenchmark(m0[, 1:900], sum(m0[, 1:900]), sum(r0[,1:900]), sum(m0)) 
Unit: milliseconds 
      expr  min  lq  mean median  uq 
     m0[, 1:900] 10.087403 12.350751 16.697078 18.307475 19.054157 
sum(m0[, 1:900]) 11.067583 13.341860 17.286514 19.123748 19.990661 
sum(r0[, 1:900]) 11.066164 13.194244 16.869551 19.204434 20.004034 
      sum(m0) 1.015247 1.040574 1.059872 1.049513 1.067142 
     max neval 
58.238217 100 
25.664729 100 
23.505308 100 
    1.233617 100 

Nhiệm vụ chuẩn của cách tổng hợp toàn bộ ma trận mất 1,059872 mili giây và nhanh hơn so với các chức năng khác khoảng 16 lần.

+0

tôi nhận được một thông báo lỗi khi Tôi thử ví dụ của bạn: 'Lỗi trong r0 [, 1: 900]: số không chính xác của các tham số' – 5th

+0

' thư viện ('ref') 'sửa chữa nó – dvantwisk

+0

OK vì vậy các tiêu chí ở đây cho một giải pháp là gì? Liệu nó có phải nhanh hơn những gì bạn đang làm bây giờ hay nó sẽ nhanh hơn tổng hợp toàn bộ ma trận? –

Trả lời

4

Vấn đề với giải pháp của bạn là việc subsetting đang phân bổ một ma trận khác, điều này cần có thời gian.

Bạn có hai giải pháp:

Nếu thời gian thực hiện với sum trên toàn bộ ma trận không quan trọng với bạn, bạn có thể sử dụng colSums trên toàn bộ ma trận và tập hợp con các kết quả:

sum(colSums(m0)[1:900]) 

Hoặc bạn có thể sử dụng Rcpp để tính toán các sum với subsetting mà không cần sao chép ma trận.

#include <Rcpp.h> 
using namespace Rcpp; 

// [[Rcpp::export]] 
double sumSub(const NumericMatrix& x, 
       const IntegerVector& colInd) { 

    double sum = 0; 

    for (IntegerVector::const_iterator it = colInd.begin(); it != colInd.end(); ++it) { 
    int j = *it - 1; 
    for (int i = 0; i < x.nrow(); i++) { 
     sum += x(i, j); 
    } 
    } 

    return sum; 
} 

    microbenchmark(m0[, 1:900], sum(m0[, 1:900]), sum(r0[,1:900]), sum(m0), 
        sum(colSums(m0)[1:900]), 
        sumSub(m0, 1:900)) 
Unit: milliseconds 
        expr  min  lq  mean median  uq  max neval 
      m0[, 1:900] 4.831616 5.447749 5.641096 5.675774 5.861052 6.418266 100 
     sum(m0[, 1:900]) 6.103985 6.475921 7.052001 6.723035 6.999226 37.085345 100 
     sum(r0[, 1:900]) 6.224850 6.449210 6.728681 6.705366 6.943689 7.565842 100 
       sum(m0) 1.110073 1.145906 1.175224 1.168696 1.197889 1.269589 100 
sum(colSums(m0)[1:900]) 1.113834 1.141411 1.178913 1.168312 1.201827 1.408785 100 
     sumSub(m0, 1:900) 1.337188 1.368383 1.404744 1.390846 1.415434 2.459361 100 

Bạn có thể sử dụng unrolling optimization để tiếp tục tối ưu hóa phiên bản Rcpp.

+0

Vâng, đây là câu trả lời. +1. Tôi nghĩ rằng bình luận của tôi gọi nó ra trước khi chúng tôi thực hiện nó xứng đáng là 1 quá tho;) Mặc dù vậy, nếu 'sum (colSums (m0) [1: 900])' làm điều đó tốt, chúng ta thậm chí không cần cồng kềnh hơn ' Rcpp'. –

+0

Cảm ơn bạn đã phản hồi. Có, tôi nghĩ rằng bạn vô cùng đúng. Vấn đề chính là cấp phát bộ nhớ cho bản sao của ma trận. Có thể làm điều này trong R mà không cần sao chép ma trận? Tôi cần tập hợp con ma trận làm đầu vào cho một hàm tự viết khác, hàm sum() chỉ giao dịch như ví dụ ở đây. – maxatSOflow

+0

Về cơ bản, tôi tạo tất cả các chức năng của mình để chúng có thể opper trên một tập con của một ma trận. Nếu bạn không muốn tạo bản sao, bạn sẽ chỉ cần các chức năng như thế này. –

0

Sử dụng compiler Tôi đã viết một chức năng mà được kết quả về 2x nhanh như các phương pháp khác của bạn (8x của sum(m0) thay vì 16x):

require(compiler) 

compiler_sum <- cmpfun({function(x) { 
    tmp <- 0 
    for (i in 1:900) 
     tmp <- tmp+sum(x[,i]) 
    tmp 
}}) 

microbenchmark( 
       sum(m0), 
       compiler_sum(m0) 
       ) 
Unit: milliseconds 
      expr  min  lq  mean median  uq  max 
      sum(m0) 1.016532 1.056030 1.107263 1.084503 1.11173 1.634391 
compiler_sum(m0) 7.655251 7.854135 8.000521 8.021107 8.29850 16.760058 
neval 
    100 
    100 
Các vấn đề liên quan