R Language
* wende die Familie der Funktionen (Funktionale) an
Suche…
Bemerkungen
Eine Funktion in der *apply
Familie ist eine Abstraktion einer for
Schleife. Gegenüber den for
Loops-Funktionen haben *apply
Funktionen folgende Vorteile:
- Erfordert weniger Code zum Schreiben.
- Hat keinen Iterationszähler.
- Verwendet temporäre Variablen nicht zum Speichern von Zwischenergebnissen.
for
Schleifen sind jedoch allgemeiner und geben uns mehr Kontrolle, sodass komplexe Berechnungen durchgeführt werden können, die mit *apply
Funktionen nicht immer trivial sind.
Die Beziehung zwischen for
Schleifen und *apply
Funktionen wird in der Dokumentation für for
Schleifen erläutert.
Mitglieder der *apply
Familie
Die *apply
Funktionsfamilie enthält mehrere Varianten desselben Prinzips, die sich hauptsächlich in der Art der ausgegebenen Ausgabe unterscheiden.
Funktion | Eingang | Ausgabe |
---|---|---|
apply | matrix , data.frame oder array | Vektor oder Matrix (abhängig von der Länge jedes zurückgegebenen Elements) |
sapply | Vektor oder list | Vektor oder Matrix (abhängig von der Länge jedes zurückgegebenen Elements) |
lapply | Vektor oder list | list |
vapply | Vektor oder `Liste | Vektor oder Matrix (abhängig von der Länge jedes zurückgegebenen Elements) der benutzerdefinierten Klasse |
mapply | mehrere Vektoren, lists oder eine Kombination | list |
Siehe "Beispiele", um zu sehen, wie jede dieser Funktionen verwendet wird.
Verwenden Sie anonyme Funktionen mit apply
apply
wird verwendet, um eine Funktion (möglicherweise eine anonyme) über die Ränder eines Arrays oder einer Matrix auszuwerten.
Verwenden Sie das iris
Dataset, um diese Idee zu veranschaulichen. Der iris
Datensatz hat Messungen von 150 Blumen von 3 Arten. Mal sehen, wie dieser Datensatz aufgebaut ist:
> head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
Stellen Sie sich vor, Sie möchten den Mittelwert jeder dieser Variablen kennen. Eine Möglichkeit, dieses Problem zu lösen, könnte die Verwendung einer for
Schleife sein, aber R-Programmierer bevorzugen oft die Verwendung von " apply
(Gründe, siehe Anmerkungen):
> apply(iris[1:4], 2, mean)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.199333
- Im ersten Parameter setzen wir die Untermenge
iris
, dass sie nur die ersten 4 Spalten enthält, da dermean
nur für numerische Daten gilt. - Der zweite Parameterwert von
2
gibt an, dass wir nur an den Spalten arbeiten möchten (der zweite Index des Arrays r × c).1
würde die Zeile bedeuten.
Auf die gleiche Weise können wir aussagekräftigere Werte berechnen:
# standard deviation
apply(iris[1:4], 2, sd)
# variance
apply(iris[1:4], 2, var)
Einschränkung : R hat einige eingebaute Funktionen, die besser zur Berechnung von Spalten- und Reihensummen und colMeans
rowMeans
sind: colMeans
und rowMeans
.
Nun machen wir eine andere und sinnvollere Aufgabe: Berechnen Sie den Mittelwert nur für die Werte, die größer als 0.5
. Dafür werden wir unsere eigene erstellen mean
Funktion.
> our.mean.function <- function(x) { mean(x[x > 0.5]) }
> apply(iris[1:4], 2, our.mean.function)
Sepal.Length Sepal.Width Petal.Length Petal.Width
5.843333 3.057333 3.758000 1.665347
(Beachten Sie den Unterschied im Mittelwert von Petal.Width
)
Was aber, wenn wir diese Funktion nicht im Rest unseres Codes verwenden möchten? Dann können wir eine anonyme Funktion verwenden und unseren Code folgendermaßen schreiben:
apply(iris[1:4], 2, function(x) { mean(x[x > 0.5]) })
Wie wir gesehen haben, können wir mit apply
die gleiche Operation für Spalten oder Zeilen eines Datasets mit nur einer Zeile ausführen.
Einschränkung : Da apply
je nach Länge der Ergebnisse der angegebenen Funktion sehr unterschiedliche Ausgabearten liefert, ist dies möglicherweise nicht die beste Wahl, wenn Sie nicht interaktiv arbeiten. Einige der anderen *apply
Familienfunktionen sind etwas vorhersagbarer (siehe Anmerkungen).
Massendatei wird geladen
für eine große Anzahl von Dateien, die möglicherweise in einem ähnlichen Prozess und mit gut strukturierten Dateinamen bearbeitet werden müssen.
Zunächst muss ein Vektor der Dateinamen erstellt werden, auf die zugegriffen werden soll. Dazu gibt es mehrere Optionen:
Vektor manuell mit
paste0()
files <- paste0("file_", 1:100, ".rds")
Mit
list.files()
mit einem regex Suchbegriff für den Dateityp, erfordert die Kenntnis von regulären Ausdrücken ( regex ) , wenn andere Dateien gleichen Typs im Verzeichnis befinden.files <- list.files("./", pattern = "\\.rds$", full.names = TRUE)
Dabei ist X
ein Vektor eines Teils des verwendeten Dateinamensformats.
lapply
gibt jede Antwort als Element einer Liste aus.
readRDS
ist spezifisch für .rds
Dateien und ändert sich je nach Anwendung des Prozesses.
my_file_list <- lapply(files, readRDS)
Dies ist nicht notwendigerweise schneller als eine for-Schleife von testing, sondern ermöglicht, dass alle Dateien ein Element einer Liste sind, ohne sie explizit zuzuweisen.
Schließlich müssen wir häufig mehrere Pakete gleichzeitig laden. Mit diesem Trick können Sie library()
auf alle Bibliotheken anwenden, die wir importieren möchten:
lapply(c("jsonlite","stringr","igraph"),library,character.only=TRUE)
Mehrere `data.frames` kombinieren (` lapply`, `mapply`)
In dieser Übung werden vier lineare Bootstrap-Regressionsmodelle generiert und die Zusammenfassungen dieser Modelle in einem einzigen Datenrahmen kombiniert.
library(broom)
#* Create the bootstrap data sets
BootData <- lapply(1:4,
function(i) mtcars[sample(1:nrow(mtcars),
size = nrow(mtcars),
replace = TRUE), ])
#* Fit the models
Models <- lapply(BootData,
function(BD) lm(mpg ~ qsec + wt + factor(am),
data = BD))
#* Tidy the output into a data.frame
Tidied <- lapply(Models,
tidy)
#* Give each element in the Tidied list a name
Tidied <- setNames(Tidied, paste0("Boot", seq_along(Tidied)))
An dieser Stelle können wir zwei Methoden zum Einfügen der Namen in den data.frame verwenden.
#* Insert the element name into the summary with `lapply`
#* Requires passing the names attribute to `lapply` and referencing `Tidied` within
#* the applied function.
Described_lapply <-
lapply(names(Tidied),
function(nm) cbind(nm, Tidied[[nm]]))
Combined_lapply <- do.call("rbind", Described_lapply)
#* Insert the element name into the summary with `mapply`
#* Allows us to pass the names and the elements as separate arguments.
Described_mapply <-
mapply(
function(nm, dframe) cbind(nm, dframe),
names(Tidied),
Tidied,
SIMPLIFY = FALSE)
Combined_mapply <- do.call("rbind", Described_mapply)
Wenn Sie ein Fan von magrittr
Stil-Pipes sind, können Sie die gesamte Aufgabe in einer einzelnen Kette magrittr
(dies ist jedoch möglicherweise nicht ratsam, wenn Sie Zwischenobjekte wie die Modellobjekte selbst benötigen):
library(magrittr)
library(broom)
Combined <- lapply(1:4,
function(i) mtcars[sample(1:nrow(mtcars),
size = nrow(mtcars),
replace = TRUE), ]) %>%
lapply(function(BD) lm( mpg ~ qsec + wt + factor(am), data = BD)) %>%
lapply(tidy) %>%
setNames(paste0("Boot", seq_along(.))) %>%
mapply(function(nm, dframe) cbind(nm, dframe),
nm = names(.),
dframe = .,
SIMPLIFY = FALSE) %>%
do.call("rbind", .)
Eingebaute Funktionale verwenden
Integrierte Funktionen: lapply (), sapply () und mapply ()
R verfügt über integrierte Funktionen, von denen die bekannteste wahrscheinlich die anwendbare Funktionsfamilie ist. Hier finden Sie eine Beschreibung einiger der häufigsten Anwendungsfunktionen:
-
lapply()
= nimmt eine Liste als Argument und wendet die angegebene Funktion auf die Liste an. -
sapply()
= dasselbe wielapply()
, versucht jedoch die Ausgabe in einen Vektor oder eine Matrix zu vereinfachen.-
vapply()
= eine Variante vonsapply()
in der der Typ des Ausgabeobjekts angegeben werden muss.
-
-
mapply()
= wielapply()
, kann jedoch mehrere Vektoren als Eingabe an die angegebene Funktion übergeben. Kann wiesapply()
vereinfacht werden.-
Map()
ist ein Alias fürmapply()
mitSIMPLIFY = FALSE
.
-
lapply ()
lapply()
kann mit zwei verschiedenen Iterationen verwendet werden:
-
lapply(variable, FUN)
-
lapply(seq_along(variable), FUN)
# Two ways of finding the mean of x
set.seed(1)
df <- data.frame(x = rnorm(25), y = rnorm(25))
lapply(df, mean)
lapply(seq_along(df), function(x) mean(df[[x]))
sapply ()
sapply()
versucht, seine Ausgabe in einen Vektor oder eine Matrix aufzulösen.
# Two examples to show the different outputs of sapply()
sapply(letters, print) ## produces a vector
x <- list(a = 1:10, beta = exp(-3:3), logic = c(TRUE,FALSE,FALSE,TRUE))
sapply(x, quantile) ## produces a matrix
mapply ()
mapply()
funktioniert ähnlich wie lapply()
außer dass es mehrere Vektoren als Eingabe lapply()
kann (daher das m für multivariate).
mapply(sum, 1:5, 10:6, 3) # 3 will be "recycled" by mapply
Verwendung benutzerdefinierter Funktionen
Benutzerdefinierte Funktionen
Benutzer können ihre eigenen Funktionen in unterschiedlichem Umfang erstellen. Die folgenden Beispiele stammen von Functionals by Hadley Wickham:
randomise <- function(f) f(runif(1e3))
lapply2 <- function(x, f, ...) {
out <- vector("list", length(x))
for (i in seq_along(x)) {
out[[i]] <- f(x[[i]], ...)
}
out
}
Im ersten Fall akzeptiert randomise
ein einzelnes Argument f
und ruft es für eine Stichprobe von Uniform-Zufallsvariablen auf. Um die Äquivalenz zu demonstrieren, rufen wir set.seed
unten auf:
set.seed(123)
randomise(mean)
#[1] 0.4972778
set.seed(123)
mean(runif(1e3))
#[1] 0.4972778
set.seed(123)
randomise(max)
#[1] 0.9994045
set.seed(123)
max(runif(1e3))
#[1] 0.9994045
Das zweite Beispiel ist eine Neuimplementierung von base::lapply
, die mithilfe von Funktionen eine Operation ( f
) auf jedes Element in einer Liste ( x
) anwendet. Mit dem Parameter ...
kann der Benutzer zusätzliche Argumente an f
, z. B. die Option na.rm
in der Funktion mean
:
lapply(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
#
# [[2]]
# [1] NA
lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean)
# [[1]]
# [1] 3
#
# [[2]]
# [1] NA
lapply(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4
lapply2(list(c(1, 3, 5), c(2, NA, 6)), mean, na.rm = TRUE)
# [[1]]
# [1] 3
#
# [[2]]
# [1] 4