2015-04-22 9 views
7

Ich habe zwei VektorenKombinieren jedes Element eines Vektors mit einem anderen Vektor in R

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

ich die folgende Ausgabe erhalten möchten:

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

Wie kann ich z schaffen? Ich habe versucht, paste und c zu verwenden, aber nichts scheint zu funktionieren. Das einzige, was ich mir vorstellen kann, ist eine for() und es ist furchtbar langsam. Ich habe das gegoogelt und ich bin mir sicher, dass die Lösung da draußen ist und ich treffe einfach nicht die richtigen Keywords.

UPDATE: Für Benchmarking Zwecke:

Mit Nicola Lösung:

> 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 

Dieses lächerlich schnell ist! Ich muss sagen! Kann mir bitte jemand das erklären? Meine for() die ich kenne ist immer falsch in R hätte mindestens einen Tag dauern müssen, wenn es auch fertig ist.

Die anderen Vorschläge:

> 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 

hatte ich

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

Nach 15 Minuten zu töten.

+0

Obwohl nicht so schnell wie @ Nicolas eine andere Option ist 'rep (x, each = length (y) +1) * c (1, y)' – akrun

+0

Ich habe eine Bearbeitung vorgenommen, um Dinge zu beschleunigen, wenn 'y' aus allen Nullen besteht. – nicola

Antwort

4

können Sie versuchen, dieses

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 

oder einfacher aus @docendodiscimus

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

Sie könnten 'lapply' verwenden, so dass Sie nicht simplify = FALSE angeben müssen –

+0

Ich habe die anderen Vorschläge nicht ausprobiert, aber das ist extrem schnell (benötigt 30 Sekunden vs. meine Schleife, die mindestens einen Tag gedauert hätte) . –

+0

@cddesjardins es wäre interessant, wenn Sie die anderen Antworten auch auf Geschwindigkeit testen würden. –

2

Sie könnten auch vektorisieren versuchen, so

folgt
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 

Eine kompakte, aber möglicherweise langsame Option (Beitrag von @akrun) wäre

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

Versuchte einige Benchmarks auf einem 1e6 'x' Vektor und 'y' der Länge 100. Mit 'dim <-' ist ein bisschen schneller, @Mamoun Benghezals Lösung kam zuerst, die' replicate' Lösung ist die langsamste, obwohl auf einer Skala von 1 vs 2.9 – akrun

+0

@akrun Interessant. Strange obwohl –

1

können Sie versuchen:

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

Oder eine verrückte Lösung mit GUSB und Paste ..

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

Dies scheint aus irgendeinem Grund schneller:

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

Die obige Lösung ist allgemein in dem Sinne, dass sowohl x als auch y c einen Wert haben. Im OP Fall, wo y nur von 0 gemacht wird, ist dies schnell, wie es sein kann:

`[<-`(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 

bearbeiten

Ich weiß, ich habe sehr kryptisch gewesen und der Code produzierte ich nicht leicht zu folgen, obwohl es nur eine Zeile ist.Ich werde im Detail erklären, was die zweite Lösung tut.

Zuerst bemerken Sie, dass der resultierende Vektor die Werte enthalten x plus die Nullen in y wiederholt length(x) mal haben wird. Also insgesamt wird es length(x) + length(x)*length(y) oder length(x)*(length(y)+1) lang sein. So schaffen wir einen Vektor mit nur so lange Nullen wie nötig:

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

Jetzt müssen wir die x Werte in res platzieren. Wir stellen fest, dass der erste Wert von x den ersten Wert in res belegt; die zweite wird nach length(y)+1 von der ersten und so weiter sein, bis alle length(x) Werte gefüllt sind. Wir können einen Vektor von Indizes erstellen, in dem die x Werte setzen:

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

Und dann machen wir den Wiedereinbau:

res[indices]<-x 

Meine Linie für die drei Linien nur eine Verknüpfung oben war. Hoffe das klärt ein wenig auf.

+1

Ihre Lösung ist die schnellste bisher. Ich dachte, das 't' könnte die Geschwindigkeit reduzieren, aber es hat nicht – akrun

+1

Ja, interessante Lösung. –

+1

Sehr schöne Lösung. Sie können 'integer' anstelle von' numeric' verwenden, um es noch schneller zu machen. – cryo111

1

Hier ist eine andere Art und Weise:

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

Und einige Benchmarks:

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 

Und hier ist eine andere Idee (aber es scheint langsam):

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

Basierend auf dem 'x' von OPs Post, bekomme ich' 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' was nicht das erwartete Ergebnis ist – akrun

+0

Komisch, ich bekomme das Richtige: 'as.numeric (unlist (strsplit (as.Zeichen (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 ja - wissenschaftliche Notation ausschalten: ' Optionen (scipen = 100) ' – nsheff

Verwandte Themen