2015-05-15 5 views
7

Sto cercando di evitare l'utilizzo di loop utilizzando apply per applicare una funzione definita dall'utente a una matrice. Il problema che ho è che ci sono parametri aggiuntivi che la mia funzione usa e differiscono per ogni colonna della matrice. Di seguito è un esempio di giocattolo.Utilizzare "apply" per applicare una funzione a una matrice in cui i parametri sono specifici della colonna

Say Ho la seguente funzione:

foo <- function(x, a, b, c) return((a*x + b)^c) 

e voglio applicarlo a una matrice bar utilizzando diversi valori di a, b e c per ogni colonna.

bar <- matrix(1:15, ncol = 3) 
a <- 4:6 
b <- 3:1 
c <- 1:3 

In questo caso, per la prima colonna di bar, allora a=4, b=3 e c=1. Ho provato questo,

apply(bar, 2, foo, a=a, b=b, c=c) 

ma questo è chiaramente non corretto, come ogni colonna utilizza tutti i parametri in sequenza prima di avvolgere indietro al primo parametro di nuovo. Eventuali suggerimenti?

risposta

12

Potremmo split il 'bar' da 'colonna' (col(bar)) e con mapply possiamo applicare 'foo' per il corrispondente 'a', 'b', valori 'C' per ogni colonna di 'bar'

mapply(foo, split(bar, col(bar)), a, b, c) 

O senza utilizzare apply

ind <- col(bar) 
(a[ind]*bar +b[ind])^c[ind] 
+2

Invece di 'split' puoi usare anche 'as.data.frame'. – nicola

+0

@nicola Sì, ho pensato di mantenerlo nella 'matrix' – akrun

+2

Avevo già messo in primo piano il primo e ora vorrei che ci fosse la possibilità di aggiungere voti per modifiche eccezionalmente eleganti. –

2

Si potrebbe mettere i parametri nel vettore:

newbar <- rbind(a,b,c,bar) 
newfoo <- function(z){x <- z[-(1:3)]; (z[1]*x+z[2])^z[3]} 
apply(newbar,2,newfoo) 

che dà

[,1] [,2] [,3] 
    7 1024 300763 
    11 1369 389017 
    15 1764 493039 
    19 2209 614125 
    23 2704 753571 
2

È possibile utilizzare sweep; di solito questo è per sottrarre la media di ogni colonna, ma è possibile passare in un indice invece di ottenere indicizzazione parallelo attraverso una, b, c:

> sweep(bar, 2, seq_along(a), function(x,i) foo(x, a[i], b[i], c[i]), FALSE) 
    [,1] [,2] [,3] 
[1,] 7 1024 300763 
[2,] 11 1369 389017 
[3,] 15 1764 493039 
[4,] 19 2209 614125 
[5,] 23 2704 753571 
+0

Vedere anche http://stackoverflow.com/questions/3444889/how-to-use-the-r-function-sweep –

9

non vedo perchè perdere tempo con una funzione affatto :

> a <- matrix(4:6,nrow = 5,ncol = 3,byrow = TRUE) 
> b <- matrix(3:1,nrow = 5,ncol = 3,byrow = TRUE) 
> c <- matrix(1:3,nrow = 5,ncol = 3,byrow = TRUE) 
> (a*bar + b)^c 
    [,1] [,2] [,3] 
[1,] 7 1024 300763 
[2,] 11 1369 389017 
[3,] 15 1764 493039 
[4,] 19 2209 614125 
[5,] 23 2704 753571 
+0

Questo è più elegante, anche se avrei dovuto provarlo .. – akrun

+0

@akrun Ah, ho perso il fine della tua risposta – joran

+0

Va bene. Non l'avrei mai indovinato in ogni caso – akrun

3

Credo che si può solo trasporre tua matrice e l'uso vettorializzazione:

t(foo(t(bar),a,b,c)) 

Questo dovrebbe funzionare per ogni vettorializzare foo.

Problemi correlati