Domanda

Supponiamo di avere un n da 2 a matrice e una funzione che prende un 2-vettore come uno dei suoi argomenti.Vorrei applicare la funzione per ogni riga della matrice e ottenere un n-vettore.Come fare questo in R?

Per esempio, vorrei calcolare la densità di un 2D distribuzione Normale standard su tre punti:

bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
    exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}

out <- rbind(c(1, 2), c(3, 4), c(5, 6))

Come applicare la funzione per ogni riga di out?

Come passare i valori per gli altri argomenti oltre i punti per la funzione nel modo in cui si specifica?

È stato utile?

Soluzione

È sufficiente utilizzare la funzione apply():

R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
     [,1] [,2]
[1,]    1    2
[2,]    3    4
[3,]    5    6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1]  4 10 16
R> 

Questo richiede una matrice e applica una funzione (stupido) per ogni riga. Si passa argomenti extra alla funzione di quarto, quinto, ... argomenti apply().

Altri suggerimenti

Nel caso in cui si desidera applicare le funzioni comuni come somma o media, si dovrebbe usare rowSums o rowMeans dato che sono più veloce di approccio apply(data, 1, sum). In caso contrario, bastone con apply(data, 1, fun). È possibile passare ulteriori argomenti che seguono argomento FUN (come Dirk già suggerito):

set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
     [,1] [,2] [,3] [,4]
[1,]   NA    5    2    3
[2,]    2   NA    2    4
[3,]    3    4   NA    5
[4,]    5    4    3   NA
[5,]    2    1    4    4

Poi si può fare qualcosa di simile:

apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
    [,1] [,2] [,3] [,4] [,5]
25%  2.5    2  3.5  3.5 1.75
50%  3.0    2  4.0  4.0 3.00
75%  4.0    3  4.5  4.5 4.00

Ecco un breve esempio dell'applicazione di una funzione per ogni riga di una matrice. (Qui, la funzione normalizza applicata ogni riga 1).

Nota. Il risultato della apply() doveva essere recepito utilizzando t() per ottenere lo stesso layout della A matrice di ingresso

A <- matrix(c(
  0, 1, 1, 2,
  0, 0, 1, 3,
  0, 0, 1, 3
), nrow = 3, byrow = TRUE)

t(apply(A, 1, function(x) x / sum(x) ))

Risultato:

     [,1] [,2] [,3] [,4]
[1,]    0 0.25 0.25 0.50
[2,]    0 0.00 0.25 0.75
[3,]    0 0.00 0.25 0.75

Primo passo: fare la funzione di oggetto, quindi l'applicazione di esso.Se si desidera un oggetto matrix che ha lo stesso numero di righe, è possibile impostare e utilizzare l'oggetto[] forma come illustrato (in caso contrario, il valore restituito sarà semplificata di un vettore):

bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
     exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
                           x[2]^2/sigma[2]^2-
                           2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 
     1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
     }
 out=rbind(c(1,2),c(3,4),c(5,6));

 bvout<-matrix(NA, ncol=1, nrow=3)
 bvout[] <-apply(out, 1, bvnormdens)
 bvout
             [,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15

Se si desidera utilizzare diverso da quello di default i parametri quindi, la chiamata dovrebbe includere argomenti denominati dopo la funzione:

bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)

apply() può essere utilizzato anche su matrici di dimensione superiore, e il MARGINE argomento può essere un vettore così come un numero intero.

Applica fa il lavoro bene, ma è piuttosto lento. Utilizzando sapply e vapply potrebbe essere utile. rowwise di dplyr potrebbe anche essere utile Vediamo un esempio di come fare fila saggio prodotto di una struttura dati.

a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)

Si noti che l'assegnazione alla variabile prima di utilizzare vapply / sapply / applicare è buona pratica in quanto riduce il tempo molto. Vediamo i risultati microbenchmark

a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
    apply(b, 1 , prod),
    vapply(a, prod, 0),
    sapply(a, prod) , 
    apply(iris[1:10,1:3], 1 , prod),
    vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
    sapply(data.frame(t(iris[1:10,1:3])), prod) ,
    b %>%  rowwise() %>%
        summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)

Dai uno sguardo attento a come t () viene utilizzato

Un altro approccio, se si desidera utilizzare una parte variare del set di dati, invece di un singolo valore è quello di utilizzare rollapply(data, width, FUN, ...). Utilizzando un vettore di larghezze consente di applicare una funzione su una finestra diversa del set di dati. Ho usato questo per costruire una routine di filtraggio adattativo, anche se non è molto efficiente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top