Pergunta

Suponha que eu tenha uma matriz por 2 e uma função que toma um vetor 2 como um de seus argumentos. Eu gostaria de aplicar a função a cada linha da matriz e obter um vetor N. Como fazer isso em r?

Por exemplo, gostaria de calcular a densidade de uma distribuição normal 2D padrão em três pontos:

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))

Como aplicar a função a cada linha de out?

Como passar valores para os outros argumentos além dos pontos para a função da maneira como você especificar?

Foi útil?

Solução

Você simplesmente usa o apply() função:

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> 

Isso leva uma matriz e aplica uma função (boba) a cada linha. Você passa argumentos extras para a função como quarto, quinto, ... argumentos para apply().

Outras dicas

Caso você queira aplicar funções comuns, como soma ou média, você deve usar rowSums ou rowMeans já que eles são mais rápidos do que apply(data, 1, sum) abordagem. Caso contrário, fique com apply(data, 1, fun). Você pode passar argumentos adicionais após o argumento divertido (como Dirk já sugeriu):

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

Então você pode fazer algo assim:

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

Aqui está um pequeno exemplo de aplicação de uma função a cada linha de uma matriz. (Aqui, a função aplicada normaliza cada linha para 1.)

Observação: O resultado do apply() Teve que ser transposto usando t() Para obter o mesmo layout que a matriz de entrada A.

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) ))

Resultado:

     [,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

A primeira etapa seria fazer o objeto de função e depois aplicá -lo. Se você deseja um objeto Matrix que tenha o mesmo número de linhas, você pode predefini -lo e usar o formulário [] como ilustrado (caso contrário, o valor retornado será simplificado a um vetor):

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 você quiser usar outros parâmetros padrão, a chamada deve incluir argumentos nomeados após a função:

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

Aplicar () também pode ser usado em matrizes dimensionais mais altas e o argumento da margem pode ser um vetor e também um número inteiro.

Inscreva -se bem o trabalho, mas é bastante lento. Usar Sapply e Vapply pode ser útil. O RowWise da DPLYR também pode ser útil, vamos ver um exemplo de como fazer o produto de linha de qualquer quadro de dados.

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

Observe que atribuir à variável antes de usar o VAPPLY/ SAPPLY/ APLICAR é uma boa prática, pois reduz muito o tempo. Vamos ver os resultados da 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))
)

Dê uma olhada cuidadosa de como T () está sendo usado

Outra abordagem se você quiser usar uma parte variável do conjunto de dados em vez de um único valor é usar rollapply(data, width, FUN, ...). O uso de um vetor de larguras permite aplicar uma função em uma janela variável do conjunto de dados. Eu usei isso para criar uma rotina de filtragem adaptativa, embora não seja muito eficiente.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top