2010-10-19 26 views
8

Tôi có một data.frame (link to file) với 18 cột và 11520 hàng mà tôi thay đổi như thế này:làm thế nào để tăng tốc độ lên mã R này

library(plyr) 
df.median<-ddply(data, .(groupname,starttime,fPhase,fCycle), 
       numcolwise(median), na.rm=TRUE) 

theo system.time(), nó mất khoảng này dài để chạy:

user system elapsed 
    5.16 0.00 5.17 

Cuộc gọi này là một phần của webapp, vì vậy thời gian chạy là khá quan trọng. Có cách nào để tăng tốc cuộc gọi này không?

+2

Bạn có thể lưu lại kết quả không? – Shane

+0

'ddply()' là đầu tiên và quan trọng nhất * thuận tiện *. Nếu bạn cần một cái gì đó nhanh chóng, bạn có thể cần phải thực hiện lại logic. –

+0

@Shane: Hiện có 3 * 400 bộ dữ liệu có thể (và tăng hàng ngày) mà người dùng có thể yêu cầu. Không chắc rằng một người dùng sẽ nhấn vào cùng một tập dữ liệu khác. Vì vậy, bộ nhớ đệm sẽ chỉ hữu ích trong một phiên. Vì đầu ra của webapp về cơ bản là một báo cáo được đóng hộp, tôi không nghĩ rằng người dùng thường sẽ yêu cầu nó nhiều hơn một lần. Bạn có triển khai bộ nhớ đệm cho tình huống tôi đã mô tả không? Tôi đã không bao giờ làm điều đó trước đây, vì vậy tôi đang ở một chút mất mát. – dnagirl

Trả lời

9

Chỉ cần sử dụng aggregate là khá một chút nhanh hơn ...

> groupVars <- c("groupname","starttime","fPhase","fCycle") 
> dataVars <- colnames(data)[ !(colnames(data) %in% c("location",groupVars)) ] 
> 
> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median)) 
    user system elapsed 
    1.89 0.00 1.89 
> system.time(df.median <- ddply(data, .(groupname,starttime,fPhase,fCycle), numcolwise(median), na.rm=TRUE)) 
    user system elapsed 
    5.06 0.00 5.06 
> 
> ag.median <- ag.median[ do.call(order, ag.median[,groupVars]), colnames(df.median)] 
> rownames(ag.median) <- 1:NROW(ag.median) 
> 
> identical(ag.median, df.median) 
[1] TRUE 
+0

'aggregate' sửa lỗi này một cách thủ công. – dnagirl

7

Chỉ cần để tóm tắt một số điểm từ các ý kiến:

  1. Trước khi bạn bắt đầu để tối ưu hóa, bạn nên có một số ý nghĩa đối với hiệu suất "chấp nhận được". Tùy thuộc vào hiệu suất được yêu cầu, bạn có thể cụ thể hơn về cách cải thiện mã. Ví dụ, tại một số ngưỡng, bạn sẽ cần phải ngừng sử dụng R và chuyển sang một ngôn ngữ được biên dịch.
  2. Khi bạn có thời gian chạy dự kiến, bạn có thể cấu hình mã hiện có của mình để tìm các tắc nghẽn tiềm ẩn. R có một số cơ chế cho việc này, bao gồm Rprof (có các ví dụ về stackoverflow nếu bạn search for [r] + rprof).
  3. plyr được thiết kế chủ yếu để dễ sử dụng, không dành cho hiệu suất (mặc dù phiên bản gần đây có một số cải tiến hiệu suất tốt đẹp). Một số hàm cơ sở nhanh hơn vì chúng có ít chi phí hơn. @ JDLong chỉ đến a nice thread bao gồm một số vấn đề này, bao gồm một số kỹ thuật chuyên môn từ Hadley.
+0

Cảm ơn cho bản tóm tắt. Và cảm ơn tất cả những người đã đóng góp những thông tin hữu ích như vậy. Tôi có rất nhiều đọc để làm! – dnagirl

