Estou aprendendo R recentemente e confuso com duas funções: lapplye do.call. Parece que eles são similares à mapfunçã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: lapplye do.call. Parece que eles são similares à mapfunçã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 Mapque 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.
Mapaplica uma função aos elementos correspondentes de determinados vetores ... Mapé um invólucro simples para o mapplyqual 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 mapplylapply é um caso especial de mapplyMape lapplyserá 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.callrecebe 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 rbindou 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.
lapplyaplica uma função sobre uma lista, do.callchama 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, rbindliga 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 rbinda 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.callnão é. lapplyaplica uma função a todos os elementos de uma lista, do.callchama uma função em que todos os argumentos da função estão em uma lista. Portanto, para uma nlista de elementos, lapplypossui nchamadas de função e do.callpossui 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 queapplyem Lisp