2015-04-22 15 views
7

Tôi có hai vectơKết hợp mỗi phần tử của một véc tơ với vector khác trong R

x <- c(2, 3, 4) 
y <- rep(0, 5) 

Tôi muốn để có được kết quả như sau:

> z 
2, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0 

Làm thế nào tôi có thể tạo z? Tôi đã cố gắng sử dụng pastec nhưng không có gì có vẻ hiệu quả. Điều duy nhất tôi có thể nghĩ đến là sử dụng một for() và nó là khủng khiếp chậm. Tôi đã googled này và tôi chắc chắn giải pháp là ra khỏi đó và tôi chỉ không đánh đúng từ khóa.

UPDATE: Đối với mục đích benchmarking:

Sử dụng giải pháp Nicola của:

> system.time(
+ precipitation <- `[<-`(numeric(length(x)*(length(y)+1)),seq(1,by=length(y)+1,length.out=length(x)),x) 
+) 
user system elapsed 
0.419 0.407 0.827 

Đây là ridiculously nhanh chóng! Tôi phải nói! Có ai đó giải thích điều này cho tôi biết không? My for() mà tôi biết là luôn luôn sai trong R sẽ phải mất ít nhất một ngày nếu nó thậm chí đã hoàn thành.

Những gợi ý khác:

> length(prate) 
[1] 4914594 
> length(empty) 
[1] 207 
> system.time(
+ precipitation <- unlist(sapply(prate, FUN = function(prate) c(prate,empty), simplify=FALSE)) 
+) 
user system elapsed 
16.470 3.859 28.904 

tôi phải giết

len <- length(prate) 
precip2 <- c(rbind(prate, matrix(rep(empty, len), ncol = len))) 

Sau 15 phút.

+0

Mặc dù không nhanh như @ Nicola của một tùy chọn khác là 'rep (x, each = length (y) +1) * c (1, y)' – akrun

+0

Tôi đã chỉnh sửa để tăng tốc độ khi 'y' được tạo thành từ tất cả các số 0. – nicola

Trả lời

4

bạn có thể thử này

