2013-01-23 17 views
5

Ich muss gewichtete Mittel pro Zeile (6M + Zeilen) berechnen, aber es dauert sehr lange Zeit. Die Spalte mit Gewichten ist ein Zeichenfeld, also kann gewichtet werden.kann nicht direkt verwendet werden.data.table Funktion pro Zeile zu langsam

Hintergrunddaten:

library(data.table) 
library(stringr) 
values <- c(1,2,3,4) 
grp <- c("a", "a", "b", "b") 
weights <- c("{10,0,0,0}", "{0,10,0,0}", "{10,10,0,0}", "{0,0,10,0}") 
DF <- data.frame(cbind(grp, weights)) 
DT <- data.table(DF) 

string.weighted.mean <- function(weights.x) { 
    tmp.1 <- na.omit(as.numeric(unlist(str_split(string=weights.x, pattern="[^0-9]+")))) 
    tmp.2 <- weighted.mean(x=values, w=tmp.1) 
} 

Hier ist, wie es (zu langsam) mit data.frames getan werden kann:

DF$wm <- mapply(string.weighted.mean, DF$weights) 

den Job Dies tut aber ist viel zu langsam (Stunden):

DT[, wm:=mapply(string.weighted.mean, weights)] 

Wie kann die letzte Zeile umformuliert werden, um die Dinge zu beschleunigen?

+2

Sie haben eine gute Antwort. Nur um hinzuzufügen: Ich habe Mühe, an ein schlechteres Eingabeformat zu denken. Wenn möglich, verwenden Sie Listenspalten, um die Gewichtungen als numerische Vektoren zu speichern, und für Effizienz nie _ever_ iterieren nach Zeile, immer nach Spalte. Und eine Matrix mag bei solchen Aufgaben besser sein als data.table. –

Antwort

6
DT[, rowid := 1:nrow(DT)] 
setkey(DT, rowid) 
DT[, wm :={ 
    weighted.mean(x=values, w=na.omit(as.numeric(unlist(str_split(string=weights, pattern="[^0-9]+")))))  
}, by=rowid] 
+1

Eine schöne Möglichkeit, die 'rowid' zu verwenden, ist' rowid: = .I' –

2

Da es scheint nicht, dass Gruppe etwas mit der Berechnung des gewichteten Mittels zu tun, habe ich versucht, das Problem ein wenig zu vereinfachen.

 values <- seq(4) 

# A function to compute a string of length 4 with random weights 0 or 10 
    tstwts <- function() 
    { 
     w <- sample(c(0, 10), 4, replace = TRUE) 
     paste0("{", paste(w, collapse = ","), "}") 
    } 

# Generate 100K strings and put them into a vector 
    u <- replicate(1e5, tstwts()) 
    head(u) # Check 
    table(u) 

# Function to compute a weighted mean from a string using values 
# as an assumed external numeric vector 'values' of the same length as 
# the weights 
    f <- function(x) 
     { 
      valstr <- gsub("[\\{\\}]", "", x) 
      wts <- as.numeric(unlist(strsplit(valstr, ","))) 
      sum(wts * values)/sum(wts) 
     } 

# Execute the function f recursively on the vector of weights u 
    v <- sapply(u, f) 

# Some checks: 
    head(v) 
    table(v) 

Auf meinem System für 100K Wiederholungen,

> system.time(sapply(u, f)) 
    user system elapsed 
    3.79 0.00 3.83 

Eine Datentabelle Version dieser (sans Gruppen)

DT <- data.table(weights = u) 
DT[, wt.mean := lapply(weights, f)]) 
head(DT) 
dim(DT) 

Auf meinem System wäre, das dauert

system.time (DT [, wt.mean: = lapply (Gewichte, f)]) Benutzersystem verstrichene 3,62 0,03 3,69

so etwa 35-40 s pro Million Beobachtungen auf einem System vergleichbar Mine (Win7, 2,8 GHz Dual-Core-Chip, 8 GB RAM) erwarten. YMMV.