Spaß mit Strings: stringr

In diesem Beitrag zeigen wir einige Möglichkeiten, wie man in R mit dem Paket stringR Strings und Texte bearbeitet und Informationen daraus extrahiert.

Dafür benötigen wir zunächst einen kleinen Text-Datensatz. Wir nutzen das Paket textdata,

um einen Test-Text zu haben.

# install.packages("textdata")
library(textdata)
catalogue

Interessant ist der Datensatz dataset_dbpedia, der Auszüge aus der gleichnamigen Webseite enthält. Wir nutzen nicht den ganzen Datensatz, sondern nur die ersten 10 Zeilen.

DBPedia <- dataset_dbpedia()
AuszugDBPedia <- DBPedia[1:10,]
AuszugDBPedia

Auszug des DBPedia-Datensatzes

Stringr nutzen

Suche von Mustern in Texten

In der Arbeit mit Strings werden häufig RegEx-Muster (reguläre Ausdrücke) genutzt. Diese Zeichenfolhen sind ewas gewöhungsbedürftig, aber wir versuchen hier einige einfache RegEx-Muster vorzustellen. Für eine Übersicht stehen im Internet verschiedene CheatSheets zur Verfügung. Im Zusammenhang mit stringr können wir das stingr Cheatsheet von RStudio empfehlen.


Wir haben 10 verschiedene Texte. Wir fragen uns, zum Beispiel, welche Unternehmen sich mit Stiften beschäftigen. Anders ausgedrückt: Wir interessieren uns, in welchem Text das Wort "pen" für Stift steht. Der reguläre Ausdruck ist von uns als " pen(s)? " gewählt. Wir suchen als nach allen Stellen, an denen ein Leerzeichen gefolgt von den Buchstaben pen oder pens gefolgt wiederum von einem Leerzeichen vorkommen. Der Bereich (s)? bedeutet dass ein s null oder einmal vorkommt.

Zur Suche können wir die Befehle `str_detect`, `str_which`, `str_count` und `str_locate` nutzen. Auch die Funktion `str_view` kann sehr hilfreich sein, denn sie zeigt die gefundenen Textstellen innerhalb des Textes an.

library(stringr)
# RegEx " pen(s)? " kann pen und pens zurückgeben
str_which(AuszugDBPedia$description, pattern = " pen(s)? ")



Aber ist das auch das was wir suchen? Finden wir es mit str_view_all() heraus:

str_view_all(AuszugDBPedia$description, pattern = " pen(s)? ")



Wunderbar, wir erkennen, dass innerhalb des Text-Ausschnitts nur bei dem Eintrag für Stabilo Stifte vorkommen.


Texte teilen

Im Bereich der Text-Analyse ist es hilfreich Strings in Substrings zerlegen zu können. Benötigt werden meistens einzelne Wörter, Buchstaben, Buchstabengruppen oder Sätze. Wir wollen hier den Auszug aus DBPedia in einzelne Sätze zerteilen.


Sätze können durch die Zeichen . ! und ? voneinander getrennt sein. Als regulärer Ausdruck dient nun "(\\.|\\!|\\?) +". Das heißt, dass wir nach einem der Zeichen . oder ! oder ? suchen. Das Zeichen wird von einem oder keinem Leerzeichen gefolgt.


Schauen wir, ob unsere Idee funktioniert mittels str_view:

str_view_all(AuszugDBPedia$description, pattern = "(\\.|\\!|\\?) +")
Ansicht der gefundenen Satzenden

Perfekt, dass scheint zu funktionieren. Nun trennen wir die Sätze.

str_split(string = AuszugDBPedia$description, pattern = "(\\.|\\!|\\?) +")
Trennen der Strings mit Entfernen der Punktuation

Nun haben wir eine Liste erhalten, die die einzelnen Sätze enthält. Aber wir haben die

Satztrennzeichen entfernt. Dazu gibt es jedoch einen Work-Around: `Look Arounds`innerhalb der RegEx-Muster

str_split(string = AuszugDBPedia$description, pattern = "(?<=(\\.|\\!|\\?)) +")
Trennen der Strings - Punktuation beibehalten

Wunderbar, nun haben wir die Sätze getrennt und die Satztrennzeichen erhalten.


Leerzeichen und anderen Whitespace entfernen


Arbeitet man mit Texten aus verschiednen Dateiformaten und Quellen, so hat man teilweise viele Leerzeichen

