2012-05-01 46 views
19

Tôi đang tìm tốc độ càng nhiều càng tốt và ở lại cơ sở để làm những gì expand.grid làm. Tôi đã sử dụng outer cho các mục đích tương tự trong quá khứ để tạo ra một véc tơ; một cái gì đó như thế này:Sử dụng bên ngoài thay vì expand.grid

v <- outer(letters, LETTERS, paste0) 
unlist(v[lower.tri(v)]) 

điểm chuẩn đã cho tôi thấy rằng outer có thể mạnh nhanh hơn expand.grid nhưng lần này tôi muốn tạo hai cột giống như expand.grid (tất cả combo có thể cho 2 vectơ) nhưng phương pháp của tôi với outer không điểm chuẩn nhanh với thời gian bên ngoài.

tôi hy vọng để mất 2 vectơ và tạo mọi kết hợp có thể là hai cột càng nhanh càng tốt (tôi nghĩ outer thể là con đường nhưng tôi rộng mở cho bất kỳ phương pháp cơ bản.

Dưới đây là phương pháp expand.grid và . outer phương pháp

dat <- cbind(mtcars, mtcars, mtcars) 

expand.grid(seq_len(nrow(dat)), seq_len(ncol(dat))) 

FOO <- function(x, y) paste(x, y, sep=":") 
x <- outer(seq_len(nrow(dat)), seq_len(ncol(dat)), FOO) 
apply(do.call("rbind", strsplit(x, ":")), 2, as.integer) 

Các microbenchmarking lãm outer chậm:

#  expr  min  lq median  uq  max 
# EXPAND.G 812.743 838.6375 894.6245 927.7505 27029.54 
# OUTER 5107.871 5198.3835 5329.4860 5605.2215 27559.08 

Tôi nghĩ rằng việc sử dụng outer của tôi chậm vì tôi không biết cách sử dụng outer để trực tiếp tạo chiều dài 2 véc tơ mà tôi có thể do.call('rbind' cùng nhau. Tôi phải làm chậm paste và chia nhỏ. Làm thế nào tôi có thể làm điều này với outer (hoặc các phương pháp khác trong base) theo cách nhanh hơn expand grid?

CHỈNH SỬA: Thêm kết quả microbenchmark.

**

Unit: microseconds 
     expr  min  lq median  uq  max 
1 ERNEST 34.993 39.1920 52.255 57.854 29170.705 
2  JOHN 13.997 16.3300 19.130 23.329 266.872 
3 ORIGINAL 352.720 372.7815 392.377 418.738 36519.952 
4 TOMMY 16.330 19.5960 23.795 27.061 6217.374 
5 VINCENT 377.447 400.3090 418.505 451.864 43567.334 

**

enter image description here

+0

Tyler, bạn có thêm phương pháp của tôi vào danh sách điểm chuẩn không? Nó phải bằng một nửa tốc độ nhanh nhất bạn có ở đây. – John

+0

Đúng vậy. Nó thực sự là nhanh nhất. –

Trả lời

12

Sử dụng rep.int:

expand.grid.alt <- function(seq1,seq2) { 
    cbind(rep.int(seq1, length(seq2)), 
     c(t(matrix(rep.int(seq2, length(seq1)), nrow=length(seq2))))) 
} 

expand.grid.alt(seq_len(nrow(dat)), seq_len(ncol(dat))) 

Trong máy tính của tôi cũng giống như 6 lần nhanh hơn so với expand.grid.

+0

Tôi đã rất hoài nghi nhưng nó rất nhanh. Phản ứng tốt đẹp. Tôi đoán bên ngoài không phải là phương pháp tôi nên có được tham gia. Tôi đã đăng kết quả microbenchmarking lên máy WIn 7 ở trên. –

+1

@TylerRinker Hãy coi chừng, có lỗi trong chức năng của tôi! Đối số 'nrow' sai. Tôi đã sửa nó ngay bây giờ. –

+0

@ErnestA Tôi đã thêm dấu ngoặc đơn ở phía xa bên phải của dòng mã cuối cùng, sau đó phải thêm một số văn bản trước khi có thể gửi chỉnh sửa. –

3

Bạn có thể tạo hai cột riêng.

library(microbenchmark) 
n <- nrow(dat) 
m <- ncol(dat) 
f1 <- function() expand.grid(1:n, 1:m) 
f2 <- function() 
    data.frame( 
    Var1 = as.vector(outer(1:n, rep(1,m))), 
    Var2 = as.vector(outer(rep(1,n), 1:m)) 
) 
microbenchmark(f1, f2, times=1e6) 
# Unit: nanoseconds 
# expr min lq median uq max 
# 1 f1 70 489 490 559 168458 
# 2 f2 70 489 490 559 168597 
+0

Cảm ơn bạn đã phản hồi. Bạn giải quyết vấn đề bên ngoài của tôi và việc học là tuyệt vời. Cách tiếp cận của Ernest rất nhanh, nhanh hơn nhiều so với cách tiếp cận bên ngoài. –

4

@ErnestA có một giải pháp tuyệt vời xứng đáng với việc đánh dấu câu trả lời!

... nó có thể là nhẹ nhanh hơn mặc dù:

expand.grid.alt2 <- function(seq1,seq2) { 
    cbind(Var1=rep.int(seq1, length(seq2)), Var2=rep(seq2, each=length(seq1))) 
} 

s1=seq_len(2000); s2=seq_len(2000) 
system.time(for(i in 1:10) expand.grid.alt2(s1, s2)) # 1.58 
system.time(for(i in 1:10) expand.grid.alt(s1, s2)) # 1.75 
system.time(for(i in 1:10) expand.grid(s1, s2))  # 2.46 
+0

Rất đẹp, chắc chắn là một sự tăng tốc của Ernest. 1 Tôi sẽ giữ kiểm tra trên Ernest mặc dù điều này là nhanh hơn bởi vì tôi đã đưa ra kiểm tra và tôi cảm thấy buồn cười về phân công lại. Nó sẽ làm cho tôi cảm thấy hoàn toàn dễ dàng nếu bạn dựa trên phản ứng của bạn trên câu trả lời của mình :) Tôi có thể hỏi nếu bạn đã làm? –

+1

@TylerRinker - Vâng tôi đã làm. Vì vậy, bạn có thể cảm thấy hoàn toàn dễ dàng ngay bây giờ ;-) – Tommy

