2015-05-28 19 views
10

Tôi muốn tóm tắt một số biến trong khung dữ liệu dựa trên một cột. Tuy nhiên khung dữ liệu của tôi khá lớn (> 30.000.000 hàng) và việc sử dụng hàm tổng hợp trong dplyr mất nhiều thời gian để chạy. Có cách nào nhanh hơn trong R để tăng tốc quá trình tổng hợp không?Cách nhanh hơn để tóm tắt các biến dựa trên cột trong R

Tôi có một df khung dữ liệu trong định dạng:

proid X1 X2 X3 X4 
1  1 zz a e a 
2  2 ff g z b 
3  1 cd s f d 
4  3 ab t e e 
5  2 ta b h k 
     .... 

Tôi muốn nối các biến X1 để X4 khi họ có giá trị prodid cùng. Các chuỗi nối được phân tách bằng dấu phẩy. Vì vậy, các bảng trên nên cho tôi bảng mới:

proid  X1 X2 X3 X4 
1  1 zz,cd a,s e,f a,d 
2  2 ff,ta g,b z,h b,k 
3  3  ab t e e 
     .... 

Tôi đã sử dụng mã dplyr sau:

concat <- function(x){ 
    x <- na.omit(x) 
    if(length(x)==0){ 
    return(as.character(NA)) 
    }else{ 
    return(paste(x,collapse=",")) 
    } 
} 

dg<-group_by(df,proid) 
df<-summarise(dg,proid,concat(X1),concat(X2),concat(X3),concat(X4)) 
+3

thử 'setDT (df) [, lapply (.SD, concat), by = proid] 'và xem những gì timings trông giống như – eddi

Trả lời

11

Sửa lưu ý: loại bỏ phần gốc của câu trả lời của tôi mà không giải quyết NA điều trị & thêm điểm chuẩn.

concat2 <- function(x) if(all(is.na(x))) NA_character_ else paste(na.omit(x), collapse = ",") 

Sử dụng data.table:

setDT(df)[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")] 
# proid X1 X2 X3 
#1:  1 zz,cd a,s e,f 
#2:  2 ff,ta g,b z,h 
#3:  3 NA t e 

Sử dụng dplyr:

df %>% group_by(proid) %>% summarise_each(funs(concat2), -X4) 

Benchmark, dữ liệu nhỏ hơn trong trường hợp sử dụng thực tế và không đại diện đầy đủ, vì vậy chỉ muốn để có được một ấn tượng như thế nào concat2 so sánh với concat vv ..

library(microbenchmark) 
library(dplyr) 
library(data.table) 

N <- 1e6 
x <- c(letters, LETTERS) 
df <- data.frame(
    proid = sample(1e4, N, TRUE), 
    X1 = sample(sample(c(x, NA), N, TRUE)), 
    X2 = sample(sample(c(x, NA), N, TRUE)), 
    X3 = sample(sample(c(x, NA), N, TRUE)), 
    X4 = sample(sample(c(x, NA), N, TRUE)) 
) 

dt <- as.data.table(df) 

concat <- function(x){ 
    x <- na.omit(x) 
    if(length(x)==0){ 
    return(as.character(NA)) 
    }else{ 
    return(paste(x,collapse=",")) 
    } 
} 

concat2 <- function(x) if(all(is.na(x))) NA_character_ else paste(na.omit(x), collapse = ",") 

concat.dplyr <- function(){ 
    df %>% group_by(proid) %>% summarise_each(funs(concat), -X4) 
} 

concat2.dplyr <- function(){ 
    df %>% group_by(proid) %>% summarise_each(funs(concat2), -X4) 
} 

concat.data.table <- function(){ 
    dt[, lapply(.SD, concat), by = proid, .SDcols = -c("X4")] 
} 

concat2.data.table <- function(){ 
    dt[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")] 
} 


microbenchmark(concat.dplyr(), 
       concat2.dplyr(), 
       concat.data.table(), 
       concat2.data.table(), 
       unit = "relative", 
       times = 10L) 
Unit: relative 
       expr  min  lq median  uq  max neval 
     concat.dplyr() 1.058839 1.058342 1.083728 1.105907 1.080883 10 
     concat2.dplyr() 1.057991 1.065566 1.109099 1.145657 1.079201 10 
    concat.data.table() 1.024101 1.018443 1.093604 1.085254 1.066560 10 
concat2.data.table() 1.000000 1.000000 1.000000 1.000000 1.000000 10 

Kết quả: dữ liệu. Có thể thực hiện nhanh hơn một chút so với dplyr trên dữ liệu mẫu và concat2 nhanh hơn một chút so với concat. Tuy nhiên, sự khác biệt vẫn còn khá nhỏ trên tập dữ liệu mẫu này.

+0

Phiên bản data.table chạy trong khoảng một phần tư thời gian của phiên bản dplyr trên máy tính của tôi. Phiên bản dplyr/tidyr của @StevenBeaupre chạy trong khoảng 1,5 lần phiên bản dplyr. – eipi10

+4

Cả hai giải pháp này không tính đến 'na.omit()' trong hàm OP ... @ eipi10, chênh lệch tốc độ với 'dplyr' sẽ phụ thuộc phần lớn vào số lượng nhóm, và b) số hàng (theo thứ tự đó) ... – Arun

+1

@ user22119, có lẽ bạn nên làm quen rồi: P. Bắt đầu với các họa tiết HTML [ở đây] (https://github.com/Rdatatable/data.table/wiki/Getting-started). – Arun

2

na.omit thực hiện nhiều lần kiểm tra và hoạt động không cần thiết. Thay thế nó bằng đơn giản is.na gọi sẽ cung cấp cho bạn một tăng tốc khá:

concat3 = function(x) { 
    x = x[!is.na(x)] 
    if (length(x) == 0) 
    NA_character_ 
    else 
    paste(x, collapse = ",") 
} 

Sử dụng dữ liệu docendo của (nhưng với chuỗi thay vì các yếu tố - Các yếu tố chậm tất cả các phiên bản xuống):

microbenchmark(dt[, lapply(.SD, concat3), by = proid, .SDcols = -c("X4")], 
       dt[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")], 
       times = 5) 
#Unit: milliseconds 
#              expr  min  lq  mean median  uq  max neval 
# dt[, lapply(.SD, concat3), by = proid, .SDcols = -c("X4")] 960.2475 1079.177 1251.545 1342.684 1402.571 1473.045  5 
# dt[, lapply(.SD, concat2), by = proid, .SDcols = -c("X4")] 1718.8121 1892.696 2159.148 2171.772 2470.205 2542.253  5 
Các vấn đề liên quan