im Text. stringr hat dafür das passende Werkzeug: `str_trim` und `str_squish`


Zunächst erzeugen wir uns einen Beispieltext:

# Helge Schneider Katzeklo :)
LovelyWhitespace <- "   	Katzenklo, Katzenklo-ja das macht die Katze froh,   
    		Katzenklo, Katzenklo macht die Katze froh.	
  Willst du eine saubere Katze haben,  
	Musst du im Geschäft nach Katzenklo fragen.
  Katzenklo, Katzenklo-ja das macht die Katze froh,
      Katzenklo, Katzenklo macht die Katze froh.
                          Katzenklo, Katzenklo-ja das macht die Katze froh,
     Katzenklo, Katzenklo macht die Katze froh. 
 Gehst du ins Geschäft hinein,		
Kauf was Schönes für die Katze ein. 	"

Whitespace ist ziemlich störend. Man kann es auch durch einen str_replace_all() aufruf entfernen. Etwa alle Leezeichen mit dem regulären Ausdruck `[[:space:]]`.

str_replace_all(LovelyWhitespace, pattern = "[[:blank:]]+", replacement = " ")
Ersetzen des Whitespace mittels str_replace

Mit `str_trim` und `str_squish`geht das noch einfacher:

# Whitespace am Anfang und Ende entfernen
str_trim(LovelyWhitespace)
Ersetzen des Whitespace an Text-Ende und -Anfang mittels str_replace

Nun testen wir noch str_squish:

# Alle überflüssigen Whitespace-Zeichen und Zeilenumbrüche entfernen
str_squish(LovelyWhitespace)
Ersetzen des Whitespace mittels str_squish

Zum Schluss noch etwas Spaß beim Dechiffrieren

James Veitch ist ein Britischer Stand-Up-Comedian, der unter anderem sehr viele

Spam-Mails beantwortet hat. In einer Spam-Korrenspondenz fordert er einen Geheim-Code im Text zu verwenden.

Der Spam-Sender verwendet diesen. Wir werden den Text zurückübersetzen:

JamesVeitchLostInTranslation <- "The business is on. I am trying to raise the balance for the gummy bear so he can submit all the needed fizzy cola bottle jelly beans to the cream egg for the peanut M&Ms process to start. Send 1500 Pounds via a giant gummy lizard."
JamesVeitchLostInTranslation

# Wir schreiben sicherheitshalber alles groß, damit auch keine falschen Muster erkannt werden:
JamesVeitchLostInTranslation <- str_to_upper(JamesVeitchLostInTranslation)

JamesVeitchLostInTranslation
# 1. Gummy bear = lawyer
JamesVeitchTranslated <- str_replace_all(JamesVeitchLostInTranslation, pattern = "GUMMY BEAR", replacement = "LAWYER")

JamesVeitchTranslated
str_view_all(string = JamesVeitchTranslated, pattern = "LAWYER")
Decodieren eines einzelnen Wortpaares

Nun automatisieren wir das Entschlüsseln des gesamten Textes

## Automatisieren
NamenDict <- str_to_upper(c("lawyer", "bank", "legal", "claim", "documents", "Western Union"))
Dict <- str_to_upper(c("gummy bear", "cream egg", "fizzy cola bottle", "peanut M&Ms","jelly beans", "a giant gummy lizard"))

names(Dict) <- NamenDict
JamesVeitchTranslated <- JamesVeitchLostInTranslation

for(i in 1:length(Dict)){
  # print(Dict[i])
  # print(names(Dict[i]))
  
  JamesVeitchTranslated <- str_replace_all(JamesVeitchTranslated, pattern = as.character(Dict[i]), replacement = as.character(names(Dict[i])))
}

JamesVeitchLostInTranslation
JamesVeitchTranslated

# Text wieder mit korrekter Groß-/Kleinschreibung darstellen
str_to_sentence(JamesVeitchTranslated)
Decodieren mittels Wörterbuch-Ansatz

Fazit

Mit Texten zu arbeiten heißt auch mit regulären Ausdrücken umzugehen, um Textelemente zu extrahieren oder zu ersetzen. Das Paket stringr kann genau bei diesen Aufgaben helfen. Besonders interessant ist die Funktion `str_view_all`, denn sie visualisiert die gefundenen Elemente im Text. Auch `str_squish` ist hilfreich, denn es entfernt überflüssiges Whitespace aus dem Datensatz. Viel Spaß beim Ausprobieren.