+0

@Tommy Tôi đã đi đến độ dài lớn để tránh 'rep (... each =)' bởi vì tôi cho rằng nó sẽ chậm hơn. Trong thực tế, nó không phải là. –

13

Các tài liệu cho rep.int không phải là khá hoàn chỉnh. Nó không chỉ là nhanh nhất trong trường hợp phổ biến nhất bởi vì bạn có thể truyền vectơ cho đối số lần, giống như với rep. Bạn có thể sử dụng nó đơn giản cho cả hai trình tự giảm thời gian khác 40% hoặc hơn so với Tommy.

expand.grid.jc <- function(seq1,seq2) { 
    cbind(Var1 = rep.int(seq1, length(seq2)), 
    Var2 = rep.int(seq2, rep.int(length(seq1),length(seq2)))) 
} 
+0

trong trạng thái hiện tại, mã của bạn sẽ phát sinh lỗi. Tôi nghĩ rằng nó thiếu một dấu ngoặc đơn ở đâu đó nhưng tôi không thể tìm ra nơi. –

+0

+1 Tuyệt vời! Nó * không nên * nhanh hơn của tôi, nhưng nó chắc chắn là :-) Rõ ràng, 'rep' cần phải cải thiện cách nó xử lý đối số' mỗi' ... – Tommy

+0

có Tommy, nên ... Tôi thực sự nghĩ rằng expand.grid sử dụng một cái gì đó như những gì tôi đã viết nội bộ ... nó chỉ chậm vì kiểm tra lỗi và mạnh mẽ. – John

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