2013-05-20 16 views
6

Tôi có một khung dữ liệu lớn với cột yếu tố mà tôi cần chia thành ba cột yếu tố bằng cách tách các tên hệ số bằng dấu tách. Đây là cách tiếp cận hiện tại của tôi, rất chậm với khung dữ liệu lớn (đôi khi vài triệu hàng):Tăng tốc `strsplit` khi đầu ra có thể được biết là

data <- readRDS("data.rds") 
data.df <- reshape2:::melt.array(data) 
head(data.df) 
## Time Location Class Replicate Population 
##1 1  1 LIDE.1.S   1 0.03859605 
##2 2  1 LIDE.1.S   1 0.03852957 
##3 3  1 LIDE.1.S   1 0.03846853 
##4 4  1 LIDE.1.S   1 0.03841260 
##5 5  1 LIDE.1.S   1 0.03836147 
##6 6  1 LIDE.1.S   1 0.03831485 

Rprof("str.out") 
cl <- which(names(data.df)=="Class") 
Classes <- do.call(rbind, strsplit(as.character(data.df$Class), "\\.")) 
colnames(Classes) <- c("Species", "SizeClass", "Infected") 
data.df <- cbind(data.df[,1:(cl-1)],Classes,data.df[(cl+1):(ncol(data.df))]) 
Rprof(NULL) 

head(data.df) 
## Time Location Species SizeClass Infected Replicate Population 
##1 1  1 LIDE   1  S   1 0.03859605 
##2 2  1 LIDE   1  S   1 0.03852957 
##3 3  1 LIDE   1  S   1 0.03846853 
##4 4  1 LIDE   1  S   1 0.03841260 
##5 5  1 LIDE   1  S   1 0.03836147 
##6 6  1 LIDE   1  S   1 0.03831485 

summaryRprof("str.out") 

$by.self 
       self.time self.pct total.time total.pct 
"strsplit"   1.34 50.00  1.34  50.00 
"<Anonymous>"   1.16 43.28  1.16  43.28 
"do.call"    0.04  1.49  2.54  94.78 
"unique.default"  0.04  1.49  0.04  1.49 
"data.frame"   0.02  0.75  0.12  4.48 
"is.factor"   0.02  0.75  0.02  0.75 
"match"    0.02  0.75  0.02  0.75 
"structure"   0.02  0.75  0.02  0.75 
"unlist"    0.02  0.75  0.02  0.75 

$by.total 
         total.time total.pct self.time self.pct 
"do.call"     2.54  94.78  0.04  1.49 
"strsplit"     1.34  50.00  1.34 50.00 
"<Anonymous>"    1.16  43.28  1.16 43.28 
"cbind"      0.14  5.22  0.00  0.00 
"data.frame"     0.12  4.48  0.02  0.75 
"as.data.frame.matrix"  0.08  2.99  0.00  0.00 
"as.data.frame"    0.08  2.99  0.00  0.00 
"as.factor"     0.08  2.99  0.00  0.00 
"factor"      0.06  2.24  0.00  0.00 
"unique.default"    0.04  1.49  0.04  1.49 
"unique"      0.04  1.49  0.00  0.00 
"is.factor"     0.02  0.75  0.02  0.75 
"match"      0.02  0.75  0.02  0.75 
"structure"     0.02  0.75  0.02  0.75 
"unlist"      0.02  0.75  0.02  0.75 
"[.data.frame"    0.02  0.75  0.00  0.00 
"["       0.02  0.75  0.00  0.00 

$sample.interval 
[1] 0.02 

$sampling.time 
[1] 2.68 

Có cách nào để tăng tốc hoạt động này không? Tôi lưu ý rằng có một số nhỏ (< 5) của mỗi danh mục "Loài", "Kích thước" và "Bị nhiễm" và tôi biết những điều này là trước.

Ghi chú:

  • stringr::str_split_fixed thực hiện nhiệm vụ này, nhưng không phải bất kỳ nhanh
  • Khung dữ liệu được thực sự ban đầu được tạo ra bằng cách gọi reshape::melt trên một mảng trong đó Class và mức độ liên quan của nó là một kích thước. Nếu có một cách nhanh hơn để đi từ đó đến đây, thật tuyệt.
  • data.rds tại http://dl.getdropbox.com/u/3356641/data.rds

Trả lời

5

này có lẽ nên cung cấp khá tăng:

library(data.table) 
DT <- data.table(data.df) 


