RegExp-Kurs: R (stringr)

Vom einfachen Programm zum fertigen Debian-Paket, Fragen rund um Programmiersprachen, Scripting und Lizenzierung.
Antworten
Benutzeravatar
tegula
Beiträge: 439
Registriert: 04.06.2004 13:51:04
Lizenz eigener Beiträge: MIT Lizenz

RegExp-Kurs: R (stringr)

Beitrag von tegula » 08.07.2022 15:45:08

Kursübersicht

In diesem Thread geht es um die Anwendung von regulären Ausdrücken in R mittels des Packages (der Bibliothek) stringr.
https://de.wikipedia.org/wiki/R_(Programmiersprache) hat geschrieben:R ist eine freie Programmiersprache für statistische Berechnungen und Grafiken. Sie wurde 1992 von Statistikern für Anwender mit statistischen Aufgaben neu entwickelt. Die Syntax orientiert sich an der Programmiersprache S, mit der R weitgehend kompatibel ist, und die Semantik an Scheme. Als Standarddistribution wird R mit einem Interpreter als Kommandozeilenumgebung mit reduzierten grafischen Schaltflächen angeboten. So ist R aktuell auf den wichtigsten Plattformen verfügbar; die Umgebung wird von den Entwicklern ausdrücklich ebenfalls als R bezeichnet. R ist Teil des GNU-Projekts.
https://stringr.tidyverse.org/ hat geschrieben: The stringr package provide[­s] a cohesive set of functions designed to make working with strings as easy as possible. [...] stringr is built on top of stringi, which uses the ICU C library to provide fast, correct implementations of common string manipulations. stringr focusses on the most important and commonly used string manipulation functions whereas stringi provides a comprehensive set covering almost anything you can imagine.
Stringr stellt eine benutzerfreundliche Möglichkeit dar, reguläre Ausdrücke innerhalb von R zu verwenden. Der hierbei genutzte RE-Dialekt nennt sich "ICU" oder "Java-ähnlich". ERE-Ausdrücke, die wir während des Grundlagen-Kurses von Meillo gelernt haben, können (nach Anpassung der Escapezeichen (vgl. Kapitel 2, Unterabschnitt "Escaping") und der vordefinierten Zeichenklasse (vgl. Kapitel 4)) in der Regel ohne Probleme übernommen werden :).

1.) Installation
R und die für den Kursteil benötigten R-Packages sind in den offiziellen Debian-Quellen verfügbar. Benötigt werden Debianr-recommended und Debianr-cran-tidyverse.

Optional: Für diesen Kurs-Part ist ein beliebiger Texteditor ausreichend. Eine integrierte Entwicklungsumgebung macht die Benutzung von R aber bequemer und einfacher. Eine Übersicht findet sich im Archwiki (https://wiki.archlinux.org/title/R#Edit ... _R_support) oder auf Wikipedia (https://en.wikipedia.org/wiki/R_(progra ... Interfaces).

2.) Hilfreiches Vorwissen
Wenn ihr schon einmal R genutzt habt, könnt ihr diesen Abschnitt überspringen.
Zuweisungsoperator: Im Unterschied zu Python, gibt es in R zwei Möglichkeiten eine Zuweisung auszudrücken. "<-" und "=". Für die Zuweisung eines Wertes an ein Objekt sind beide Schreibweisen möglich. Für die Übergabe eines Schlüsselwortarguments an eine Funktion oder eine Methode ist hingegen (wie in Python) ausschließlich die Schreibweise "=" erlaubt.

Code: Alles auswählen

data(trees)
# Zuweisung von Werten an Objekte: Sowohl "<-" als auch "=" sind erlaubt.
volumen_kubikzoll = trees$Volume
volumen_kubikzoll <- trees$Volume 
# Übergabe von Schlüsselwortargumenten an Funktionen: Ausschließlich "=" ist erlaubt.
summary(object = volumen_kubikzoll, digit = 4)
Pipe-Operator: Im weiteren Verlauf dieser Einführung wird häufig der Pipe-Operator %>% verwendet. Der Pipe-Operator ermöglicht es zwei Funktionen miteinander zu verknüpfen. Das heißt die zweite Funktion verwendet den Rückgabewert der ersten Funktion als (ootb: erstes positionales) Argument. Der Pipe-Operator stellt damit eine IMHO flexiblere und übersichtlichere Alternative zu Klammern da. Um den Pipe-Operator verwenden zu können, ist es allerdings erforderlich, zuvor entweder das Package magrittr oder Meta-Package tidyverse zu laden.

