Estou aprendendo R recentemente e confuso com duas funções: lapply
e do.call
. Parece que eles são similares à map
função no Lisp. Mas por que existem duas funções com um nome tão diferente? Por que R não usa apenas uma função chamada map
?
Estou aprendendo R recentemente e confuso com duas funções: lapply
e do.call
. Parece que eles são similares à map
função no Lisp. Mas por que existem duas funções com um nome tão diferente? Por que R não usa apenas uma função chamada map
?
Respostas:
Há uma função chamada Map
que pode ser semelhante ao mapa em outros idiomas:
lapply
retorna uma lista do mesmo tamanho que X, cada elemento resultante da aplicação de FUN ao elemento correspondente de X.
do.call
constrói e executa uma chamada de função a partir de um nome ou uma função e uma lista de argumentos a serem passados para ele.
Map
aplica uma função aos elementos correspondentes de determinados vetores ... Map
é um invólucro simples para o mapply
qual não tenta simplificar o resultado, semelhante ao mapcar do Common Lisp (com argumentos sendo reciclados, no entanto). Versões futuras podem permitir algum controle do tipo de resultado.
Map
é um invólucro mapply
lapply
é um caso especial de mapply
Map
e lapply
será semelhante em muitos casos.Por exemplo, aqui está lapply
:
lapply(iris, class)
$Sepal.Length
[1] "numeric"
$Sepal.Width
[1] "numeric"
$Petal.Length
[1] "numeric"
$Petal.Width
[1] "numeric"
$Species
[1] "factor"
E o mesmo usando Map
:
Map(class, iris)
$Sepal.Length
[1] "numeric"
$Sepal.Width
[1] "numeric"
$Petal.Length
[1] "numeric"
$Petal.Width
[1] "numeric"
$Species
[1] "factor"
do.call
recebe uma função como entrada e espalha seus outros argumentos para a função. É amplamente utilizado, por exemplo, para montar listas em estruturas mais simples (geralmente com rbind
ou cbind
).
Por exemplo:
x <- lapply(iris, class)
do.call(c, x)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
"numeric" "numeric" "numeric" "numeric" "factor"
do.call(cbind, x)
a versão atual me dá Error in do.call(c, x) : 'what' must be a function or character string
...
cbind()
é diferente da função c()
e, embora isso também funcione, fornece resultados diferentes.
lapply
aplica uma função sobre uma lista, do.call
chama uma função com uma lista de argumentos. Isso parece uma grande diferença para mim ...
Para dar um exemplo com uma lista:
X <- list(1:3,4:6,7:9)
Com lapply, você obtém a média de cada elemento da lista como este:
> lapply(X,mean)
[[1]]
[1] 2
[[2]]
[1] 5
[[3]]
[1] 8
do.call
gera um erro, pois a média espera que o argumento "trim" seja 1.
Por outro lado, rbind
liga todos os argumentos na linha. Então, para ligar o X rowwise, você deve:
> do.call(rbind,X)
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
Se você usasse lapply
, R se aplicaria rbind
a todos os elementos da lista, dando a você essa bobagem:
> lapply(X,rbind)
[[1]]
[,1] [,2] [,3]
[1,] 1 2 3
[[2]]
[,1] [,2] [,3]
[1,] 4 5 6
[[3]]
[,1] [,2] [,3]
[1,] 7 8 9
Para ter algo como Map, você precisa ?mapply
, que é algo totalmente diferente. Para obter, por exemplo, a média de cada elemento em X, mas com um corte diferente, você pode usar:
> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
lapply
é semelhante a map
, do.call
não é. lapply
aplica uma função a todos os elementos de uma lista, do.call
chama uma função em que todos os argumentos da função estão em uma lista. Portanto, para uma n
lista de elementos, lapply
possui n
chamadas de função e do.call
possui apenas uma chamada de função. Então, do.call
é bem diferente de lapply
. Espero que isso esclareça seu problema.
Um exemplo de código:
do.call(sum, list(c(1, 2, 4, 1, 2), na.rm = TRUE))
e:
lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
Nas palavras mais simples:
lapply () aplica uma determinada função para cada elemento em uma lista, portanto haverá várias chamadas de função.
do.call () aplica uma determinada função à lista como um todo, portanto, há apenas uma chamada de função.
A melhor maneira de aprender é brincar com os exemplos de funções na documentação do R.
Embora tenha havido muitas respostas, aqui está o meu exemplo para referência. Suponha que tenhamos uma lista de dados como:
L=list(c(1,2,3), c(4,5,6))
A função lapply retorna uma lista.
lapply(L, sum)
O acima significa algo como abaixo.
list( sum( L[[1]]) , sum( L[[2]]))
Agora vamos fazer a mesma coisa para do.call
do.call(sum, L)
Isso significa
sum( L[[1]], L[[2]])
No nosso exemplo, ele retorna 21. Em resumo, lapply sempre retorna uma lista, enquanto o tipo de retorno do.call realmente depende da função executada.
A diferença entre ambos são:
lapply(1:n,function,parameters)
=> Envia 1, parâmetros para funcionar => envia 2, parâmetros para funcionar e assim por diante
do.call
Apenas envia 1… n como vetor e parâmetros para funcionar
Portanto, em apply você tem n chamadas de função, em do.call você tem apenas um
do.call
é quase o mesmo queapply
em Lisp