2016-05-27 11 views
6

Sto tentando di eliminare sequenze di righe da un frame di dati, la sequenza inizia con una stringa nota e termina con una stringa nota, ma il il contenuto e il numero delle file intermedie sono sconosciuti. Vorrei ripetere questa operazione sull'intero frame dei dati.R Per l'intervallo di eliminazione loop delle righe da una stringa a una seconda stringa in una colonna

Ad esempio, se il frame di dati è come indicato di seguito, vorrei rimuovere le righe da tutte le istanze di StringA a StringB (incluso) ma mantenere le righe che seguono StringB fino alla ricorrenza successiva di StringA; per l'esempio di seguito, cioè, vorrei rimuovere le righe contenenti StringA, unknownC, unknownD, unknownS, StringB, ma quindi mantenere unknownK e unknownR, quindi continuare a eliminare StringA, unknownU, unknownP, StringB, ma mantenere unknownT.

Column 1 Column 2 
StringA  1 
unknownC 9 
unknownD 11 
unknownS 5 
StringB 7 
unknownK 6 
unknownR 1 
StringA 76 
unknownU 2 
unknownP 41 
StringB 3 
unknownT 9 

ho provato df2 <- df[1:which(df[,1]=="StringA")-1,], che non è corretto, ma sono in perdita come quello che altro approccio per provare. Grazie in anticipo per qualsiasi consiglio.

+2

È noto per certo che stringA è sempre associato a una stringa successiva B? È anche noto per certo che le stringhe A e B si alternano sempre (e, g. Mai A ... A ... B)? – dww

+0

Sì, lo è. Sarà sempre A ... B, e mai A..A ... B – SPZ

risposta

5

si può provare qualcosa di simile, costruendo l'indice di essere rimosso utilizzando la funzione Map:

indexToRemove <- unlist(Map(`:`, which(df$`Column 1` == "StringA"), 
           which(df$`Column 1` == "StringB"))) 

df[-indexToRemove, ] 
    Column 1 Column 2 
6 unknownK  6 
7 unknownR  1 
12 unknownT  9 

dati:

structure(list(`Column 1` = structure(c(1L, 3L, 4L, 8L, 2L, 5L, 
7L, 1L, 10L, 6L, 2L, 9L), .Label = c("StringA", "StringB", "unknownC", 
"unknownD", "unknownK", "unknownP", "unknownR", "unknownS", "unknownT", 
"unknownU"), class = "factor"), `Column 2` = c(1L, 9L, 11L, 5L, 
7L, 6L, 1L, 76L, 2L, 41L, 3L, 9L)), .Names = c("Column 1", "Column 2" 
), class = "data.frame", row.names = c(NA, -12L)) 
+0

Hmm Mi piace l'idea di questa strategia Psidom, ma non sono sicuro di come evitare questo avvertimento che ho ricevuto quando ho provato il primo passo : In mapply (FUN = f, ..., SIMPLIFY = FALSE): argomento più lungo non multiplo di lunghezza più breve – SPZ

+0

Spot on for me. Bravo –

+0

Non esattamente sicuro, ma se la tua colonna è qualcosa come 'A ... B ... A ...' o 'B ... A ... B..' questo potrebbe accadere. – Psidom

3

È possibile utilizzare un ciclo for. Anche se questo sarà più lento delle soluzioni vettorializzate pubblicate, ha alcuni vantaggi in termini di essere abbastanza versatile per adattarsi a problemi simili simili e di essere robusto contro i dati di input inaspettati.

Note:

  1. Questo metodo è robusto contro stranezze nei dati di input - esso non dipende avendo sempre alternati e sempre accoppiato, STRINGA ... StringB coppie, né assume che STRINGA si verificherà sempre prima di StringB. Ogni volta che incontra StringA inizierà l'eliminazione delle righe finché non incontra StringB.
  2. Sul lato negativo, l'utilizzo di questo metodo su frame di dati molto grandi potrebbe essere lento, in quanto stiamo aumentando un dataframe all'interno del ciclo (sempre garantito per rallentare grandi operazioni).

Il codice:

keep.line <- TRUE 
out.df <- data.frame() 

for (i in 1:NROW(my.df)) { 
    if (my.df[i,]$Column1 == "StringA") keep.line <- FALSE 
    if (keep.line) out.df <- rbind(out.df, my.df[i,]) 
    if (my.df[i,]$Column1 == "StringB") keep.line <- TRUE 
} 

out.df 
## Column1 Column2 
## unknownK 0.3679608 
## unknownR -0.8867749 
## unknownT 1.6277386 

Alcuni dati:

Column1 <-c( 
"StringA" ,  
"unknownC",  
"unknownD", 
"unknownS", 
"StringB" , 
"unknownK", 
"unknownR", 
"StringA" , 
"unknownU", 
"unknownP", 
"StringB" , 
"unknownT") 

my.df <- data.frame(Column1, Column2 = rnorm(12), stringsAsFactors = F) 
+0

Grazie mille, mi piace questo approccio ad anello. – SPZ

3

Utilizzando @ i dati di Psidom:

sel <- with(dat, 
    (cumsum(`Column 1`=="StringA") == cumsum(`Column 1`=="StringB")) 
    & 
    (!(`Column 1` %in% c("StringA","StringB"))) 
) 
dat[sel,] 

# Column 1 Column 2 
#6 unknownK  6 
#7 unknownR  1 
#12 unknownT  9 

Per fornire s oma spiegazione: utilizza cumsum per creare due contatori di quante volte sono stati visualizzati "StringA" e "StringB" in Column 1. Se i numeri corrispondono, significa che c'è stato 1 A e 1 corrispondente B.Come nei valori contrassegnati = sotto

cumsum(dat$`Column 1`=="StringA") 
#[1] 1 1 1 1 1 1 1 2 2 2 2 2 
cumsum(dat$`Column 1`=="StringB") 
#[1] 0 0 0 0 1 1 1 1 1 1 2 2 
#   = = =  = = 

Rimozione dei casi in cui è Column 1%in% uno degli obiettivi StringA/B corde finalizza esso.

+0

Questo sembra interessante, ma è difficile da seguire. Potresti annotare per spiegare come funziona. – dww

+1

@dww - aggiunta spiegazione / – thelatemail

Problemi correlati