Code: Alles auswählen

library(magrittr)
data(mtcars)

# Folgendes wird gemacht: Die Antriebsleistung der Autos wird von Pferdestärken (Pferdestärken) in Kilowatt (kW) umgerechnet. Anschließen werden das (als Zahl vorliegende) Ergebnis in eine Zeichenkette umwandelt. Zum Schluss wird die Angabe der Einheit ("kW") zu dieser  Zeichenkette hinzufügt.

## Variante 1: Mit Klammern (ohne Pipe-Operator) --> IMHO eher unübersichtlich
paste((as.character(multiply_by(mtcars$hp, 0.746))), "kW", sep = " ")
## Variante 2: Mit Pipe-Operator (in einer Zeile) --> IMHO schon übersichtlicher
mtcars$hp %>% multiply_by(0.746) %>% as.character() %>% paste("kW", sep = " ")
## Variante 3: Mit Pipe-Operator (in mehren Zeilen --> IMHO noch mal  übersichtlicher
mtcars$hp %>%
  multiply_by(0.746) %>%
  as.character() %>%
  paste("kW", sep = " ")
Weitergehende Infos zum Pipe-Operator (für das Verständnis bzw. die Bearbeitung dieses Kurs-Parts nicht notwendig): https://magrittr.tidyverse.org

Escaping: Als Escapezeichen dient der Backslash. Eine Besonderheit ist jedoch, dass grundsätzlich doppelt escapet werden muss, um aus einen Standardzeichen ein Metazeichen zu machen. De facto dient also ein doppelter Backslash als Escape-Zeichen.

Code: Alles auswählen

library(tidyverse)
# TODO: Es soll nur die Schreibweise mit zwei getrennten Wörter ("hallo debianforum") gefunden werden.
## richtig:
"hallo_debianforum hallo debianforum" %>%
  str_extract_all(pattern = "hallo\\b.debianforum")
## falsch:
"hallo_debianforum hallo debianforum" %>% 
  str_extract_all(pattern = "hallo\b.debianforum")
Weitergehende Infos zur Thematik: https://github.com/rstudio/cheatsheets/ ... trings.pdf (Seite 2, linke Spalte "Need to Know").

3.) Vorbereitung

Arbeitsverzeichnis festlegen, Script-Datei erstellen und Schwäbische Kunde downloaden: Erstellt ein Verzeichnis (z. B. ~/regex_R) für diesen Kurs-Part und speichert dort eine leere Textdatei mit der Dateinamensendung ".R" (z. B. skript_regex.R) sowie die Schwäbische_Kunde (NoPaste-Eintrag41651). Öffnet nun das R-Skript und fügt folgenden Befehl ein, um das Arbeitsverzeichnis festzulegen.

Code: Alles auswählen

#!/usr/bin/env Rscript #optional
setwd("~/regex_R") # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)
getwd()          # Arbeitsverzeichnis anzeigen
print("Das ist ein Test") # Zeichenkette "Das ist ein Test" ausgeben

Skript ausführen (ohne Entwicklungsumgebung):
(Wenn ihr eine Entwicklungsumgebung (statt Texteditor und Terminal) zum Ausführen der Befehle bzw. eures Skripts nutzt und/oder schon einmal R benutzt habt, könnt ihr diesen Unterabschnitt überspringen.)
Öffnet ein Terminal, wechselt in eurer Arbeitsverzeichnis und übergebt das Script an das Programm Rscript. Daraufhin wird das Skript ausgeführt.

Code: Alles auswählen

cd ~/regex_R # Pfad zum Arbeitsverzeichnis ggf. anpassen
Rscript skript_regex.R # Pfad ggf. anpassen

Schwäbische Kunde importieren und für spätere Verwendung abspeichern: Zum Importieren der Schwäbischen Kunde benutzen wir die Funktion read_lines aus dem Package readr. Das Ergebnis des Imports speichern wir unter dem Dateinamen "schwaebische_kunde.RData" ab, um es später wiederverwenden zu können.

Code: Alles auswählen

# Importieren
schwaebische_kunde <- readr::read_lines("schwaebische-kunde.txt") %>%
  dplyr::as_tibble() %>%
  dplyr::rename(text = value) %>%
  tibble::rowid_to_column("zeile")
