2009-09-29 17 views
36

Ho un vettore logico, per il quale desidero inserire nuovi elementi in particolari indici. Ho trovato una soluzione maldestra di seguito, ma esiste un modo più ordinato?Come inserire elementi in un vettore?

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) 

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

e

print(probes.2) 

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

Così funziona, ma è brutto cercando - qualche suggerimento?

+0

Perché avete bisogno di fare l'inserimento? – hadley

+0

lunga storia, ma fondamentalmente alla ricerca di esecuzioni di TRUE, ma ho luoghi predeterminati in cui voglio interrompere una corsa. La prima volta che ho usato "rle" ma scalato molto male, così mi è venuta in mente questa soluzione vettoriale sporca –

risposta

29

Si può fare qualche magia con gli indici:

Innanzitutto creare vettore con valori di uscita:

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 

Ora trucco. Ogni elemento vecchio ottiene rango, ogni nuovo elemento prende la metà-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 

Quindi utilizzare order per ordinare in ordine corretto:

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

Bello e subdolo - quanto bene scala l'ordine con migliaia/milioni di elementi? –

+0

Su 1.58GHz Core2 system.time (ordine (rnorm (1e6))) richiede <2s – Marek

2

Questo è un po 'complicato. Ecco un modo. Itera su tutta la lista, inserendo ogni volta, quindi non è troppo efficiente.

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 

Questo dovrebbe anche funzionare se ind ha ripetuto gli elementi, anche se ind ha bisogno di essere ordinati per la costruzione probes.ind al lavoro.

6

ne dite di questo:

> 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

Subdolo! Usa il fatto che as.vector fa un collasso in termini di colonne della matrice creata da rbind. Questo perché una matrice è solo un vettore con informazioni aggiuntive che indicano il numero di righe e memorizzato internamente in ordine di colonna. Questo fa parte della definizione del linguaggio R, ma potrebbe essere un po 'oscuro, a seconda di chi sta leggendo il codice ... – Harlan

+0

@Harlan Ottima spiegazione. Questo fa una grande differenza quando si lavora con questo esempio. – Rob

57

Questi sono tutti approcci molto creativi. Penso che lavorare con gli indici sia sicuramente la strada da percorrere (la soluzione di Marek è molto bella).

Vorrei solo menzionare che c'è una funzione da fare grosso modo: append().

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

Oppure si potrebbe fare questo in modo ricorsivo con gli indici (è necessario far crescere il "dopo" valore ad ogni iterazione):

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

Per inciso, this question was also previously asked on R-Help. Come dice Barry:

"In realtà direi che non c'erano modi per farlo, dal momento che non penso che si possa effettivamente inserire in un vettore - devi creare un nuovo vettore che produce l'illusione dell'inserimento!"

+0

Non conoscevo la funzione append, grazie per averlo portato alla mia attenzione! Avrei dovuto specificare nella mia domanda che non volevo un ciclo perché i miei veri vettori avrebbero migliaia/milioni di elementi –

+1

E si può impostare 'after = 0' per inserire un nuovo valore all'inizio di un vettore. – coip

+0

Se 'ind' è ordinato, come sembri assumere, puoi fare il ciclo più semplicemente al contrario:' 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 

Alcune timing: Il mio metodo sistema dell'utente trascorso 0,03 0,00 0,03

Marek metodo sistema dell'utente trascorso 0.18 0.00 0.18

R accoda con ciclo for sistema dell'utente è trascorso 1,61 0,48 2,10

+2

Ottima idea, sembra essere il modo più efficiente per farlo! Tuttavia, è necessario spostare tutti gli indici per fare in modo che funzioni come previsto, ovvero aggiungere 'ind <- ind + 0: (length (ind) -1)' prima di eseguire assegnazioni a 'new.probes'. – aoles

+0

Puoi omettere l'ultimo passo (e la definizione di 'val') semplicemente inizializzando' new.probes' con i valori da sostituire: 'new.probes <- rep (FALSE, length (probes) + length (val))'. Questo lo rende ancora più veloce. –

1

o si può farlo utilizzando la funzione insertRow dal pacchetto miscTools.

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

Sono arrivato qui a cercarlo. I trucchi sull'uso dei nomi da ordinare sono interessanti e approfondiscono la mia comprensione della lingua, ma è meglio per la mia situazione. – Chris

Problemi correlati