Wat is het verschil tussen lapply en do.call?

Ik ben onlangs R aan het leren en ben in de war door twee functies: lapplyen do.call. Het lijkt erop dat ze vergelijkbaar zijn met de functie mapin 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 mapdie vergelijkbaar kan zijn met kaart in andere talen:

  • lapplyretourneert 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.callconstrueert en voert een functieaanroep uit van een naam of een functie en een lijst met argumenten die eraan moeten worden doorgegeven.

  • mappast een functie toe op de corresponderende elementen van gegeven vectoren… mapis een eenvoudige wrapper om mapplyte 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.


  1. mapis een wrapper rond mapply
  2. lapplyis een speciaal geval van mapply
  3. Daarom zullen mapen lapplyin 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.callneemt 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 rbindof 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%

lapplypast een functie toe op een lijst, do.callroept 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.callgeeft een foutmelding, aangezien mean verwacht dat het argument “trim” 1 is.

Aan de andere kant bindt rbindalle 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 lapplyzou gebruiken, zou R rbindtoepassen 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 ?mapplynodig, 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%

lapplylijkt op map, do.callis dat niet. lapplypast een functie toe op alle elementen van een lijst, do.callroept een functie aan waarbij alle functieargumenten in een lijst staan. Dus voor een nelementenlijst heeft lapplynfunctieaanroepen en do.callheeft slechts één functieaanroep . Dus do.callis 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

Other episodes