2016-05-29 11 views
1

in Mathematica, I-Arrays machen kann mit:Assign Array-Werte in R mit der Funktion der Indizes

Table[f(x1, x2, ..., xn), {x1, v1}, {x2, v2}, ..., {xn, vn}] 

Wo f irgendeine Funktion ist, sind die xi Variablen und die entsprechenden vi sind die Vektoren von Werten, die Variablen übernehmen. Wenn die vi Längen Li haben, dann ist das Array L1xL2x...xLn.

Ist diese Funktion in R mit eingebauter Funktion verfügbar, oder müsste ich dafür ein eigenes Programm schreiben?

Hier ist eine Funktion, die ich geschrieben habe, die erreicht, was ich will, aber gibt es eine eingebaute Funktion, die das tut?

# Function definition 
xapply <- function(fun,vecs){ 
n <- length(vecs) 
dims <- sapply(vecs,length) 
prods <- c(1,cumprod(dims)) 
ivecs <- vector(mode="list",length=n) 
for(i in seq(n)){ 
    ivecs[[i]] <- rep(rep(vecs[[i]],each=prods[i]),prods[n+1]/prods[i+1]) 
} 
my.args <- c(fun,ivecs) 
return(array(do.call(mapply,my.args),dims)) 
} 

# Example 
v1=c(1,2,3,4) 
v2=c(10,20,30,40,50) 
v3=c(100,200,300) 
v123=list(v1,v2,v3) 
my.array1 <- xapply(function(x,y,z) x+y+z,v123) 
my.array1 
+0

Haben Sie jede mögliche v1 X v2 X ... X vn Kombination berechnet werden sollen? – lmo

Antwort

1

Hier ist, wie würde ich Dazu mit dem Lambda und Vektorliste v123 als Eingabe demonstriert:

array(do.call(function(x,y,z) x+y+z,unname(do.call(expand.grid,v123))),lapply(v123,length)); 
## , , 1 
## 
##  [,1] [,2] [,3] [,4] [,5] 
## [1,] 111 121 131 141 151 
## [2,] 112 122 132 142 152 
## [3,] 113 123 133 143 153 
## [4,] 114 124 134 144 154 
## 
## , , 2 
## 
##  [,1] [,2] [,3] [,4] [,5] 
## [1,] 211 221 231 241 251 
## [2,] 212 222 232 242 252 
## [3,] 213 223 233 243 253 
## [4,] 214 224 234 244 254 
## 
## , , 3 
## 
##  [,1] [,2] [,3] [,4] [,5] 
## [1,] 311 321 331 341 351 
## [2,] 312 322 332 342 352 
## [3,] 313 323 333 343 353 
## [4,] 314 324 334 344 354 
## 
identical(.Last.value,my.array1); 
## [1] TRUE 

Der Vorteil dieser Linie über eine apply() - oder Map() -basierte Lösung ist, dass es vektorisiert wird. Es wird nur ein Aufruf an die Funktion vorgenommen.

Zuerst wird expand.grid() über do.call() mit der Vektorliste als Argumentliste aufgerufen. Dies erzeugt einen Datenrahmen, der alle möglichen Kombinationen der Eingabevektoren enthält, einen pro Reihe. Wir müssen dann die automatisch generierten Spaltennamen aus dem data.frame entfernen, indem wir unname() aufrufen.

Wir können dann das resultierende unbenannte data.frame als Argumentliste an das Lambda übergeben, das wiederum über do.call() aufgerufen wird. Dies funktioniert, weil data.frames intern Listen mit einer Listenkomponente pro Spalte sind, daher ist data.frame für die Verwendung als Liste von Argumenten geeignet, die von do.call() erwartet werden. Dies verdeutlicht auch, warum der Anruf benötigt wurde; andernfalls würde das Lambda mit benannten Argumenten aufgerufen werden (die automatisch generierten Namen wären Var1, Var2, Var3), die nicht an die Parameter binden würden (x, y, z).

Das Ergebnis des vektorisierten Lambda-Aufrufs ist ein atomarer Vektor. Da Sie ein Array möchten, müssen wir es in einen Aufruf von array() einbinden und die entsprechende Dimensionalität aus den Längen der Eingabevektoren über übergeben.


Auch Sie können in die outer() Funktion aussehen sollen, die intern führt diese Art von kartesischer Expansion, vektorisiert Anruf und Dimensionalität Verpackung, aber nur für zwei Eingangsobjekte zu einem Zeitpunkt.

+0

