2017-09-26 1 views
1

Ich habe mich gefragt: Angenommen, Sie wollen eine Matrix verwandeln, zum Beispiel, und Sie wollen so etwas wieapply(), wenn die Funktion auf Index abhängt und mutieren() Effizienz

Y[i,j] = i*j*X[i,j] 

eine Verwendung für die Schleife ist viel langsamer als andere Optionen, und apply() weiß nicht, welche i und j es verwendet.

Eine Lösung, die ich mir vorstellen kann, ist die Definition eines data.frame-ähnlichen Objekts mit den Spalten i, j, X und dann die Verwendung von mutate(), um die gewünschten Y-Werte zu erhalten.

Ich habe zwei Fragen:

(a) Ist es möglich, die obige Matrix zu konstruieren, einen statt for-Schleife apply()? Wenn ja, ist es effizienter, es so zu konstruieren oder den muate() -Trick zu verwenden?

(b) Angenommen, ich habe sowohl Matrix- als auch Data.frame-Objektdarstellungen. Was ist effizienter, wenn ich Operationen mit Zeilen- und Spaltenindex ausführen möchte? Zum Beispiel, wenn eine Statistik wie die Summe von (Y [i, j] - Mittelwert (Y)) ²/(i * j) wollen. Ich weiß, dass ich Matrizen mit den Zeilen- und Spaltenindizes konstruieren kann und dann einfach vektorisierte Funktionen verwenden kann, aber ist es besser als die Verwendung von Mutate?

Antwort

4

Je nachdem, wie groß und spärlich Ihre Matrix ist, das erste, was Sie können geben einen Versuch ist verwenden row und col Funktion row und column Indizes jeweils zu konstruieren, und dann verwenden Sie Ihre Matrix zu transformieren:

X <- matrix(1:9, 3, 3) 

row(X) * col(X) * X 
#  [,1] [,2] [,3] 
#[1,] 1 8 21 
#[2,] 4 20 48 
#[3,] 9 36 81 

Dann für (Y[i,j] - mean(Y))²/(i*j), ist es ähnlich:

Y <- row(X) * col(X) * X 
(Y - mean(Y))^2/(row(Y) * col(Y)) 

#   [,1]  [,2]  [,3] 
#[1,] 592.11111 150.222222 6.259259 
#[2,] 227.55556 7.111111 85.629630 
#[3,] 88.92593 18.962963 344.308642 

Dies ist ein vollständig vektorisierter Ansatz, der keine apply oder for loop erfordert, aber zusätzlichen Speicher benötigt.

2

Ich denke outer kann schneller sein, dass row(X) * col(X).

# Define dimensions 
n.rows <- n.cols <- 1000 

# Define matrix 
X <- matrix(runif(n.rows * n.cols), ncol = n.cols) 

# Psidom's approach 
rowcol.method <- function(X){row(X) * col(X) * X} 

# Approach using outer 
outer.method <- function(X){outer(1:nrow(X), 1:ncol(X)) * X} 

# Benchmark library 
library(microbenchmark) 

# Test 
microbenchmark(
    rowcol.method(X), 
    outer.method(X) 
) 

Ergebnisse:

Unit: milliseconds 
      expr  min  lq  mean median  uq  max neval cld 
rowcol.method(X) 20.895870 21.154815 23.795695 21.612485 22.584323 62.50660 100 b 
    outer.method(X) 5.608577 5.729724 6.883643 5.836526 5.977156 50.12508 100 a 

Vergleichen Ausgabe:

identical(rowcol.method(X), outer.method(X)) 
[1] TRUE 

Ähnliches gilt für die andere Berechnung, obwohl es war eine verrückte Ausreißer für den äußeren Ansatz (221.66718 ms).

# Define matrix 
Y <- row(X) * col(X) * X 

# Psidom's approach 
rowcol.method.Y <- function(Y) {(Y - mean(Y))^2/(row(Y) * col(Y))} 

# Approach using outer 
outer.method.Y <- function(Y) {(Y - mean(Y))^2/outer(1:nrow(X), 1:ncol(X))} 

# Test 
microbenchmark(
    rowcol.method.Y(Y), 
    outer.method.Y(Y) 
) 

Ergebnisse:

Unit: milliseconds 
       expr  min  lq  mean median  uq  max neval cld 
rowcol.method.Y(Y) 27.94405 30.18635 34.63551 33.32627 37.06467 46.58983 100 b 
    outer.method.Y(Y) 11.27064 12.66349 18.77192 15.66756 18.18864 221.66718 100 a 

Vergleichen Ausgabe:

identical(rowcol.method.Y(Y), outer.method.Y(Y)) 
[1] TRUE 
Verwandte Themen