unlist(sapply(x, FUN = function(x) c(x,y), simplify=FALSE)) 
[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 

hoặc đơn giản hơn từ @docendodiscimus

unlist(lapply(x, FUN = function(x) c(x,y))) 
+1

Bạn có thể sử dụng 'lapply' để bạn không cần phải chỉ định simplify = FALSE –

+0

Tôi chưa thử các gợi ý khác nhưng điều này cực kỳ nhanh (mất 30 giây thích hợp so với vòng lặp của tôi sẽ mất ít nhất một ngày) . –

+0

@cddesjardins nó sẽ là thú vị nếu bạn sẽ kiểm tra các câu trả lời khác cho tốc độ quá. –

2

Bạn cũng có thể cố gắng vectorize như sau

len <- length(x) 
c(rbind(x, matrix(rep(y, len), ncol = len))) 
## [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 

Một lựa chọn nhỏ gọn hơn, nhưng có khả năng chậm (do @akrun đóng góp) sẽ là

c(rbind(x, replicate(len, y))) 
## [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 
+0

Đã thử một số điểm chuẩn trên vector 1e6 'x' và 'y' chiều dài 100. Sử dụng 'dim <-' nhanh hơn một chút, giải pháp @Mamoun Benghezal xuất hiện trước, giải pháp' replicate' là chậm nhất, mặc dù trên thang điểm 1 so với 2.9 – akrun

+0

@akrun Thú vị. Strange mặc dù –

1

Bạn có thể thử:

c(sapply(x, 'c', y)) 
#[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 

Hoặc một giải pháp điên với gusb và dán ..

library(functional) 
p = Curry(paste0, collapse='') 

as.numeric(strsplit(p(gsub('(.*)$', paste0('\\1',p(y)),x)),'')[[1]]) 
#[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 
5

Điều này có vẻ nhanh hơn đối với một số lý do:

unlist(t(matrix(c(as.list(x),rep(list(y),length(x))),ncol=2))) 

Các giải pháp trên nói chung, theo nghĩa là cả hai xy c có bất kỳ giá trị nào. Trong trường hợp OP, nơi y được thực hiện chỉ từ 0, đây là nhanh vì nó có thể là:

`[<-`(numeric(length(x)*(length(y)+1)),seq(1,by=length(y)+1,length.out=length(x)),x) 
#[1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0 

Sửa

tôi nhận ra tôi đã rất khó hiểu và mã tôi sản xuất không phải là dễ làm theo, mặc dù chỉ là một dòng.Tôi sẽ giải thích chi tiết về giải pháp thứ hai.

Trước hết, bạn nhận thấy rằng véc-tơ thu được sẽ có các giá trị containd trong x cộng với số không trong y lặp lại length(x) lần. Vì vậy, tổng số, nó sẽ là length(x) + length(x)*length(y) hoặc length(x)*(length(y)+1) dài. Vì vậy, chúng ta tạo ra một vector chỉ với zero miễn là cần thiết:

res<-numeric(length(x)*(length(y)+1)) 

Bây giờ chúng ta phải đặt x giá trị trong res. Chúng tôi nhận thấy rằng giá trị đầu tiên của x chiếm giá trị đầu tiên trong res; số thứ hai sẽ sau length(y)+1 từ lần đầu tiên và tiếp tục, cho đến khi tất cả các giá trị length(x) được lấp đầy. Chúng ta có thể tạo ra một vector của các chỉ số trong đó để đặt x giá trị:

indices<-seq.int(1,by=length(y)+1,length.out=length(x)) 

Và rồi chúng tôi đưa thay thế:

res[indices]<-x 

dòng của tôi chỉ là một phím tắt cho ba dòng trên. Hy vọng điều này làm rõ một chút.

+1

Giải pháp của bạn là nhanh nhất cho đến nay. Tôi nghĩ rằng 't' có thể làm giảm tốc độ, nhưng nó đã không – akrun

+1

Vâng, giải pháp thú vị. –

+1

Giải pháp rất đẹp. Bạn có thể sử dụng 'số nguyên' thay vì' số' để làm cho nó nhanh hơn. – cryo111

1

Dưới đây là một cách khác:

options(scipen=100) 
as.numeric(unlist(strsplit(as.character(x * 10^5), ""))) 

Và một số tiêu chuẩn:

microbenchmark({as.numeric(unlist(strsplit(as.character(x*10^5), "")))}, {unlist(t(matrix(c(as.list(x),rep(list(y),length(x))),ncol=2)))}, {unlist(sapply(x, FUN = function(x) c(x,y), simplify=FALSE))}, times=100000) 
Unit: microseconds 
                     expr 
      {  as.numeric(unlist(strsplit(as.character(x * 10^5), ""))) } 
{  unlist(t(matrix(c(as.list(x), rep(list(y), length(x))), ncol = 2))) } 
     {  unlist(sapply(x, FUN = function(x) c(x, y), simplify = FALSE)) } 
    min  lq  mean median  uq  max neval 
9.286 10.644 12.15242 11.678 12.286 1650.133 100000 
9.485 11.164 13.25424 12.288 13.067 1887.761 100000 
5.607 7.429 9.21015 8.147 8.784 30457.994 100000 

Và đây là một ý tưởng khác (nhưng có vẻ như chậm):

r = rle(1) 
r$lengths = rep(c(1,5), length(x)) 
r$values = as.vector(rbind(x, 0)) 
inverse.rle(r) 
+0

Dựa trên 'x' từ bài đăng của OP, tôi nhận được' as.numeric (unlist (strsplit (as.character (x * 10^5), ""))) # [1] 2 NA NA 0 5 3 NA NA 0 5 4 NA NA 0 5' không phải là kết quả mong đợi – akrun

+0

Hài hước, tôi có được điều đúng: 'as.numeric (unlist (strsplit (as.ký tự (x * 10^5), ""))) [1] 2 0 0 0 0 0 3 0 0 0 0 0 4 0 0 0 0 0' – nsheff

+0

@akrun oh yeah - tắt ký pháp khoa học: ' tùy chọn (scipen = 100) ' – nsheff

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