DT[, c("Species", "SizeClass", "Infected") 
     := as.list(strsplit(Class, "\\.")[[1]]), by=Class ] 

Những lý do cho sự gia tăng:

  1. data.table trước cấp phát bộ nhớ cho các cột
  2. mỗi phép gán cột trong data.frame gán lại toàn bộ dữ liệu (data.table ngược lại không)
  3. tuyên bố by cho phép bạn thực hiện tác vụ strsplit một lần cho mỗi giá trị duy nhất.

Dưới đây là một phương pháp nhanh chóng tốt đẹp cho toàn bộ quá trình.

# Save the new col names as a character vector 
newCols <- c("Species", "SizeClass", "Infected") 

# split the string, then convert the new cols to columns 
DT[, c(newCols) := as.list(strsplit(as.character(Class), "\\.")[[1]]), by=Class ] 
DT[, c(newCols) := lapply(.SD, factor), .SDcols=newCols] 

# remove the old column. This is instantaneous. 
DT[, Class := NULL] 

## Have a look: 
DT[, lapply(.SD, class)] 
#  Time Location Replicate Population Species SizeClass Infected 
# 1: integer integer integer numeric factor factor factor 

DT 
+0

Nhanh quá! Mặc dù bạn đã sử dụng 'as.character (Class)'. Bạn có thể trả về các cột dưới dạng các thừa số trong cùng một lệnh không? –

+0

Bạn có thể chuyển đổi thành yếu tố, nhưng sau đó thực hiện như một dòng thứ hai. Sử dụng as.factor trong cùng một cuộc gọi bao gồm đối số 'by' nhất thiết sẽ làm chậm quá trình. –

+0

@NoamRoss, bắt đẹp trên 'as.character'. Cập nhật mã cộng với một vài bước bổ sung –

3

Bạn có thể nhận một sự gia tăng khá về tốc độ bằng cách chỉ trích các bộ phận của chuỗi bạn không cần sử dụng gsub thay vì tách tất cả mọi thứ lên và cố gắng để đưa nó trở lại với nhau:

data <- readRDS("~/Downloads/data.rds") 
data.df <- reshape2:::melt.array(data) 

# using `strsplit` 
system.time({ 
cl <- which(names(data.df)=="Class") 
Classes <- do.call(rbind, strsplit(as.character(data.df$Class), "\\.")) 
colnames(Classes) <- c("Species", "SizeClass", "Infected") 
data.df <- cbind(data.df[,1:(cl-1)],Classes,data.df[(cl+1):(ncol(data.df))]) 
}) 

user system elapsed 
3.349 0.062 3.411 

#using `gsub` 
system.time({ 
data.df$Class <- as.character(data.df$Class) 
data.df$SizeClass <- gsub("(\\w+)\\.(\\d+)\\.(\\w+)", "\\2", data.df$Class, 
    perl = TRUE) 
data.df$Infected <- gsub("(\\w+)\\.(\\d+)\\.(\\w+)", "\\3", data.df$Class, 
    perl = TRUE) 
data.df$Class <- gsub("(\\w+)\\.(\\d+)\\.(\\w+)", "\\1", data.df$Class, 
    perl = TRUE) 
}) 

user system elapsed 
0.812 0.037 0.848 
+0

+1 phương pháp rất tốt đẹp! –

2

Hình như bạn có một yếu tố, do đó, làm việc trên các cấp độ và sau đó bản đồ trở lại. Sử dụng fixed=TRUE trong strsplit, điều chỉnh thành split=".".

Classes <- do.call(rbind, strsplit(levels(data.df$Class), ".", fixed=TRUE)) 
colnames(Classes) <- c("Species", "SizeClass", "Infected") 
df0 <- as.data.frame(Classes[data.df$Class,], row.names=NA) 
cbind(data.df, df0) 
+1

Thực sự là một câu trả lời tuyệt vời - đơn giản và không thêm phụ thuộc mới. Nhưng sự tham gia có thể chậm với một data.frame lớn, vì vậy, cấu trúc 'data.frame' của Ricardo là một giải pháp tốt hơn cho tôi. –

+0

Rất tiếc, có nghĩa là cấu trúc 'data.table', nhưng tôi không thể chỉnh sửa nhận xét sau thời gian này. –

+0

Đề xuất này đã tăng tốc mã của tôi theo thứ tự độ lớn! Cảm ơn! – CephBirk

Các vấn đề liên quan