2017-09-02 4 views
5

Ich habe das folgende Problem: Ich brauche viele Teilmengen einer großen Matrix. Eigentlich brauche ich nur Ansichten als Eingabe für eine andere Funktion f(), also muss ich die Werte nicht ändern. Es scheint jedoch, dass R für diese Aufgabe schrecklich langsam ist oder ich etwas falsch mache (was eher wahrscheinlich erscheint). Das Spielzeugbeispiel zeigt, wie viel Zeit es dauert, nur die Spalten auszuwählen und sie dann in einer anderen Funktion zu verwenden (in diesem Spielzeugbeispiel die primitive Funktion sum()). Als "Benchmark" teste ich auch die Rechenzeit gegen die Zusammenfassung der gesamten Matrix, die überraschend schneller ist. Ich experimentierte auch mit dem Paket Ref, konnte jedoch keinen Leistungszuwachs erzielen. Die Schlüsselfrage ist also, wie man die Matrix unterteilen kann, ohne sie zu kopieren? Ich freue mich über jede Hilfe, Danke!Schnelle Unterteilung einer Matrix in 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 

Die Benchmark-Aufgabe, die gesamte Matrix Summieren nimmt 1,059872 Millisekunden und ist etwa 16-mal schneller als die anderen Funktionen.

+0

ich eine Fehlermeldung erhalten, wenn Ich versuche dein Beispiel: 'Fehler in r0 [, 1: 900]: falsche Anzahl von Dimensionen' – 5th

+0

' Bibliothek ('ref') 'behebt es – dvantwisk

+0

OK also, was ist die Kriterien hier für eine Lösung? Muss es einfach schneller sein als das, was Sie gerade tun, oder müsste es schneller sein als die gesamte Matrix zu summieren? –

Antwort

4

Das Problem mit Ihrer Lösung ist, dass die Teilmenge eine andere Matrix zuweist, die Zeiten braucht.

Sie haben zwei Lösungen:

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

Oder Sie:

Wenn die mit sum auf der gesamten Matrix genommen Zeit mit Ihnen in Ordnung ist, können Sie colSums auf die gesamte Matrix und Teilmenge das Ergebnis verwenden könnte könnte Rcpp verwenden, um die sum mit Subsetting zu berechnen, ohne die Matrix zu kopieren.

#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 

könnten Sie unrolling optimization verwenden, um die RCPP Version zu optimieren.

+0

Ja, das ist die Antwort. +1. Ich denke, dass mein Kommentar, bevor wir es implementiert haben, es verdient +1 verdient hat;) Wirklich, wenn 'sum (colSums (m0) [1: 900])' so gut tut, brauchen wir nicht einmal das schwerere ' Rcpp'. –

+0

Danke für die Antwort. Ja, ich denke du bist absolut richtig. Das Hauptproblem ist die Zuweisung von Speicher für die Kopie der Matrix. Ist es möglich, dies in R zu tun, ohne die Matrix zu kopieren? Ich brauche die Matrix-Untermenge als Eingabe für eine andere selbstgeschriebene Funktion, die Funktion sum() behandelt hier nur ein Beispiel. – maxatSOflow

+0

Grundsätzlich mache ich alle meine Funktionen so, dass sie auf eine Teilmenge einer Matrix wirken können. Wenn Sie keine Kopie erstellen möchten, benötigen Sie nur solche Funktionen. –

0

Mit compiler schrieb ich eine Funktion, die das Ergebnis über 2x bekommt so schnell wie Ihre andere Methoden (8x dass die sum(m0) statt 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