2012-09-09 3 views
6

Ho il seguente ciclo nidificato:iterare su prodotto cartesiano di vettori

for (x in xs) { 
    for (y in ys) { 
     # Do something with x and y 
    } 
} 

Quale mi piacerebbe appiattire così ho pensato di costruire un prodotto cartesiano dei due vettori xs e ys e l'iterazione sul risultato . In Python, questo sarebbe banale:

for xy in product(xs, ys): 
    # x, y = xy[0], xy[1] 

Ma in R, l'equivalente più semplice che ho trovato sembra scoraggiante:

xys <- expand.grid(xs, ys) 
for (i in 1 : nrow(xys)) { 
    xy <- as.vector(xys[i, ]) 
    # x <- xy[1], y <- xy[2] 
} 

Sicuramente ci deve essere un modo migliore, no? (Per chiarire, io non voglio iterare su un indice di ... Penso che ci deve essere un modo per scorrere direttamente sopra le tuple nel prodotto.)

risposta

8

È possibile utilizzare la funzione apply per applicare una funzione a ciascuna riga del frame di dati. Basta sostituire "your function" con la tua funzione attuale.

# example data 
xs <- rnorm(10) 
ys <- rnorm(10)  

apply(expand.grid(xs, ys), 1, FUN = function(x) {"your function"}) 

Questo è un esempio molto semplice. Qui, la somma di entrambi i valori in una riga viene calcolato:

apply(expand.grid(xs, ys), 1, FUN = function(x) {x[1] + x[2]}) 

qui è una variante che utilizza argomenti denominati (xs, ys) invece di indici (x[1], x[2]):

myfun <- function(xs, ys) xs + ys 
arguments <- expand.grid(xs = rnorm(10), ys = rnorm(10)) 
apply(arguments, 1, function(x)do.call(myfun, as.list(x))) 
+0

@Konrad Rudolph: non ho cancellato la mia risposta. Non c'era niente di sbagliato in questo. Non ero sicuro se fosse esattamente la soluzione che cercavi. @flodel ha ragione sui problemi usando 'apply' con tipi di input misti. In questo caso, puoi usare 'as.numeric' per trasformare una stringa in un valore numerico. Ma non ci sono problemi se si utilizzano solo vettori numerici. –

10

R ha un diverso paradigma di Python, così don' Mi aspetto che abbia generatori o tuple - abbiamo vettori e indici per questo.

In questo modo, per mappare una funzione su un prodotto cartesiano è sufficiente chiamare

outer(xs,ys,function(x,y) ...) 

e undim il risultato se lo si desidera.

EDIT: Nel caso xs o ys sono qualcosa di più complesso di vettori di base, una possibilità è quella di utilizzare indici, cioè

outer(seq(a=xs),seq(a=ys),function(xi,yi) ... xs[[xi]]/ys[xi,]/etc. ...) 

o mappare una funzione su un prodotto artigianale bit utilizzando mapply

mapply(function(x,y) ...,xs,rep(ys,each=length(xs))) 
+0

Non mi interessano i diversi paradigmi. Sono * preoccupato per la pervasività delle variabili dell'indice nel mio codice. Per quanto comprendo R, la maggior parte/tutti loro dovrebbero essere inutili. Il tuo codice di esempio * sembra * come quello che ho cercato da esso si comporta nel modo sbagliato: 'outer (1: 2, 3: 4, function (x, y) {print (sprintf ('% d,% d', x, y))} '- questo stampa un array * e * una matrice con i risultati - quindi non so come riscrivere il mio ciclo per lavorare qui ... (non so cosa intendi per" undim ", forse questo lo spiegherebbe.) –

+0

Uuh, il commento precedente è stupido: la matrice è solo il valore restituito da 'outer'. Tuttavia, non sono ancora sicuro di come adattarlo per funzionare come una sostituzione del mio ciclo annidato, dal momento che 'x' e' y' sono vettori, non scalari.Sfortunatamente, ho davvero bisogno di scalari –

+0

@KonradRudolph Ok, esteso – mbq