2

Vâng tôi chỉ cần làm một vài biến đổi đơn giản trên một khung dữ liệu lớn (dữ liệu bóng chày thiết trong gói plyr) sử dụng tiêu chuẩn chức năng thư viện (ví dụ, 'bảng', 'tapply', 'tổng hợp', v.v.) và hàm plyr tương tự - trong mỗi trường hợp, tôi thấy plyr chậm hơn đáng kể. Ví dụ:

> system.time(table(BB$year)) 
    user system elapsed 
    0.007 0.002 0.009 

> system.time(ddply(BB, .(year), 'nrow')) 
    user system elapsed 
    0.183 0.005 0.189 

Thứ hai, và tôi đã làm không điều tra xem liệu điều này sẽ cải thiện hiệu suất trong trường hợp của bạn, nhưng đối với khung dữ liệu kích thước mà bạn đang làm việc với bây giờ và lớn hơn, tôi sử dụng các thư viện data.table, có sẵn trên CRAN. Nó là đơn giản để tạo các đối tượng data.table cũng như để chuyển đổi data.frames còn tồn tại để data.tables - chỉ cần gọi data.table trên data.frame bạn muốn chuyển đổi:

dt1 = data.table(my_dataframe) 
3

Để thêm vào của Joshua dung dịch. Nếu bạn quyết định sử dụng có nghĩa là thay vì trung bình, bạn có thể tăng tốc độ tính toán khác 4 lần:

> system.time(ag.median <- aggregate(data[,dataVars], data[,groupVars], median)) 
    user system elapsed 
    3.472 0.020 3.615 
> system.time(ag.mean <- aggregate(data[,dataVars], data[,groupVars], mean)) 
    user system elapsed 
    0.936 0.008 1.006 
+1

rất thú vị! Tôi sẽ ghi nhớ điều đó. Thật không may, dữ liệu này phải so sánh trung vị. – dnagirl

4

Thứ tự của các dữ liệu quan trọng khi bạn đang tính toán trung vị: nếu dữ liệu là theo thứ tự từ nhỏ đến lớn, sau đó tính toán nhanh hơn một chút.

x <- 1:1e6 
y <- sample(x) 
system.time(for(i in 1:1e2) median(x)) 
    user system elapsed 
    3.47 0.33 3.80 

system.time(for(i in 1:1e2) median(y)) 
    user system elapsed 
    5.03 0.26 5.29 

Đối với bộ dữ liệu mới, hãy sắp xếp dữ liệu theo cột thích hợp khi bạn nhập. Đối với các tập dữ liệu hiện tại, bạn có thể sắp xếp chúng làm công việc theo lô (bên ngoài ứng dụng web).

2

Làm việc với dữ liệu này là nhanh hơn đáng kể với dplyr:

library(dplyr) 

system.time({ 
    data %>% 
    group_by(groupname, starttime, fPhase, fCycle) %>% 
    summarise_each(funs(median(., na.rm = TRUE)), inadist:larct) 
}) 
#> user system elapsed 
#> 0.391 0.004 0.395 

(Bạn sẽ cần dplyr 0.2 để có được %>%summarise_each)

này so sánh thuận lợi để plyr:

library(plyr) 
system.time({ 
    df.median <- ddply(data, .(groupname, starttime, fPhase, fCycle), 
    numcolwise(median), na.rm = TRUE) 
}) 
#> user system elapsed 
#> 0.991 0.004 0.996 

Và đến aggregate() (mã từ @ joshua-ulrich)

groupVars <- c("groupname", "starttime", "fPhase", "fCycle") 
dataVars <- colnames(data)[ !(colnames(data) %in% c("location", groupVars))] 
system.time({ 
    ag.median <- aggregate(data[,dataVars], data[,groupVars], median) 
}) 
#> user system elapsed 
#> 0.532 0.005 0.537 
Các vấn đề liên quan