Das größte Problem und die Wurzel der Ineffektivität ist die Indizierung von data.frame. Ich meine all diese Zeilen, in denen Sie sie verwenden temp[,]
.
Versuchen Sie dies so weit wie möglich zu vermeiden. Ich habe Ihre Funktion übernommen, die Indizierung geändert und hier version_A
dayloop2_A <- function(temp){
res <- numeric(nrow(temp))
for (i in 1:nrow(temp)){
res[i] <- i
if (i > 1) {
if ((temp[i,6] == temp[i-1,6]) & (temp[i,3] == temp[i-1,3])) {
res[i] <- temp[i,9] + res[i-1]
} else {
res[i] <- temp[i,9]
}
} else {
res[i] <- temp[i,9]
}
}
temp$`Kumm.` <- res
return(temp)
}
Wie Sie sehen können, erstelle ich einen Vektor, res
der Ergebnisse sammelt. Am Ende füge ich es hinzu data.frame
und ich muss mich nicht mit Namen anlegen. Wie ist es besser?
Ich führe jede Funktion für data.frame
mit nrow
1.000 bis 10.000 mal 1.000 aus und messe die Zeit mitsystem.time
X <- as.data.frame(matrix(sample(1:10, n*9, TRUE), n, 9))
system.time(dayloop2(X))
Ergebnis ist
Sie können sehen, dass Ihre Version exponentiell von abhängt nrow(X)
. Die modifizierte Version hat eine lineare Beziehung, und ein einfaches lm
Modell sagt voraus, dass die Berechnung für 850.000 Zeilen 6 Minuten und 10 Sekunden dauert.
Kraft der Vektorisierung
Wie Shane und Calimo in ihren Antworten angeben, ist die Vektorisierung ein Schlüssel zu einer besseren Leistung. Von Ihrem Code aus können Sie sich außerhalb der Schleife bewegen:
- Konditionierung
- Initialisierung der Ergebnisse (welche sind
temp[i,9]
)
Dies führt zu diesem Code
dayloop2_B <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in 1:nrow(temp)) {
if (cond[i]) res[i] <- temp[i,9] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
Vergleichen Sie das Ergebnis für diese Funktionen, diesmal für nrow
10.000 bis 100.000 mal 10.000.
Tuning das abgestimmte
Eine weitere Optimierung besteht darin, eine Schleifenindizierung temp[i,9]
auf zu ändern res[i]
(die in der i-ten Schleifeniteration genau gleich ist). Es ist wieder ein Unterschied zwischen der Indizierung eines Vektors und der Indizierung eines data.frame
.
Zweitens: Wenn Sie sich die Schleife ansehen, sehen Sie, dass keine Schleife über alle Schleifen erforderlich ist i
, sondern nur für diejenigen, die dem Zustand entsprechen.
Auf geht's
dayloop2_D <- function(temp){
cond <- c(FALSE, (temp[-nrow(temp),6] == temp[-1,6]) & (temp[-nrow(temp),3] == temp[-1,3]))
res <- temp[,9]
for (i in (1:nrow(temp))[cond]) {
res[i] <- res[i] + res[i-1]
}
temp$`Kumm.` <- res
return(temp)
}
Die Leistung, die Sie in hohem Maße erzielen, hängt von einer Datenstruktur ab. Genau - auf Prozent der TRUE
Werte im Zustand. Für meine simulierten Daten dauert die Rechenzeit 850.000 Zeilen unter einer Sekunde.
Wenn du willst, dass du weiter gehen kannst, sehe ich mindestens zwei Dinge, die getan werden können:
- Schreiben Sie einen
C
Code, um bedingte Cumsum zu machen
Wenn Sie wissen, dass in Ihrer Datenmaximalsequenz nicht groß ist, können Sie die Schleife in "vektorisiert" ändern, während
while (any(cond)) {
indx <- c(FALSE, cond[-1] & !cond[-n])
res[indx] <- res[indx] + res[which(indx)-1]
cond[indx] <- FALSE
}
Der für Simulationen und Abbildungen verwendete Code ist auf GitHub verfügbar .