Anwenden einer Funktion auf jede Zeile einer Matrix oder einem Datenrahmen
Frage
Angenommen, ich habe eine n von 2-Matrix und einer Funktion, die einen 2-Vektor als eine seiner Argumente annimmt. Ich möchte die Funktion jeder Zeile der Matrix anzuwenden und einen n-Vektor zu erhalten. Wie dies in R tun?
Zum Beispiel würde Ich mag die Dichte einer 2D-Standardnormalverteilung auf drei Punkte berechnen:
bivariate.density(x = c(0, 0), mu = c(0, 0), sigma = c(1, 1), rho = 0){
exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+x[2]^2/sigma[2]^2-2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) * 1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}
out <- rbind(c(1, 2), c(3, 4), c(5, 6))
So wird die Funktion jeder Reihe von out
anwenden?
Wie Werte für die anderen Argumente neben den Punkten auf die Funktion in der Art und Weise passieren Sie angeben?
Lösung
Sie einfach die apply()
-Funktion:
R> M <- matrix(1:6, nrow=3, byrow=TRUE)
R> M
[,1] [,2]
[1,] 1 2
[2,] 3 4
[3,] 5 6
R> apply(M, 1, function(x) 2*x[1]+x[2])
[1] 4 10 16
R>
Dies nimmt eine Matrix und wendet eine (dumme) Funktion zu jeder Zeile. Sie übergeben zusätzliche Argumente für die Funktion als vierte, fünfte, ... Argumente apply()
.
Andere Tipps
Falls Sie häufig verwendete Funktionen wie Summe oder Mittelwert anwenden möchten, sollten Sie rowSums
oder rowMeans
verwenden, da sie sind schneller als apply(data, 1, sum)
Ansatz. Ansonsten bleibt bei apply(data, 1, fun)
. Sie können zusätzliche Argumente nach FUN Argument übergeben (wie Dirk schon vorgeschlagen):
set.seed(1)
m <- matrix(round(runif(20, 1, 5)), ncol=4)
diag(m) <- NA
m
[,1] [,2] [,3] [,4]
[1,] NA 5 2 3
[2,] 2 NA 2 4
[3,] 3 4 NA 5
[4,] 5 4 3 NA
[5,] 2 1 4 4
Dann können Sie etwas tun:
apply(m, 1, quantile, probs=c(.25,.5, .75), na.rm=TRUE)
[,1] [,2] [,3] [,4] [,5]
25% 2.5 2 3.5 3.5 1.75
50% 3.0 2 4.0 4.0 3.00
75% 4.0 3 4.5 4.5 4.00
Hier ist ein kurzes Beispiel eine Funktion zu jeder Zeile einer Matrix aufgebracht wird. (Hier die Funktion angewendet normalisiert jede Zeile. 1)
. Hinweis: Das Ergebnis aus der apply()
sein mußte transponiert t()
mit dem gleichen Layout wie die Eingabematrix A
bekommen
A <- matrix(c(
0, 1, 1, 2,
0, 0, 1, 3,
0, 0, 1, 3
), nrow = 3, byrow = TRUE)
t(apply(A, 1, function(x) x / sum(x) ))
Ergebnis:
[,1] [,2] [,3] [,4]
[1,] 0 0.25 0.25 0.50
[2,] 0 0.00 0.25 0.75
[3,] 0 0.00 0.25 0.75
Der erste Schritt wäre es, die Funktionsobjekt zu machen, die Anwendung dann. Wenn Sie ein Matrix-Objekt mögen, dass die gleiche Anzahl von Zeilen hat, können Sie es vordefinieren und das Objekt verwenden [] Form, wie dargestellt (ansonsten der zurückgegebene Wert auf einen Vektor vereinfacht wird):
bvnormdens <- function(x=c(0,0),mu=c(0,0), sigma=c(1,1), rho=0){
exp(-1/(2*(1-rho^2))*(x[1]^2/sigma[1]^2+
x[2]^2/sigma[2]^2-
2*rho*x[1]*x[2]/(sigma[1]*sigma[2]))) *
1/(2*pi*sigma[1]*sigma[2]*sqrt(1-rho^2))
}
out=rbind(c(1,2),c(3,4),c(5,6));
bvout<-matrix(NA, ncol=1, nrow=3)
bvout[] <-apply(out, 1, bvnormdens)
bvout
[,1]
[1,] 1.306423e-02
[2,] 5.931153e-07
[3,] 9.033134e-15
Wenn Sie wollte andere verwenden, als Ihre Standardparameter dann sollte der Anruf benannten Argumente nach der Funktion sind:
bvout[] <-apply(out, 1, FUN=bvnormdens, mu=c(-1,1), rho=0.6)
apply () kann auch auf höhere dimensionale Arrays verwendet werden, und das RAND-Argument kann ein Vektor sowie eine einzelne ganze Zahl sein.
Bewerben macht den Job gut, aber ziemlich langsam ist. Mit sapply und vapply könnte nützlich sein. dplyr die zeilenweise könnte auch nützlich sein Mal sehen, ein Beispiel, wie zeilenweise Produkt von jedem Datenrahmen zu tun.
a = data.frame(t(iris[1:10,1:3]))
vapply(a, prod, 0)
sapply(a, prod)
Beachten Sie, dass an Variablen zugewiesen wird, bevor Sie vapply / sapply / apply ist eine gute Praxis, wie es an der Zeit eine Menge reduziert. Mal sehen, Ergebnisse-Micro
a = data.frame(t(iris[1:10,1:3]))
b = iris[1:10,1:3]
microbenchmark::microbenchmark(
apply(b, 1 , prod),
vapply(a, prod, 0),
sapply(a, prod) ,
apply(iris[1:10,1:3], 1 , prod),
vapply(data.frame(t(iris[1:10,1:3])), prod, 0),
sapply(data.frame(t(iris[1:10,1:3])), prod) ,
b %>% rowwise() %>%
summarise(p = prod(Sepal.Length,Sepal.Width,Petal.Length))
)
Haben Sie einen sorgfältigen Blick auf, wie t () verwendet wird
Ein weiterer Ansatz, wenn Sie einen Variierung Teil des Datensatzes anstelle eines einzigen Wert verwenden möchten, ist rollapply(data, width, FUN, ...)
zu verwenden. Verwendung eines Vektors von Breiten ermöglicht Ihnen, eine Funktion auf einem unterschiedlichen Fenster des Datensatzes anzuwenden. Ich habe verwendet, um dieses eine adaptive Filterung Routine zu bauen, obwohl es nicht sehr effizient ist.