Was ist die leistungsstärkere Alternative zu for-Schleifen, um Daten nach Gruppen-ID zu unterteilen?

Ein wiederkehrendes Analyseparadigma, auf das ich in meiner Forschung stoße, ist die Notwendigkeit, eine Teilmenge basierend auf allen unterschiedlichen Gruppen-ID-Werten zu erstellen, statistische Analysen für jede Gruppe durchzuführen und die Ergebnisse zur weiteren Verarbeitung / Zusammenfassung in eine Ausgabematrix einzutragen.

Wie ich das normalerweise in R mache, sieht ungefähr so aus:

data.mat <- read.csv("...")  
groupids <- unique(data.mat$ID)  #Assume there are then 100 unique groups

results <- matrix(rep("NA",300),ncol=3,nrow=100)  

for(i in 1:100) {  
  tempmat <- subset(data.mat,ID==groupids[i])  

  # Run various stats on tempmat (correlations, regressions, etc), checking to  
  # make sure this specific group doesn't have NAs in the variables I'm using  
  # and assign results to x, y, and z, for example.  

  results[i,1] <- x  
  results[i,2] <- y  
  results[i,3] <- z  
}

Das funktioniert bei mir, aber abhängig von der Größe der Daten und der Anzahl der Gruppen, mit denen ich arbeite, kann dies bis zu drei Tage dauern.

Gibt es neben dem Verzweigen in die Parallelverarbeitung einen "Trick", um so etwas schneller laufen zu lassen? Zum Beispiel, die Schleifen in etwas anderes umzuwandeln (so etwas wie eine Anwendung mit einer Funktion, die die Statistiken enthält, die ich in der Schleife ausführen möchte) oder die Notwendigkeit zu beseitigen, die Teilmenge der Daten einer Variablen tatsächlich zuzuweisen?

Bearbeiten:

Vielleicht ist dies nur allgemein bekannt (oder ein Stichprobenfehler), aber ich habe versucht, einen Teil meines Codes mit Klammern zu setzen, anstatt den Befehl subset zu verwenden, und es schien einen leichten Leistungszuwachs zu bieten, der mich überraschte. Ich habe einen Code, den ich unten verwendet und mit den gleichen Objektnamen wie oben ausgegeben habe:

system.time(for(i in 1:1000){data.mat[data.mat$ID==groupids[i],]})  
   user  system elapsed  
 361.41   92.62  458.32
system.time(for(i in 1:1000){subset(data.mat,ID==groupids[i])})  
   user  system elapsed   
 378.44  102.03  485.94
Aktualisieren:

In einer der Antworten schlug jorgusch vor, dass ich das data.table-Paket verwende, um meine Teilmenge zu beschleunigen. Also habe ich es auf ein Problem angewendet, das ich Anfang dieser Woche ausgeführt habe. In einem Datensatz mit etwas mehr als 1.500.000 Zeilen und 4 Spalten (ID, Var1, Var2, Var3) wollte ich zwei Korrelationen in jeder Gruppe berechnen (indiziert durch die Variable "ID"). Es gibt etwas mehr als 50.000 Gruppen. Unten ist mein Anfangscode (der dem obigen sehr ähnlich ist):

data.mat <- read.csv("//home....")  
groupids <- unique(data.mat$ID)

results <- matrix(rep("NA",(length(groupids) * 3)),ncol=3,nrow=length(groupids))  

for(i in 1:length(groupids)) {  
  tempmat <- data.mat[data.mat$ID==groupids[i],] 

  results[i,1] <- groupids[i]  
  results[i,2] <- cor(tempmat$Var1,tempmat$Var2,use="pairwise.complete.obs")  
  results[i,3] <- cor(tempmat$Var1,tempmat$Var3,use="pairwise.complete.obs")    

}  

Ich führe das gerade noch einmal durch, um genau zu sehen, wie lange das gedauert hat, aber soweit ich mich erinnere, habe ich es gestartet, als ich morgens ins Büro kam und es irgendwann am Nachmittag fertig war. Abbildung 5-7 Stunden.

Umstrukturierung meines Codes zur Verwendung von data.table ....

data.mat <- read.csv("//home....")  
data.mat <- data.table(data.mat)  

testfunc <- function(x,y,z) {  
  temp1 <- cor(x,y,use="pairwise.complete.obs")  
  temp2 <- cor(x,z,use="pairwise.complete.obs")  
  res <- list(temp1,temp2)  
  res  
}  

system.time(test <- data.mat[,testfunc(Var1,Var2,Var3),by="ID"])  
 user  system  elapsed  
16.41    0.05    17.44  

Wenn ich die Ergebnisse mit data.table mit denen vergleiche, die ich mit einer for-Schleife erhalten habe, um alle IDs zu unterteilen und die Ergebnisse manuell aufzuzeichnen, habe ich anscheinend die gleichen Antworten erhalten (obwohl ich das etwas gründlicher prüfen muss). Das scheint eine ziemlich große Geschwindigkeitssteigerung zu sein.

Update 2:

Das Ausführen des Codes unter Verwendung von Teilmengen endete wieder:

   user     system   elapsed  
17575.79  4247.41   23477.00
Update 3:

Ich wollte sehen, ob etwas mit dem ebenfalls empfohlenen plyr-Paket anders funktioniert. Dies ist das erste Mal, dass ich es verwende, daher habe ich möglicherweise etwas ineffiziente Dinge getan, aber es hat im Vergleich zur for-Schleife mit Teilmenge immer noch erheblich geholfen.

Verwenden Sie dieselben Variablen und Einstellungen wie zuvor ...

data.mat <- read.csv("//home....")  
system.time(hmm <- ddply(data.mat,"ID",function(df)c(cor(df$Var1,df$Var2,  use="pairwise.complete.obs"),cor(df$Var1,df$Var3,use="pairwise.complete.obs"))))  
  user  system elapsed  
250.25    7.35  272.09  

Antworten auf die Frage(4)

Ihre Antwort auf die Frage