[R-br] Funcionamento (implementação) da função apply (lapply) em loops

Benilton Carvalho beniltoncarvalho em gmail.com
Terça Junho 14 09:08:51 BRT 2011


Atualmente, a ideia de *apply() ser mais rapido que for() nao eh
exatamente verdadeira.

A diferenca essencial (as far as users care) entre ambas eh que a
familia *apply cria um objeto de resposta para cada elemento de
entrada, ao passo que usuarios do for() fazem alocacao da resposta a
objetos pre-existentes (o que dispara uma copia e, consequentemente,
faz com que a execucao seja mais lenta).

Veja o exemplo abaixo (mude as dimensoes caso vc nao tenha RAM suficiente):

nc <- 1e6
nr <- 200

## com sapply
set.seed(1)
t0 <- system.time(res0 <- sapply(1:nr, function(x) rnorm(nc)))

## com for() usando o q a maioria de usuarios faz...
set.seed(1)
t1 <- system.time({res1 <- NULL; for (i in 1:nr) res1 <- cbind(res1,
rnorm(nc))})
all.equal(res0, res1)  ## deve ser TRUE
rm(res0)

## com for() mais eficiente
set.seed(1)
t2 <- system.time({res2 <- matrix(NA, nc=nr, nr=nc); for (i in 1:nr)
res2[,i] <- rnorm(nc)})
all.equal(res1, res2) ## deve ser TRUE
rm(res1); gc()

## com lapply()
set.seed(1)
t3 <- system.time(res3 <- do.call(cbind, lapply(1:nr, function(x) rnorm(nc))))
all.equal(res2, res3) ## deve ser TRUE
rm(res2, res3); gc()

## visualizando tempos
message(sprintf('sapply...........: %2.4f', t0[3]))
message(sprintf('for() usual......: %2.4f', t1[3]))
message(sprintf('for() pre-aloc..: %2.4f', t2[3]))
message(sprintf('do.call+lapply: %2.4f', t3[3]))

Os resultados que obtive na minha maquina sao:

sapply...........: 20.5400
for() usual......: 207.3900
for() pre-aloc..: 21.7730
do.call+lapply: 18.3960

Take-home messages:

1) for() mais lento e' fato qdo a programacao e' ineficiente;
2) lapply() e' sempre mais eficiente que sapply()

Take-home exercise: repita o for() com pre-alocacao usando listas,
combinando o resultado com do.call()... Isso e' tao rapido quanto o
do.call+lapply (na verdade, na minha execucao, ele eh ainda
ligeiramente mais rapido... levando 18.385s)...

b

2011/6/14 Junior Beleti <beleti.junior em gmail.com>:
> Boa noite,
>
> gostaria de entender o funcionamento da função apply, mais precisamente
> lapply, para loops.
>
> Já conheço a descrição de seu funcionamento:
>
> ‘lapply’ returns a list of the same length as ‘X’, each element of which is
> the result of applying ‘FUN’ to the corresponding element of ‘X’.
>
>
> Mas o que eu gostaria de saber é como ele funciona em sua essência. Por
> exemplo, utilizar um lapply ao invés de um loop "for" é mais rápido.
> Eu gostaria de saber o porque, ou seja, como o lapply é implementado.
>
> Não sei se fui claro, mas gostaria de encontrar a implementação da função
> lapply, o que não encontrei no diretório do pacote "base".
>
> Se alguém puder ajudar.
>
> Também peço desculpas por não ter dado grandes contribuições para a lista,
> mas creio ter mais experiência em programação (lógica) de fato, do que no
> ambiente R.
>
> Obrigado.
>
> --
> Carlos Roberto Beleti Junior
> Mestrado em Ciência da Computação
> Departamento de Informática
> Universidade Estadual de Maringá
>
> _______________________________________________
> R-br mailing list
> R-br em listas.c3sl.ufpr.br
> https://listas.inf.ufpr.br/cgi-bin/mailman/listinfo/r-br
> Leia o guia de postagem (http://www.leg.ufpr.br/r-br-guia) e forneça código
> mínimo reproduzível.
>



-- 
Successful people ask better questions, and as a result, they get
better answers. (Tony Robbins)


Mais detalhes sobre a lista de discussão R-br