# abspeichern
save(schwaebische_kunde, file = "schwaebische_kunde.RData")
4.) Übersicht über die in stringr möglichen regulären Ausdrucke
Eine tabellarische Übersicht der innerhalb von stringr zur Verfügung stehenden Operationen und Zeichenklassen bietet die zweite Seite des Cheat-Sheets "strings" von Rstudio: https://github.com/rstudio/cheatsheets/ ... trings.pdf. Eine Übersicht als Fließtext liefert die Vignette "regular expressions": https://cloud.r-project.org/web/package ... sions.html. Ein auffälliger Unterschied zu egrep (ERE) besteht darin, dass auch vordefinierte Zeichenklassen nur in einfache (statt doppelte) eckige Klammern gesetzt werden.

Code: Alles auswählen

library(tidyverse)
# Nur Elemente der vordefinierten Zeichenklasse "[:digit:]" (Zahlen) extrahieren
"Die folgende Zahl lautet 9 (in Worten: Neun)." %>%
  str_extract_all(pattern = "[:digit:]")
5.)Regex-Funktionen im Package stringr
Ein Überblick über die in stringr enthaltenen regex-Funktionen ist zum Beispiel in der Vignette "Introduction to stringr" zu finden: https://stringr.tidyverse.org/articles ... n-matching zu finden. Eine ausführliche Beschreibung findet sich in der Befehlreferenz des stringr-Packages: https://cloud.r-project.org/web/package ... tringr.pdf.

Feststellen, ob ein Match vorliegt: str_detect

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen:
## Zeile soll ein Komma enthalten.
schwaebische_kunde$is_match <- schwaebische_kunde$text %>%
  str_detect(pattern = ",")
# Ergebnis ausgeben
schwaebische_kunde %>%
  print(n = Inf)

Feststellen eines Matches am Beginn bzw. Ende einer Zeichenfolge: str_starts und str_ends
Soll nur der Beginn bzw. Ende einer Zeichenfolge betrachtet werden, so bietet sich die Nutzung der Funktionen str_starts bzw. str_ends an. Die Angabe der Zeilenanker ^ und $ kann bei der Verwendung dieser Funktionen entfallen.

Code: Alles auswählen

input_string <- "debianforum.de"
 
# Match am Anfang einer Zeichenfolge feststellen
input_string %>% str_starts(pattern = "[dD]") # entspricht ...
input_string %>% str_detect(pattern = "^[dD]")
 
# Match am Ende einer Zeichenfolge feststellen
input_string %>% str_ends(pattern = "de") # entspricht ...
input_string %>% str_detect(pattern = "de$")

Anzahl der Matches bestimmen: str_count

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## Vorkommen des Buchstabens e bzw. E in der jeweiligen Zeichenfolge (hier: Strophe der Schwäbischen Kunde)
schwaebische_kunde$n_matches <- schwaebische_kunde$text %>%
  str_count(pattern = "[eE]")
# Ergebnis anzeigen
schwaebische_kunde %>%
  print(n = Inf)

Position des ersten Matches bestimmen: str_locate

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## erstes auftreten des Buchstaben A bzw. a
schwaebische_kunde$position <-  schwaebische_kunde$text %>%
  str_locate(pattern = "[aA]")
# Ergebnis anzeigen
schwaebische_kunde %>%
  print (n = Inf)

Position aller matches bestimmen: str_locate_all

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## (jedes) Auftreten von A bzw. a
str_locate_all(string = schwaebische_kunde$text,
               pattern = "[Aa]")

Erstes Match extrahieren: str_extract

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## (erstes) Auftreten von A bzw. A
schwaebische_kunde$first_match <- schwaebische_kunde$text %>%
  str_extract(pattern = "[aA]")
# Ergebnis anzeigen
schwaebische_kunde %>%
  print (n = Inf)

Alle Matches extrahieren: str_extract_all

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## (jedes) auftreten von A bzw. a
schwaebische_kunde$text %>%
  str_extract_all(pattern = "[aA]")

Gruppen extrahieren (nur erstes match): str_match

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## Extrahiere das Wort vor dem ersten Komma oder Punkt
schwaebische_kunde$text %>%
  str_match(pattern = "([:alnum:]*)[:blank:]*[.,].*")

