2013-01-23 10 views
5

Tôi cần tính toán các phương tiện có trọng số cho mỗi hàng (6M + hàng), nhưng phải mất rất nhiều thời gian. Cột có trọng số là trường ký tự, vì vậy không thể sử dụng trọng số.chức năng data.table cho mỗi hàng quá chậm

nền dữ liệu:

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) 
} 

Sau đây là cách nó có thể được thực hiện (quá chậm) với data.frames:

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

này không được công việc nhưng là cách quá chậm (giờ):

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

Làm cách nào để dòng cuối cùng được sửa lại để tăng tốc?

+2

Bạn có câu trả lời tuyệt vời. Chỉ cần thêm: Tôi đấu tranh để suy nghĩ của một định dạng đầu vào tồi tệ hơn. Nếu có thể sử dụng cột danh sách để lưu trữ trọng số dưới dạng vectơ số và hiệu quả không bao giờ _ever_ lặp lại theo hàng, luôn theo cột. Và một ma trận có thể tốt hơn trong các nhiệm vụ như thế này hơn data.table. –

Trả lời

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

Cách tốt nhất để tạo 'rowid' là sử dụng' rowid: = .I' –

2

Vì dường như nhóm đó không liên quan gì đến việc tính toán giá trị trung bình, tôi đã cố gắng đơn giản hóa vấn đề một chút.

 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) 

Trên hệ thống của tôi, cho 100K lặp đi lặp lại,

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

Một phiên bản bảng dữ liệu này (nhóm sans) sẽ là

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

Trên hệ thống của tôi, điều này có

system.time (DT [, wt.mean: = lapply (trọng số, f)]) hệ thống sử dụng trôi qua 3,62 0,03 3,69

vì vậy mong đợi khoảng 35-40 s per million quan sát trên một hệ thống tương đương với mỏ (Win7, 2.8GHz Chip lõi kép, 8GB RAM). YMMV.