2017-02-22 3 views
0

Ich habe eine Liste von Strings (sehr groß, Millionen von Zeilen), aus denen ich bestimmte Teile extrahieren möchte.R: Teil der Zeichenfolge mit unterschiedlicher Länge extrahieren

Ich spalte zuerst die Zeichenkette am Semikolon und extrahiere dann zu spezifischen Abschnitten. Es ist ein wenig komplizierter, da es manchmal 3, manchmal 4 Segmente in einer Reihe gibt. Aber die Teile, die mich interessieren, sind immer das letzte und vorletzte Segment.

Beispielcode:

dataStr = c("secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2") 

splStr <- strsplit(dataStr, ";") 
extr1 <- list() 
extr2 <- list() 

for (i in 1:length(splStr)) { 
    extr1[i] <- head(tail(splStr[[i]], n=2), n=1) 
    extr2[i] <- tail(splStr[[i]], n = 1) 
} 

Es funktioniert, aber es ist viel zu langsam. Ich wäre dankbar für jede Idee, wie man das schneller machen kann. Ich vermute, dass dies mit apply gemacht werden könnte, aber ich konnte meinen Kopf nicht darum wickeln.


Die Frage aufgeworfen wurde, ob es sich um eine doppelte Frage zu this Frage sein könnte. Ich denke, es ist ein bisschen anders, da ich die letzten beiden Elemente extrahieren möchte und die Anzahl der Abschnitte unterschiedlich ist. Auch habe ich nicht die Lösung mit vapply bekommen, um an meiner realen Probe zu arbeiten.

+0

Mögliche Duplikat von [Wie in R letzte Teilelement jedes Element einer Liste bekommen] (http://stackoverflow.com/questions/36143119/how-to-get-last-subelement-of-every -element-of-a-list-in-r) –

Antwort

3

Ich glaube, Sie sind besser dran mit nur regexp hier mit:

sub(".+; (.+?); (.+?)$", "\\2", dataStr) 

Das wird das letzte Element greifen.

sub(".+; (.+?); (.+?)$", "\\1", dataStr) 

Das wird den Artikel vor dem letzten Artikel greifen.

+0

Verbesserte Geschwindigkeit um einen Faktor von 27 auf meiner realen Probe. –

0

Es kann schneller sein zu tun:

str_list <- lapply(splStr, tail, 2) 
do.call(rbind, str_list) 

     [,1]   [,2]  
[1,] " secExtr1" " secExtr2" 
[2,] " secExtr1" " secExtr2" 
[3,] " secExtr1" " secExtr2" 
[4,] " secExtr1" " secExtr2" 
[5,] " secExtr1" " secExtr2" 
[6,] " secExtr1" " secExtr2" 
[7,] " secExtr1" " secExtr2" 
[8,] " secExtr1" " secExtr2" 
[9,] " secExtr1" " secExtr2" 
[10,] " secExtr1" " secExtr2" 
+0

Nun, es ist das gleiche. SplStr ist der Split DataStr. – JohannesNE

+0

Die Regex-Methode ist tatsächlich schneller (zumindest in diesem Beispiel festgelegt). – JohannesNE

1

Wir können stringi verwenden diese schneller mit vapply

library(stringi) 
vapply(stri_split(dataStr, regex=';\\s*'), function(x) tail(x, 2), character(2)) 
+0

Dies funktioniert an dem Beispiel hier, scheitert aber an meinem realen Beispiel: 'Fehler in vapply (splStr, Funktion (x) Schwanz (x, 2), Zeichen (2)): Werte müssen Länge 2, aber FUN sein (X [[5487]]) Ergebnis ist Länge 1' –

+0

@ ulima2_ Es ist nicht klar, wenn Sie weniger als 2 Fälle haben, was zu tun ist – akrun

2

Die word von stringr Lösung zusammen zu machen,

stringr::word(dataStr, -2, -1, sep = ';') 

Sie kann dann strsplit, um sie als zwei verschiedene Wörter zu erhalten, das heißt

do.call(rbind, strsplit(trimws(word(dataStr, -2, -1, sep = ';')), '; ')) 
#  [,1]  [,2]  
# [1,] "secExtr1" "secExtr2" 
# [2,] "secExtr1" "secExtr2" 
# [3,] "secExtr1" "secExtr2" 
# [4,] "secExtr1" "secExtr2" 
# [5,] "secExtr1" "secExtr2" 
# [6,] "secExtr1" "secExtr2" 
# [7,] "secExtr1" "secExtr2" 
# [8,] "secExtr1" "secExtr2" 
# [9,] "secExtr1" "secExtr2" 
#[10,] "secExtr1" "secExtr2" 
+0

Ich denke, das ist nicht die Aufgabe: Beide Abschnitte sind immer noch zusammen in der gleiche Zelle. –

+0

Bearbeitet. Ich habe auch "Trimws" verwendet, um führende/nachstehende Leerzeichen zu entfernen – Sotos

+0

Großartig, funktioniert jetzt - danke! Die Regex-Lösung ist jedoch wesentlich schneller. –

0
> str_list <- lapply(dataStr, tail, 2) 

> do.call(rbind, str_list) 


     [,1]           
[1,] "secAlways; secExtr1; secExtr2"    
[2,] "secSometimes; secAlways; secExtr1; secExtr2" 
[3,] "secSometimes; secAlways; secExtr1; secExtr2" 
[4,] "secAlways; secExtr1; secExtr2"    
[5,] "secAlways; secExtr1; secExtr2"    
[6,] "secAlways; secExtr1; secExtr2"    
[7,] "secSometimes; secAlways; secExtr1; secExtr2" 
[8,] "secAlways; secExtr1; secExtr2"    
[9,] "secAlways; secExtr1; secExtr2"    
[10,] "secAlways; secExtr1; secExtr2" 

Ich bin nicht sicher, dass dies funktioniert?

0

Unter der Annahme, dass die letzten und vorletzten Segmente immer die gleiche Anzahl an Zeichen haben, kann dies mit der Bibliothek stringi folgendermaßen erreicht werden.

Ich habe auch angenommen, dass Sie zwei Listen als Ausgabe möchten.

library(stringi) 

dataStr = c("secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secSometimes; secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2", 
      "secAlways; secExtr1; secExtr2") 

extr1 <- as.list(stringi::stri_sub(dataStr, from=-18, to=-11)) 
extr2 <- as.list(stringi::stri_sub(dataStr, from= -8)) 
+0

Leider sind sie nicht die gleiche Anzahl von Fällen für mich, sorry für das irreführende Beispiel hier. –

Verwandte Themen