Gruppen extrahieren (alle matches): str_match_all

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen
## Extrahiere alle Kleinbuchstaben, die auf einen Großbuchstaben folgen
schwaebische_kunde$text %>%
  str_match_all("[:upper:]([:lower:])"

(Komplette) Zeichenkette zurückgeben, wenn mindestens ein Match enthalten ist: str_subset

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen:
## Zeichenfolgen (Zeilen), die ein Komma enthalten
schwaebische_kunde$text %>% str_subset(pattern = ",")

Ersetzen (nur erstes Match ersetzen): str_replace

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen:
## Ersetze das erste Auftreten von "ae" durch "ä"
schwaebische_kunde$text <- schwaebische_kunde$text %>%
  str_replace(pattern = "ae",
              replacement = "ä")
# Ergebnis ausgeben
schwaebische_kunde %>%
  print(n = Inf)

Ersetzten (alle Matches ersetzen): str_replace_all

Code: Alles auswählen

# Tidyverse laden
library(tidyverse)
# Schwäbische Kunde laden
load("schwaebische_kunde.RData")
# Regex-Funktion ausführen:
## Ersetze alle Leerzeichen durch Unterstriche
schwaebische_kunde$text <- schwaebische_kunde$text %>%
  str_replace_all(pattern = "[:space:]",
                  replacement = "_")
# Ergebnis anzeigen
schwaebische_kunde %>%
  print(n = Inf)

Aufgaben

1. Bestimme, wie viele Buchstaben die URL des dfde-Unterforums "Softwareentwicklung und -paketierung, Scripting" (viewforum.php?f=34) enthält. Zähle einmal mit und einmal ohne die Angabe des Protokolls ("https").

2. Bestimme, wie viele Verse (Zeilen) der Schwäbischen Kunde mit einem Vokal (Selbstlaut) beginnen.

3. Mehrere Einwohner von Neu New York wurden nach ihrer Lieblingsfarbe gefragt. Das Ergebnis findest du im NoPaste: NoPaste-Eintrag41775 (Hinweis: Laden erfolgt mit dem R-Befehl load("umfrage.RData")). Ordne ihren Antworten mithilfe regulärer Ausdrücke den folgenden Kategorien zu "Rot", "Blau", "Grün", "Andere Farbe" und NA (fehlender Wert).

4.) Extrahiere aus der Schwäbischen Kunde alle Großbuchstaben. Formatiere die Ausgabe so, dass getrennt nach Versen (Zeilen) folgende Informationen möglichst übersichtlich angezeigt werden: die Zeilennummer des Verses, der gesamte Text des Verses sowie alle Großbuchstaben, die in diesem Vers enthalten sind. Du bist frei in der Wahl des Ausgabemediums (z. B. R-Konsole, Standardausgabe, Spreadsheet-Datei oder ähnliches).

5.) Denke dir selbst eine Aufgabe für die anderen Teilnehmer dieses Kursteils aus.

6.) Löse die Aufgaben der anderen Teilnehmer.

Bitte postet eure Lösungen zu den Aufgaben 1-5 frühestens ab Mittwoch (13. Juli). Bitte denkt als Aufgabenersteller bei Aufgabe 6 daran, anzugeben, ab wann Lösungen zu eurer Aufgabe frühestens gepostet werden sollen :).

-------------
-------------
EDIT (12.07.2022): Korrektur eines Fehlers (fehlendes Quoting des (R-)Arbeitsverzeichnisses). Danke Huo! :THX:
Zuletzt geändert von tegula am 12.07.2022 11:56:14, insgesamt 3-mal geändert.

Huo
Beiträge: 614
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs: R (stringr)

Beitrag von Huo » 11.07.2022 13:10:03

Hallo tegula,

danke für die schöne Kurseinheit! Ich habe die letzten Tage mal ein bisschen in R hineingeschnuppert und will versuchen, wenigstens die ersten beiden Aufgaben zu bearbeiten. Allerdings empfinde ich als R-Neuling einige Befehle im Zusammenhang mit der Bibliothek Tidyverse und den Pipes als etwas kryptisch und umständlich, auch wenn sie natürlich funktionieren.

Spricht etwas dagegen, wenn ich für mich persönlich auf Tidyverse verzichte und stattdessen kurz und knackig wie folgt vorgehe?

Code: Alles auswählen

> schwaebische_kunde.RData <- readLines("schwaebische-kunde.txt")
> save(schwaebische_kunde, file = "schwaebische_kunde.RData")

Code: Alles auswählen

> library(stringr)
> load("schwaebische_kunde.RData")
> m = str_detect(schwaebische_kunde, ",")
> print(m)

Benutzeravatar
tegula
Beiträge: 439
Registriert: 04.06.2004 13:51:04
Lizenz eigener Beiträge: MIT Lizenz

Re: RegExp-Kurs: R (stringr)

Beitrag von tegula » 11.07.2022 18:17:23

Huo hat geschrieben: ↑ zum Beitrag ↑
11.07.2022 13:10:03
Hallo tegula,