Vielen Dank für die Erklärung so gründlich! Ich bin neu in R und lerne immer noch die Unterschiede zwischen Datenrahmen, Listen usw. und wie man sie richtig benutzt. Mathematica schien so viel einfacher; Es gab nur Listen. – Joe

+0

Diese äußere() Funktion ist genau das, was ich gesucht habe! Ich wünschte, dass, anstatt nur Matrizen zu machen, eine variable Anzahl von Vektoren benötigt würde, um Arrays mit mehr Dimensionen zu erstellen. – Joe

0

Wenn Ihr Ziel ist, eine Funktion zu jeder Kombination von v1 anzuwenden ist ... vn, könnten Sie expand.grid und apply verwenden:

x1 <- 1:5 
x2 <- 1:10 
x3 <- 8:10 

# get the average 
apply(expand.grid(x1,x2,x7), 1, FUN=mean) 
# get the sum of squares 
apply(expand.grid(x1,x2,x7), 1, FUN=function(i) sum(i^2)) 

Wenn Sie stattdessen v1, ..., vn von gleicher Länge und Sie eine Funktion auf entsprechende Einträge anwenden möchten, können Sie Map (oder mapply) verwenden

x1 <- 1:5 
x2 <- 2:6 
x3 <- 6:10 
# get the sum of squares 
Map(f=function(x,y,z) sum(x^2 + y^2 + z^2), x1, x2, x3) 
+0

Danke für die Einführung in die Funktion expand.grid. Ich versuche jedoch, das Rückgabeobjekt ein Array A der Dimensionen L1xL2x ... xLn zu haben, so dass A [i1, i2, ..., in] = f (i1, i2, ..., in) . – Joe

+0

Bedeutet dies e/xpand.grid, aber die Ausgabe wird in ein Array der Dimensionen vi reorganisiert? – lmo

+0

Nicht genau. Jede Zeile von expand.grid wäre die Eingabe der Funktion für ein bestimmtes Element des Arrays. In der Tat bin ich sicher, dass ich expand.grid verwenden kann, um meine Antwort unten erheblich zu vereinfachen! Ich frage mich nur, ob es dafür bereits eine eingebaute Funktion gibt. – Joe

0

Hier ist ein weiterer Weg, wie ich meine Arrays mit expand.grid(), aber es ist etwas anders formatiert als meine ursprüngliche Frage in: (1) Ich gebe die Vektoren einzeln, anstatt in einem list, (2) Ich definiere die Funktion mit den Variablen x [1], x [2] usw., und (3) ich nehme an, dass ich die Längen der Vektoren kenne. Ich wünsche mir immer noch, dass äußere() würde eine beliebige Anzahl von Arrays als Argumente, weil diese Funktion genau das, was ich will, aber nur für zwei Arrays.

array(apply(expand.grid(1:4,4:8,3:5), 1, function(x) 100*x[1]+10*x[2]+x[3]),c(4,5,3)) 
1

ich hätte verwendet rowSums (die hte Ort Ihrer Funktion übernimmt) und verwendet es auf dem Ergebnis der expand.grid, die die all-Kombinationen Erweiterungen tos:

> array(rowSums(expand.grid(v123)) , c(4,5,3)) 
, , 1 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 111 121 131 141 151 
[2,] 112 122 132 142 152 
[3,] 113 123 133 143 153 
[4,] 114 124 134 144 154 

, , 2 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 211 221 231 241 251 
[2,] 212 222 232 242 252 
[3,] 213 223 233 243 253 
[4,] 214 224 234 244 254 

, , 3 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 311 321 331 341 351 
[2,] 312 322 332 342 352 
[3,] 313 323 333 343 353 
[4,] 314 324 334 344 354 

Sie könnten ein verwenden weniger vektorisierte Lösung, wenn die Funktion nicht Zeile für Zeile ausgeführt wurde. Die mapply oder Reduce Funktionen würden Sie den gleichen Vektor erhalten:

> array(Reduce("+", expand.grid(v123)) , c(4,5,3)) 
, , 1 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 111 121 131 141 151 
[2,] 112 122 132 142 152 
[3,] 113 123 133 143 153 
[4,] 114 124 134 144 154 

, , 2 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 211 221 231 241 251 
[2,] 212 222 232 242 252 
[3,] 213 223 233 243 253 
[4,] 214 224 234 244 254 

, , 3 

    [,1] [,2] [,3] [,4] [,5] 
[1,] 311 321 331 341 351 
[2,] 312 322 332 342 352 
[3,] 313 323 333 343 353 
[4,] 314 324 334 344 354 
Verwandte Themen