Ik ben onlangs R aan het leren en ben in de war door twee functies: lapply
en do.call
. Het lijkt erop dat ze vergelijkbaar zijn met de functie map
in Lisp. Maar waarom zijn er twee functies met zo’n verschillende naam? Waarom gebruikt R niet gewoon een functie genaamd map
?
Antwoord 1, autoriteit 100%
Er is een functie genaamd map
die vergelijkbaar kan zijn met kaart in andere talen:
-
lapply
retourneert een lijst met dezelfde lengte als X, waarvan elk element het resultaat is van het toepassen van FUN op het corresponderende element van X. -
do.call
construeert en voert een functieaanroep uit van een naam of een functie en een lijst met argumenten die eraan moeten worden doorgegeven. -
map
past een functie toe op de corresponderende elementen van gegeven vectoren…map
is een eenvoudige wrapper ommapply
te probeer het resultaat niet te vereenvoudigen, vergelijkbaar met de mapcar van Common Lisp (met argumenten die echter worden hergebruikt). Toekomstige versies kunnen enige controle over het resultaattype toestaan.
map
is een wrapper rondmapply
lapply
is een speciaal geval vanmapply
- Daarom zullen
map
enlapply
in veel gevallen vergelijkbaar zijn.
Hier is bijvoorbeeld lapply
:
lapply(iris, class)
$Sepal.Length
[1] "numeric"
$Sepal.Width
[1] "numeric"
$Petal.Length
[1] "numeric"
$Petal.Width
[1] "numeric"
$Species
[1] "factor"
En hetzelfde met 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
neemt een functie als invoer en spettert de andere argumenten naar de functie. Het wordt bijvoorbeeld veel gebruikt om lijsten samen te voegen tot eenvoudigere structuren (vaak met rbind
of cbind
).
Bijvoorbeeld:
x <- lapply(iris, class)
do.call(c, x)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
"numeric" "numeric" "numeric" "numeric" "factor"
Antwoord 2, autoriteit 47%
lapply
past een functie toe op een lijst, do.call
roept een functie aan met een lijst van argumenten. Dat lijkt me nogal een verschil…
Om een voorbeeld te geven met een lijst:
X <- list(1:3,4:6,7:9)
Met lapply krijg je het gemiddelde van elk element in de lijst als volgt:
> lapply(X,mean)
[[1]]
[1] 2
[[2]]
[1] 5
[[3]]
[1] 8
do.call
geeft een foutmelding, aangezien mean verwacht dat het argument “trim” 1 is.
Aan de andere kant bindt rbind
alle argumenten rijsgewijs. Dus om X rijsgewijs te binden, doe je:
> do.call(rbind,X)
[,1] [,2] [,3]
[1,] 1 2 3
[2,] 4 5 6
[3,] 7 8 9
Als je lapply
zou gebruiken, zou R rbind
toepassen op elk element van de lijst, waardoor je deze onzin krijgt:
> 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
Om zoiets als Map te hebben, heb je ?mapply
nodig, wat helemaal iets anders is. Om bijv. het gemiddelde van elk element in X te krijgen, maar met een andere bijsnijding, zou je kunnen gebruiken:
> mapply(mean,X,trim=c(0,0.5,0.1))
[1] 2 5 8
Antwoord 3, autoriteit 30%
lapply
lijkt op map
, do.call
is dat niet. lapply
past een functie toe op alle elementen van een lijst, do.call
roept een functie aan waarbij alle functieargumenten in een lijst staan. Dus voor een n
elementenlijst heeft lapply
n
functieaanroepen en do.call
heeft slechts één functieaanroep . Dus do.call
is heel anders dan lapply
. Ik hoop dat dit uw probleem verduidelijkt.
Een codevoorbeeld:
do.call(sum, list(c(1, 2, 4, 1, 2), na.rm = TRUE))
en:
lapply(c(1, 2, 4, 1, 2), function(x) x + 1)
Antwoord 4, autoriteit 12%
Hoewel er veel antwoorden zijn geweest, is hier mijn voorbeeld ter referentie.
Stel dat we een lijst met gegevens hebben als:
L=list(c(1,2,3), c(4,5,6))
De functie lapply retourneert een lijst.
lapply(L, sum)
Bovenstaande betekent zoiets als hieronder.
list( sum( L[[1]]) , sum( L[[2]]))
Laten we nu hetzelfde doen voor do.call
do.call(sum, L)
Het betekent
sum( L[[1]], L[[2]])
In ons voorbeeld retourneert het 21. Kortom, lapply retourneert altijd een lijst, terwijl het retourtype van do.call echt afhangt van de uitgevoerde functie.
Antwoord 5, autoriteit 10%
lapply()
is een kaartachtige functie. do.call()
is anders. Het wordt gebruikt om de argumenten door te geven aan een functie in lijstvorm in plaats van ze te laten opsommen. Bijvoorbeeld
> do.call("+",list(4,5))
[1] 9
Antwoord 6, autoriteit 5%
Het verschil tussen beide is:
lapply(1:n,function,parameters)
=> Dit stuurt 1, parameters naar functie:
=> dit stuurt 2 parameters naar functie
enzovoort
do.call
Stuurt gewoon 1…n als vector en parameters om te functioneren
Dus in Apply heb je n functie-aanroepen, in do.call heb je er maar één