danke für die schöne Kurseinheit! Ich habe die letzten Tage mal ein bisschen in R hineingeschnuppert und will versuchen, wenigstens die ersten beiden Aufgaben zu bearbeiten.
Cool, das freut mich! :THX:
Huo hat geschrieben: ↑ zum Beitrag ↑
11.07.2022 13:10:03
Spricht etwas dagegen, wenn ich für mich persönlich auf Tidyverse verzichte und stattdessen kurz und knackig wie folgt vorgehe?
Nein, natürlich spricht nichts dagegen, auf den Pipe-Operator und die Tidyverse-Packages (mit Ausnahme von stringr selbst ;)) zu verzichten. Mach's so, wie es für dich am besten passt :).
Huo hat geschrieben: ↑ zum Beitrag ↑
11.07.2022 13:10:03

Code: Alles auswählen

> schwaebische_kunde.RData <- readLines("schwaebische-kunde.txt")
> save(schwaebische_kunde, file = "schwaebische_kunde.RData")
Diese Befehlsfolge funktioniert so bei mir nicht, weil das Objekt schwaebische_kunde (also jenes Objekt, welches der Befehl save abspeichern soll) unter diesem Namen nicht vorhanden ist.

Code: Alles auswählen

> # Funktioniert nicht: save-Befehl soll "schwaebische_kunde" laden, aber im Workspace
> # liegt das Objekt unter einem anderen Namen ("schwaebische_kunde.RData").
> schwaebische_kunde.RData <- readLines("schwaebische-kunde.txt")
> save(schwaebische_kunde, file = "schwaebische_kunde.RData")
Error in save(schwaebische_kunde, file = "schwaebische_kunde.RData") : 
  Objekt ‘schwaebische_kunde’ nicht gefunden
> # So funktionierts ...
> schwaebische_kunde <- readLines("schwaebische-kunde.txt")
> save(schwaebische_kunde, file = "schwaebische_kunde.RData")
> 

Huo
Beiträge: 614
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs: R (stringr)

Beitrag von Huo » 12.07.2022 10:00:27

tegula hat geschrieben: ↑ zum Beitrag ↑
11.07.2022 18:17:23
Diese Befehlsfolge funktioniert so bei mir nicht, weil das Objekt schwaebische_kunde (also jenes Objekt, welches der Befehl save abspeichern soll) unter diesem Namen nicht vorhanden ist.
Danke für die Richtigstellung. Ich hatte beim Experimentieren die Zuweisung u.a. auch korrekt ausgeführt, beim Posten aber die falsche Zeile aus meinem Terminal kopiert ... :cry:

Etwas anderes aus Deinem Tutorial funktioniert allerdings so, wie von Dir angegeben, bei mir nicht:

Code: Alles auswählen

setwd(~/regex_R) # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)
Beim Ausführen des Programms erhalte ich:

Code: Alles auswählen

Fehler: Unerwartete(s) '/' in "setwd(~/"
Es klappt aber, wenn ich den Pfad in Anführungszeichen setze:

Code: Alles auswählen

setwd("~/regex_R")

Benutzeravatar
tegula
Beiträge: 439
Registriert: 04.06.2004 13:51:04
Lizenz eigener Beiträge: MIT Lizenz

Re: RegExp-Kurs: R (stringr)

Beitrag von tegula » 12.07.2022 11:12:02

Huo hat geschrieben: ↑ zum Beitrag ↑
12.07.2022 10:00:27
Etwas anderes aus Deinem Tutorial funktioniert allerdings so, wie von Dir angegeben, bei mir nicht:

Code: Alles auswählen

setwd(~/regex_R) # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)
Beim Ausführen des Programms erhalte ich:

Code: Alles auswählen

Fehler: Unerwartete(s) '/' in "setwd(~/"
Es klappt aber, wenn ich den Pfad in Anführungszeichen setze:

Code: Alles auswählen

setwd("~/regex_R")
Sorry :oops: Vielen Dank, dass du so aufmerksam bist! Hab es jetzt korrigiert.

Hintergrund meines Fehlers: Ich hab das Tutorial in einem anderen Verzeichnis (auf einem Wechseldatenträger und zwei unterschiedlichen Computern) erstellt und und das Verzeichnis jeweils über die grafische Oberfläche von Rstudio zum (R-)Arbeitsverzeichnis gemacht. Dementsprechend hatte ich den Codeblock im (RMarkdown-)Entwurf des Tutorials von Anfang an auf eval=FALSE (das heißt: nicht ausführen) gestellt und mein Fehler ist mir dadurch gar nicht aufgefallen :oops:

