Gibt es einen Grund, warum ich verwenden sollte
map(<list-like-object>, function(x) <do stuff>)
anstatt
lapply(<list-like-object>, function(x) <do stuff>)
Die Ausgabe sollte dieselbe sein, und die von mir erstellten Benchmarks scheinen zu zeigen, dass sie lapply
etwas schneller sind (dies sollte so sein, wie es map
erforderlich ist, um alle nicht standardmäßigen Bewertungseingaben zu bewerten).
Gibt es also einen Grund, warum ich in solch einfachen Fällen tatsächlich in Betracht ziehen sollte, zu zu wechseln purrr::map
? Ich frage hier nicht nach den Vorlieben oder Abneigungen bezüglich der Syntax, anderer Funktionen, die von purrr usw. bereitgestellt werden, sondern ausschließlich nach dem Vergleich purrr::map
mit der lapply
Annahme, dass die Standardbewertung verwendet wird, d map(<list-like-object>, function(x) <do stuff>)
. H. Gibt es einen Vorteil purrr::map
in Bezug auf Leistung, Ausnahmebehandlung usw.? Die Kommentare unten deuten darauf hin, dass dies nicht der Fall ist, aber vielleicht könnte jemand etwas mehr ausarbeiten?
tidyverse
obwohl, können Sie aus dem Rohr profitieren%>%
und anonymen Funktionen~ .x + 1
Syntax~{}
Abkürzung Lambda (mit oder ohne die{}
Dichtungen für mich den Deal für Ebenepurrr::map()
. Die Art-Durchsetzung derpurrr::map_…()
ist handlich und weniger stumpf alsvapply()
.purrr::map_df()
eine super teuer Funktion ist aber auch vereinfacht Code. Es gibt absolut nichts falsch mit mit Sockel R kleben[lsv]apply()
, obwohl .purrr
. Mein Punkt ist folgender:tidyverse
ist fabelhaft für Analysen / interaktive / Berichte, nicht für die Programmierung. Wenn Sie verwenden möchtenlapply
odermap
dann programmieren, können Sie eines Tages ein Paket erstellen. Je weniger Abhängigkeiten, desto besser. Plus: Ich sehe manchmal Leute, die danachmap
mit ziemlich obskurer Syntax arbeiten. Und jetzt, wo ich Leistungstests sehe: Wenn Sie anapply
Familie gewöhnt sind, bleiben Sie dabei.Antworten:
Wenn die einzige Funktion, die Sie von purrr verwenden
map()
, nein ist, sind die Vorteile nicht wesentlich. Wie Rich Pauloo betont,map()
sind die Helfer der Hauptvorteil, mit denen Sie kompakten Code für häufig auftretende Sonderfälle schreiben können:~ . + 1
ist äquivalent zufunction(x) x + 1
list("x", 1)
ist äquivalent zufunction(x) x[["x"]][[1]]
. Diese Helfer sind etwas allgemeiner als[[
- siehe?pluck
für Details. Für Datenrechtecke ist das.default
Argument besonders hilfreich.Aber die meiste Zeit verwenden Sie keine einzelne
*apply()
/map()
Funktion, sondern eine Reihe von Funktionen, und der Vorteil von purrr ist eine viel größere Konsistenz zwischen den Funktionen. Beispielsweise:Das erste Argument dafür
lapply()
sind die Daten; Das erste Argument dafürmapply()
ist die Funktion. Das erste Argument für alle Kartenfunktionen sind immer die Daten.Mit
vapply()
,sapply()
, undmapply()
können Sie zu unterdrücken Namen auf den Ausgang wählen , mitUSE.NAMES = FALSE
; hat aberlapply()
dieses Argument nicht.Es gibt keine konsistente Möglichkeit, konsistente Argumente an die Mapper-Funktion weiterzugeben. Die meisten Funktionen verwenden
...
abermapply()
verwendetMoreArgs
(von denen Sie erwarten würden, dass sie aufgerufen werdenMORE.ARGS
), und und erwartenMap()
, dass Sie eine neue anonyme Funktion erstellen. In Kartenfunktionen steht das konstante Argument immer hinter dem Funktionsnamen.Filter()
Reduce()
Fast jede Purrr-Funktion ist typstabil: Sie können den Ausgabetyp ausschließlich anhand des Funktionsnamens vorhersagen. Dies gilt nicht für
sapply()
odermapply()
. Ja, das gibt esvapply()
; aber es gibt kein Äquivalent fürmapply()
.Sie mögen denken, dass all diese kleinen Unterschiede nicht wichtig sind (so wie manche Leute denken, dass es keinen Vorteil hat, Stringr gegenüber regulären Ausdrücken der Basis R zu verwenden), aber meiner Erfahrung nach verursachen sie unnötige Reibung beim Programmieren (die unterschiedlichen Argumentreihenfolgen, die immer zum Auslösen verwendet wurden me up), und sie erschweren das Erlernen funktionaler Programmiertechniken, da Sie neben den großen Ideen auch eine Reihe von zufälligen Details lernen müssen.
Purrr füllt auch einige praktische Kartenvarianten aus, die in Basis R fehlen:
modify()
behält den Datentyp bei, mit[[<-
dem "an Ort und Stelle" geändert wird. In Verbindung mit der_if
Variante ermöglicht dies (IMO schöne) Code wiemodify_if(df, is.factor, as.character)
map2()
ermöglicht es Ihnen, gleichzeitig überx
und abzubildeny
. Dies macht es einfacher, Ideen wie auszudrückenmap2(models, datasets, predict)
imap()
Ermöglicht die gleichzeitige Zuordnung zux
und seinen Indizes (entweder Namen oder Positionen). Dies macht es einfach, (z. B.) allecsv
Dateien in ein Verzeichnis zu laden und jederfilename
Spalte eine Spalte hinzuzufügen .walk()
gibt seine Eingabe unsichtbar zurück; und ist nützlich, wenn Sie eine Funktion wegen ihrer Nebenwirkungen aufrufen (dh Dateien auf die Festplatte schreiben).Ganz zu schweigen von den anderen Helfern wie
safely()
undpartial()
.Persönlich finde ich, dass ich mit purrr Funktionscode mit weniger Reibung und größerer Leichtigkeit schreiben kann. es verringert die Kluft zwischen dem Ausdenken und der Umsetzung einer Idee. Ihr Kilometerstand kann jedoch variieren. Es ist nicht nötig, purrr zu verwenden, es sei denn, es hilft Ihnen tatsächlich.
Mikrobenchmarks
Ja,
map()
ist etwas langsamer alslapply()
. Die Kosten für die Verwendung vonmap()
oderlapply()
hängen jedoch von dem ab, was Sie zuordnen, und nicht vom Aufwand für die Durchführung der Schleife. Das unten stehende Mikrobenchmark deutet darauf hin, dass die Kosten immap()
Vergleich zulapply()
etwa 40 ns pro Element liegen, was die meisten R-Codes wahrscheinlich nicht wesentlich beeinflusst.quelle
mutate()
, ich wollte nur ein einfaches Beispiel ohne andere Deps.map_*
hat mich dazu gebracht,purrr
viele Skripte zu laden . Es hat mir bei einigen Aspekten des Kontrollflusses meines Codes geholfen (stopifnot(is.data.frame(x))
).Vergleichen
purrr
undlapply
auf Komfort und Geschwindigkeit hinauslaufen .1.
purrr::map
ist syntaktisch bequemer als lapplyExtrahieren Sie das zweite Element der Liste
welche als @F. Privé wies darauf hin, ist das gleiche wie:
mit
lapply
wir müssen eine anonyme Funktion übergeben ...
... oder wie @RichScriven betonte, gehen wir
[[
als Argument inlapply
Wenn Sie also feststellen, dass Sie Funktionen auf viele Listen anwenden
lapply
und entweder eine benutzerdefinierte Funktion definieren oder eine anonyme Funktion schreiben möchten, ist die Bequemlichkeit ein Grund, sich für eine Bevorzugung zu entscheidenpurrr
.2. Typspezifische Kartenfunktionen einfach viele Codezeilen
map_chr()
map_lgl()
map_int()
map_dbl()
map_df()
Jede dieser typspezifischen Kartenfunktionen gibt eine atomare Liste (Vektor) zurück und nicht die von
map()
und zurückgegebenen Listenlapply()
. Wenn Sie mit verschachtelten Listen von Atomvektoren arbeiten, können Sie diese typspezifischen Kartenfunktionen verwenden, um die Vektoren direkt herauszuziehen und Vektoren direkt in int-, dbl- und chr-Vektoren zu zwingen. Die Basis R - Version würde in etwa so aussehenas.numeric(sapply(...))
,as.character(sapply(...))
etc.Die
map_<type>
Funktionen haben auch die nützliche Eigenschaft, dass sie fehlschlagen, wenn sie keinen Atomvektor des angegebenen Typs zurückgeben können. Dies ist nützlich, wenn Sie einen Kontrollfluss definieren, bei dem eine Funktion fehlschlagen soll, wenn sie [irgendwie] den falschen Objekttyp generiert.3. Bequemlichkeit beiseite,
lapply
ist [etwas] schneller alsmap
Verwenden
purrr
der Komfortfunktionen als @F. Privé wies darauf hin, dass die Verarbeitung etwas langsamer wird. Lassen Sie uns jeden der 4 Fälle, die ich oben vorgestellt habe, fahren.Und der Gewinner ist....
In der Summe, wenn Sie nach roher Geschwindigkeit suchen:
base::lapply
(obwohl es nicht viel schneller ist)Für einfache Syntax und Ausdruckbarkeit:
purrr::map
Dieses hervorragende
purrr
Tutorial zeigt die Bequemlichkeit , anonyme Funktionen bei der Verwendung nicht explizit ausschreiben zu müssenpurrr
, und die Vorteile typspezifischermap
Funktionen.quelle
function(x) x[[2]]
statt nur verwenden2
. All diese zusätzliche Zeit ist auf Überprüfungen zurückzuführen,lapply
die nicht funktionieren.[[
ist eine Funktion. Das kannst du machenlapply(list, "[[", 3)
.Wenn wir Aspekte des Geschmacks (andernfalls sollte diese Frage geschlossen werden) oder der Syntaxkonsistenz, des Stils usw. nicht berücksichtigen, lautet die Antwort "Nein". Es gibt keinen besonderen Grund,
map
anstellelapply
oder anderer Varianten der Apply-Familie, wie z. B. der strengeren, zu verwendenvapply
.PS: Denken Sie daran, dass das OP für diese Leute, die unentgeltlich abstimmen, geschrieben hat:
Wenn Sie weder die Syntax noch andere Funktionen von berücksichtigen
purrr
, gibt es keinen besonderen Grund für die Verwendungmap
. Ich benutzepurrr
mich selbst und bin mit Hadleys Antwort einverstanden, aber es geht ironischerweise genau um die Dinge, die das OP im Voraus angegeben hat, die er nicht gefragt hat.quelle