2009-09-29 22 views
36

Mam wektor logiczny, dla którego chcę wstawić nowe elementy w poszczególnych indeksach. Wymyśliłem poniżej niezręczne rozwiązanie, ale czy jest jakiś lepszy sposób?Jak wstawiać elementy do wektora?

probes <- rep(TRUE, 15) 
ind <- c(5, 10) 
probes.2 <- logical(length(probes)+length(ind)) 
probes.ind <- ind + 1:length(ind) 
probes.original <- (1:length(probes.2))[-probes.ind] 
probes.2[probes.ind] <- FALSE 
probes.2[probes.original] <- probes 

print(probes) 

daje

[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 

i

print(probes.2) 

daje

[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 

Tak to działa, ale jest brzydki patrząc - jakieś sugestie?

+0

Dlaczego trzeba wkładać? – hadley

+0

długa historia, ale w zasadzie szukają serii PRAWDA, ale mają określone miejsca, w których chcę zerwać bieg. Pierwszy raz użyłem "rle", ale skalowałem bardzo słabo, więc wymyśliłem to brudne rozwiązanie wektorowe –

Odpowiedz

29

Można zrobić jakąś magię z indeksów:

Najpierw utwórz wektor z wartościami wyjściowymi:

probs <- rep(TRUE, 15) 
ind <- c(5, 10) 
val <- c(probs, rep(FALSE,length(ind))) 
# > val 
# [1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE 
# [13] TRUE TRUE TRUE FALSE FALSE 

Teraz oszukać. Każdy stary element otrzymuje rangę, każdy nowy element staje się pół-Rank

id <- c(seq_along(probs), ind+0.5) 
# > id 
# [1] 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 14.0 15.0 
# [16] 5.5 10.5 

Następnie użyj order uporządkować w odpowiedniej kolejności:

val[order(id)] 
# [1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
# [13] TRUE TRUE TRUE TRUE TRUE 
+1

Ładne i podstępne - jak dobrze uporządkuje skalę z tysiącami/milionami elementów? –

+0

Na 1.58 GHz Core2 system.time (kolejność (rnorm (1e6))) trwa <2s – Marek

2

To trochę kłopotliwe. Oto jeden sposób. Iteruje nad listą, wstawiając za każdym razem, więc nie jest zbyt wydajna.

probes <- rep(TRUE, 15) 
probes.ind <- ind + 0:(length(ind)-1) 
for (i in probes.ind) { 
    probes <- c(probes[1:i], FALSE, probes[(i+1):length(probes)]) 
} 

> probes 
[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 

Powinno to działać nawet jeśli ind powtórzył elementy, chociaż ind nie muszą być klasyfikowane do budowy probes.ind do pracy.

6

Jak o tym:

> probes <- rep(TRUE, 15) 
> ind <- c(5, 10) 

> probes.ind <- rep(NA, length(probes)) 
> probes.ind[ind] <- FALSE 
> new.probes <- as.vector(rbind(probes, probes.ind)) 
> new.probes <- new.probes[!is.na(new.probes)] 
> new.probes 
[1] TRUE TRUE TRUE TRUE TRUE FALSE TRUE TRUE TRUE TRUE TRUE FALSE 
[13] TRUE TRUE TRUE TRUE TRUE 
+3

Sneaky! Wykorzystuje fakt, że as.vector ma kolumnową zapaść macierzy utworzonej przez rbind. Dzieje się tak dlatego, że macierz jest po prostu wektorem z dodatkowymi informacjami, które wskazują liczbę wierszy i są przechowywane wewnętrznie w kolejności zgodnej z kolejnością kolumn. Jest to część definicji języka R, ale może być nieco niejasne, w zależności od tego, kto czyta kod ... – Harlan

+0

@Harlan Świetne wyjaśnienie. To robi dużą różnicę, gdy pracujemy nad tym przykładem. – Rob

57

Są bardzo twórcze podejście. Myślę, że praca z indeksami to zdecydowanie najlepsza droga (rozwiązanie Marka jest bardzo miłe).

Chciałbym tylko wspomnieć, że istnieje funkcja do zrobienia z grubsza, że: append().

probes <- rep(TRUE, 15) 
probes <- append(probes, FALSE, after=5) 
probes <- append(probes, FALSE, after=11) 

Albo można to zrobić rekursywnie z indeksów (trzeba się rozwijać "po" wartość w każdej iteracji):

probes <- rep(TRUE, 15) 
ind <- c(5, 10) 
for(i in 0:(length(ind)-1)) 
    probes <- append(probes, FALSE, after=(ind[i+1]+i)) 

Nawiasem mówiąc, this question was also previously asked on R-Help. Jak mówi Barry:

"Właściwie powiedziałbym, że nie było na to sposobu, ponieważ nie sądzę, że możesz włożyć do wektora - musisz stworzyć nowy wektor, który wytwarza iluzję wstawienia!"

+0

Nie wiedziałem o funkcji dołączania, dzięki za zwrócenie mi uwagi! Powinienem określić w moim pytaniu, że nie chcę pętli, ponieważ moje prawdziwe wektory będą miały tysiące/miliony elementów. –

+1

I można ustawić 'after = 0', aby wstawić nową wartość na początku wektora. – coip

+0

Jeśli 'ind' jest posortowane, jak się wydaje zakładać, możesz zrobić pętlę po prostu w odwrotnej kolejności:' for (i in length (ind): 1) append (..., after = ind [i]) ' ? –

7
probes <- rep(TRUE, 1000000) 
ind <- c(50:100) 
val <- rep(FALSE,length(ind)) 

new.probes <- vector(mode="logical",length(probes)+length(val)) 
new.probes[-ind] <- probes 
new.probes[ind] <- val 

Niektóre czasy: Moja metoda systemu użytkownik upłynął 0,03 0,00 0,03

Marek metoda systemu użytkownik upłynął 0,18 0,00 0.18

R dołączyć do pętli z systemu użytkownika, który upłynął 1,61 0,48 2,10

+2

Świetny pomysł, wydaje się być najskuteczniejszym sposobem robienia tego! Musisz jednak przesunąć wszystkie indeksy, aby działało zgodnie z zamierzeniami, tj. Dodaj 'ind <- ind + 0: (length (ind) -1)' przed wykonaniem przypisań do 'new.probes'. – aoles

+0

Możesz pominąć ostatni krok (i definicję 'val'), po prostu inicjując' new.probes' z wartościami do zastąpienia: 'new.probes <- rep (FALSE, length (probes) + length (val))'. To sprawia, że ​​jest jeszcze szybszy. –

1

Albo można to zrobić za pomocą funkcji insertRow z pakietu miscTools.

probes <- rep(TRUE, 15) 
ind <- c(5,10) 
for (i in ind){ 
    probes <- as.vector(insertRow(as.matrix(probes), i, FALSE)) 
} 
+0

Poszukałem tego. Sztuczki dotyczące używania nazw do sortowania są fajne i pogłębiają moje zrozumienie języka, ale to jest lepsze dla mojej sytuacji. – Chris

Powiązane problemy