Code: Alles auswählen

 ## Arbeitsverzeichnis festlegen, Script-Datei erstellen und Schwäbische Kunde downloaden:
Erstellt ein Verzeichnis (z. B. ~/regex_R) für diesen Kurs-Part und speichert dort eine leere Textdatei mit der Dateinamensendung ".R" (z. B. skript_regex.R) sowie die Schwäbische_Kunde (<https://nopaste.debianforum.de/41651>). Öffnet nun das R-Skript und fügt folgenden Befehl ein, um das Arbeitsverzeichnis festzulegen.
```{r eval=FALSE}
#!/usr/bin/env Rscript #optional
setwd(~/regex_R) # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)
getwd()          # Arbeitsverzeichnis anzeigen
print("Das ist ein Test") # Zeichenkette "Das ist ein Test" ausgeben
```
Im Nachinein wäre es wohl besser gewesen, ich hätte das echte Arbeitsverzeichnis in das Script geschrieben, den Pfad zum Verzeichnis beim Computerwechsel manuell (im Script) angepasst und die Ausführung des entsprechenden Codeblocks aktiv geschaltet. Das selbe problematische Vorgehen habe ich übrigens beim vorherigen Shell-Codeblock gemacht. Dieser könnte also potentiell auch fehlerhaft sein.

Die Ausführung aller anderen Codeblöcke war hingegen während der Erstellung des Tutorials aktiviert. Hier wären also (Syntax-)Fehler bereits bei der Tutorialerstellung aufgefallen :) (vgl. letzte RMarkdown-Fassung des Tutorials: NoPaste-Eintrag41781).

Huo
Beiträge: 614
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs: R (stringr)

Beitrag von Huo » 13.07.2022 09:18:46

Meine Lösungen zu den ersten drei Aufgaben. Aufgaben 1 und 2 habe ich im interaktiven R-Modus bearbeitet, für Aufgabe 3 ein kleines Skript geschrieben.
tegula hat geschrieben: ↑ zum Beitrag ↑
08.07.2022 15:45:08
1. Bestimme, wie viele Buchstaben die URL des dfde-Unterforums "Softwareentwicklung und -paketierung, Scripting" (viewforum.php?f=34) enthält. Zähle einmal mit und einmal ohne die Angabe des Protokolls ("https").

Code: Alles auswählen

>library(stringr)
>
> # URL mit Protokoll
> url = "https://debianforum.de/forum/viewforum.php?f=34"
> c = str_count(url, "[:alpha:]")
> # Ausgabe des Ergebnisses
> message("Anzahl der Buchstaben: ", c)
Anzahl der Buchstaben: 36
>
> # Entfernen des Protokolls
> url_short = str_match(url, "https?://(.*)")
> s = str_count(url_short, "[:alpha:]")
> # Ausgabe des Ergebnisses
> message("Anzahl der Buchstaben: ", s[2])
Anzahl der Buchstaben: 31
2. Bestimme, wie viele Verse (Zeilen) der Schwäbischen Kunde mit einem Vokal (Selbstlaut) beginnen.
Da die Funktion str_count für jede Zeile getrennt zählt, musste ich am Schluß die Einsen aufaddieren. Funktioniert analog übrigens auch mit str_detect (dann zählt sum die TRUEs).

Code: Alles auswählen

> library(stringr)
> load("schwaebische_kunde.RData")
> c = str_count(schwaebische_kunde, "^[:punct:]*[AEIOU]")
> print(c)
 [1] 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 0 1 0
[39] 0 1 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0
> message(sum(c), " Verse beginnen mit einem Vokal.")
15 Verse beginnen mit einem Vokal.
3. Mehrere Einwohner von Neu New York wurden nach ihrer Lieblingsfarbe gefragt. Das Ergebnis findest du im NoPaste: NoPaste-Eintrag41775 (Hinweis: Laden erfolgt mit dem R-Befehl load("umfrage.RData")). Ordne ihren Antworten mithilfe regulärer Ausdrücke den folgenden Kategorien zu "Rot", "Blau", "Grün", "Andere Farbe" und NA (fehlender Wert).
Futurama-Kenner werden die Antworten der Umfrage sicher kaum überraschen :D ... Hier konnte ich im str_replace-Befehl die fehlenden Farbangaben nur durch den String "NA" ersetzen und musste diesen dann wiederum per gesonderter Zuweisung durch den (von der Aufgabenstellung wohl erwarteten) logischen Wert NA ersetzen. Ob das mit stringr auch direkt in einem Schritt geht?

