2016-05-27 13 views
6

Ich versuche, Zeilenfolgen aus einem Datenrahmen zu löschen, die Sequenz beginnt mit einer bekannten Zeichenfolge und endet mit einer bekannten Zeichenfolge, aber die Inhalt und Anzahl der dazwischenliegenden Zeilen ist unbekannt. Ich möchte dies über den gesamten Datenrahmen iterieren.R For loop delete Bereich von Zeilen von einer Zeichenfolge zu einer zweiten Zeichenfolge in einer Spalte

Zum Beispiel, wenn der Datenrahmen wie unten ist, würde Ich mag die Zeilen aus allen Instanzen Stringa zu stringB (einschließlich) zu entfernen, aber die Zeilen behalten, die stringB bis zur nächsten Wiederholung von Stringa folgen; Im folgenden Beispiel möchte ich die Zeilen entfernen, die StringA, unknownC, unknownD, unknownS, StringB enthalten, aber unknownK und unknownR behalten und dann mit StringA, unknownU, unknownP, StringB weiter löschen, aber unknownT behalten.

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 

Ich versuchte df2 <- df[1:which(df[,1]=="StringA")-1,], was nicht korrekt ist, aber bin ratlos wie das, was anderer Ansatz zu versuchen. Vielen Dank im Voraus für jede Anleitung.

+2

Ist sicher bekannt, dass stringA immer mit einem nachfolgenden stringB gepaart ist? Ist auch bekannt, dass sich die Saiten A und B immer abwechseln (z. B. Never A ... A ... B)? – dww

+0

Ja, ist es. Es wird immer A ... B sein und niemals A..A ... B – SPZ

Antwort

5

Sie können so etwas wie dies versuchen, indem der Index entfernt werden Konstruieren mit der Map Funktion:

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 

Daten:

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 Ich mag die Idee dieser Strategie Psidom, aber ich bin nicht sicher, wie ich diese Warnung vermeiden kann, die ich erhielt, als ich den ersten Schritt testete : In Mapply (FUN = f, ..., SIMPLIFY = FALSCH): länger Argument nicht ein Vielfaches der Länge kürzer – SPZ

+0

Spot für mich. Bravo –

+0

Nicht genau sicher, aber wenn Ihre Spalte etwas wie "A ... B ... A ..." oder "B ... A ... B .." ist, könnte dies passieren. – Psidom

3

Sie können eine for Schleife verwenden. Obwohl dies langsamer als die veröffentlichten vektorisierten Lösungen ist, hat es einige Vorzüge, da es sehr vielseitig ist, um sich an ähnliche verwandte Probleme anzupassen, und robust gegenüber unerwarteten Eingabedaten ist.

Hinweise:

  1. Diese Methode ist robust gegen Merkwürdigkeiten in den Eingangsdatum - es hängt nicht immer mit abwechselnden und immer gepaart, Stringa ... stringB Paare, noch nicht davon ausgehen, dass Stringa wird immer vor StringB auftreten. Jedes Mal, wenn es auf StringA trifft, beginnt es, Zeilen zu löschen, bis es StringB trifft.
  2. Auf der anderen Seite könnte die Verwendung dieser Methode für sehr große Datenrahmen langsam sein, da wir einen Datenrahmen innerhalb der Schleife wachsen (immer garantiert, um große Operationen zu verlangsamen).

Der Code:

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 

Einige Daten:

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

Vielen Dank, ich mag diesen Ansatz. – SPZ

3

Mit @ Psidom Daten:

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 

s Um ome Erklärung - dies verwendet cumsum, um zwei Zähler zu machen, wie oft "StringA" und "StringB" in Column 1 erschienen sind. Wenn die Zahlen übereinstimmen, bedeutet das, dass 1 A und 1 entsprechende B ist.Wie in den Werten markiert = unter

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 
#   = = =  = = 

die Fälle, in denen Entfernen Column 1%in% eines der Ziel ist StringA/B Strings es finalisiert.

+0

Das sieht interessant aus, ist aber schwer zu folgen. Könnten Sie es kommentieren, um zu erklären, wie das funktioniert? – dww

+1

@dww - zusätzliche Erklärung / – thelatemail