Code: Alles auswählen

setwd("~/regex_R") # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)

library(stringr)   # benötigt für str_replace

load("umfrage.RData")

# Normierung der Farbangaben
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[gG]rün.*", replacement = "Grün")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[gG]elb.*", replacement = "Gelb")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[bB]lau.*", replacement = "Blau")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[rR]ot.*", replacement = "Rot")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = "^[:space:]+$", replacement = "NA")
# Regex mit negativem Lookahead für andere Farben
umfrage$farbe <- str_replace(umfrage$farbe, pattern = "^(?!Blau|Rot|Gelb|Grün|NA).*$", replacement = "Andere")

# Ersetzen des Strings "NA" durch logical NA
umfrage$farbe[umfrage$farbe == "NA"] <- NA

# Ausgabe des Ergebnisses
cat("STATISTIK:", sep="\n")
print((table(umfrage$farbe, useNA = "always"))[c(2, 3, 4, 5, 1, 6)])
cat("\nTABELLE MIT NORMIERTEN FARBEN:", sep="\n")
print(umfrage)

## Falls Speichern des geänderten Data-Frames erwünscht
# save(umfrage, file = "umfrage_1.RData")
Ausgabe des Skripts:

Code: Alles auswählen

$ Rscript ~/regex_R/umfrage.R
STATISTIK:

  Blau   Gelb   Grün    Rot Andere   <NA> 
     1      3      3      3      3      2 

TABELLE MIT NORMIERTEN FARBEN:
                    name  farbe
1                    Fry   Gelb
2                  Leela Andere
3              Professor   Grün
4                    Amy Andere
5               Zoidberg    Rot
6                 Bender Andere
7                 Hermes   Gelb
8                   Kiff   Blau
9          Roboterteufel    Rot
10 Roboterweihnachtsmann    Rot
11               Nippler   <NA>
12                 Morbo   Grün
13                 Nixon   <NA>
14              Calculon   Gelb
15                  Lrrr   Grün

Benutzeravatar
tegula
Beiträge: 439
Registriert: 04.06.2004 13:51:04
Lizenz eigener Beiträge: MIT Lizenz

Re: RegExp-Kurs: R (stringr)

Beitrag von tegula » 13.07.2022 13:23:41

Huo hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 09:18:46
Meine Lösungen zu den ersten drei Aufgaben. Aufgaben 1 und 2 habe ich im interaktiven R-Modus bearbeitet, für Aufgabe 3 ein kleines Skript geschrieben.
Wow! Klasse Lösungen :THX:
Huo hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 09:18:46
tegula hat geschrieben: ↑ zum Beitrag ↑
08.07.2022 15:45:08
3. Mehrere Einwohner von Neu New York wurden nach ihrer Lieblingsfarbe gefragt. Das Ergebnis findest du im NoPaste: NoPaste-Eintrag41775 (Hinweis: Laden erfolgt mit dem R-Befehl load("umfrage.RData")). Ordne ihren Antworten mithilfe regulärer Ausdrücke den folgenden Kategorien zu "Rot", "Blau", "Grün", "Andere Farbe" und NA (fehlender Wert).
Futurama-Kenner werden die Antworten der Umfrage sicher kaum überraschen :D ... Hier konnte ich im str_replace-Befehl die fehlenden Farbangaben nur durch den String "NA" ersetzen und musste diesen dann wiederum per gesonderter Zuweisung durch den (von der Aufgabenstellung wohl erwarteten) logischen Wert NA ersetzen. Ob das mit stringr auch direkt in einem Schritt geht?

Code: Alles auswählen

setwd("~/regex_R") # Arbeitsverzeichnis festlegen (Pfad ggf. anpassen)

library(stringr)   # benötigt für str_replace

load("umfrage.RData")

# Normierung der Farbangaben
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[gG]rün.*", replacement = "Grün")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[gG]elb.*", replacement = "Gelb")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[bB]lau.*", replacement = "Blau")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = ".*[rR]ot.*", replacement = "Rot")
umfrage$farbe <- str_replace(umfrage$farbe, pattern = "^[:space:]+$", replacement = "NA")
# Regex mit negativem Lookahead für andere Farben
umfrage$farbe <- str_replace(umfrage$farbe, pattern = "^(?!Blau|Rot|Gelb|Grün|NA).*$", replacement = "Andere")

# Ersetzen des Strings "NA" durch logical NA
umfrage$farbe[umfrage$farbe == "NA"] <- NA

# Ausgabe des Ergebnisses
cat("STATISTIK:", sep="\n")
print((table(umfrage$farbe, useNA = "always"))[c(2, 3, 4, 5, 1, 6)])
cat("\nTABELLE MIT NORMIERTEN FARBEN:", sep="\n")
print(umfrage)

## Falls Speichern des geänderten Data-Frames erwünscht
# save(umfrage, file = "umfrage_1.RData")
Ausgabe des Skripts:

Code: Alles auswählen

$ Rscript ~/regex_R/umfrage.R
STATISTIK:

  Blau   Gelb   Grün    Rot Andere   <NA> 
     1      3      3      3      3      2 

TABELLE MIT NORMIERTEN FARBEN:
                    name  farbe
1                    Fry   Gelb
2                  Leela Andere
3              Professor   Grün
4                    Amy Andere
5               Zoidberg    Rot
6                 Bender Andere
7                 Hermes   Gelb
8                   Kiff   Blau
9          Roboterteufel    Rot
10 Roboterweihnachtsmann    Rot
11               Nippler   <NA>
12                 Morbo   Grün
13                 Nixon   <NA>
14              Calculon   Gelb
15                  Lrrr   Grün
Deine Lösung weicht leicht von der Aufgabenstellung ab. Du hast eine zusätzliche Kategorie Gelb eingeführt, die in der Aufgabenstellung nicht enthalten ist ;). Inhaltlich ist deine Kategorisierung aber eigentlich besser, schließlich wird die Farbe Gelb häufiger genannt als die Farbe Blau :THX: .
Huo hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 09:18:46
... Hier konnte ich im str_replace-Befehl die fehlenden Farbangaben nur durch den String "NA" ersetzen und musste diesen dann wiederum per gesonderter Zuweisung durch den (von der Aufgabenstellung wohl erwarteten) logischen Wert NA ersetzen. Ob das mit stringr auch direkt in einem Schritt geht?
Mit stringr::str_detect kannst du es in einem Schritt machen :)

Code: Alles auswählen

umfrage$farbe[str_detect(umfrage$farbe, "^[:space:]+$")] <- NA

Huo
Beiträge: 614
Registriert: 26.11.2017 14:03:31
Wohnort: Freiburg

Re: RegExp-Kurs: R (stringr)

Beitrag von Huo » 13.07.2022 15:19:59

tegula hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 13:23:41
Deine Lösung weicht leicht von der Aufgabenstellung ab. Du hast eine zusätzliche Kategorie Gelb eingeführt, die in der Aufgabenstellung nicht enthalten ist ;). Inhaltlich ist deine Kategorisierung aber eigentlich besser, schließlich wird die Farbe Gelb häufiger genannt als die Farbe Blau :THX: .
Die Abweichung von der Aufgabenstellung war gar keine Absicht. Nach dem zu flüchtigen Lesen der Aufgabe hatte ich mich wohl zu eifrig ins Programmieren gestürzt :oops:. Zu meinem Glück hat keiner der Umfrageteilnehmer mit "gelbgrün" geantwortet :D.
tegula hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 13:23:41
Huo hat geschrieben: ↑ zum Beitrag ↑
13.07.2022 09:18:46
... Hier konnte ich im str_replace-Befehl die fehlenden Farbangaben nur durch den String "NA" ersetzen und musste diesen dann wiederum per gesonderter Zuweisung durch den (von der Aufgabenstellung wohl erwarteten) logischen Wert NA ersetzen. Ob das mit stringr auch direkt in einem Schritt geht?
Mit stringr::str_detect kannst du es in einem Schritt machen :)

Code: Alles auswählen

umfrage$farbe[str_detect(umfrage$farbe, "^[:space:]+$")] <- NA
Oh, das ist genial :THX:! Im Grunde hätte man alle Farbersetzungen auf die Weise vornehmen können – wäre jedenfalls weniger Schreibarbeit als mit str_replace :wink: .

Benutzeravatar
tegula
Beiträge: 439
Registriert: 04.06.2004 13:51:04
Lizenz eigener Beiträge: MIT Lizenz

Re: RegExp-Kurs: R (stringr)

Beitrag von tegula » 07.09.2022 16:06:02

Da keine weiteren Lösungen hinzugekommen sind, ist es denke ich OK, wenn ich jetzt die Lösungs-Beispiele poste :wink: . Freue mich aber natürlich weiterhin über neue Lösungen und/oder Kritik an den Lösungs-Beispielen!

Lösungs-Beispiele für die Aufgabe 1 bis 4:

Antworten