Strings in Dataframe nach Unterthemen durchsuchen

Wie rufe ich R-Funktionen auf, wie selektiere ich Daten, ich weiß nicht genau ....

Moderatoren: EDi, jogo

Dörk
Beiträge: 10
Registriert: Sa Aug 29, 2020 7:06 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Dörk »

Man liest ja auch - wie ich es tue - mit "fread" aus data.table ein, das ist -zig mal schneller, vor allem von (NVMe-) SSD!
Gut zu wissen! Ich werde dann alles auf fread umstellen! Ich kapiere langsam, dass R nicht gleich R ist. :D
Vielleicht schafft fread auch meine Problem csv, Die hatte bisher read.csv immer zum Ausstieg gezwungen. ich nehme an, weil sie zu groß ist.
Ich muss mich eindeutig mit dem data.table Package beschäftigen! :D
Du hast Recht!
Ich hoffe, ich kam nicht zu rechthaberisch rüber. Das war nicht meine Intention. :? Mir fiel das nur auf, als ich den Code nachvollziehen wollte.
Ich bin dir super dankbar. :) Damit kann ich weiter jetzt weiter machen. Ich werde euch auf dem Laufenden halten. Testen kann ich den aber erst am Wochenende. Ich hab leider noch einen langen Dienst vor mir.

Grüße
Dirk
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von bigben »

Dörk hat geschrieben: Mi Sep 02, 2020 9:14 pmIch kapiere langsam, dass R nicht gleich R ist. :D
R ist eine alte Dame. Es ist eine Implementierung der Sprache S, die in den 70er Jahren des letztes Jahrhunderts entwickelt wurde und der Zuweisungsoperator `<-` soll angeblich so aussehen, weil es das damals als Zeichen auf den Tastaturen gab. Und wer 40 Jahre lang auf Rückwärtskompatibilität geachtet hat, zugleich sich aber auch 40 Jahre so weiter entwickelt hat, dass er heute ganz vorne mitschwimmt, der schleppt auch Altlasten mit sich herum. Wäre merkwürdig, wenn da alles immer homogen wäre.
Ich muss mich eindeutig mit dem data.table Package beschäftigen! :D
Wenn Du umfangreiche Daten schnell verarbeiten willst ist das eindeutig eine gute Idee.
Mein PC sollte mit SSD, 16 Kernen und 90gb Ram eigentlich schneller sein
Das sind ja radiologische Ausmaße! Leider bedeuten 16 Kerne nie, dass ein Rechner 16 Mal so schnell läuft. Erstens ist nicht jedes Problem gleichermaßen dazu geeignet, parallelisiert zu werden, andererseits fällt beim Parallelisieren immer Organisationsaufwand an, der zusätzlich zu leisten ist.

Einerseits stammt R aus einer Zeit, als die meisten keine Multicoreprozessoren hatten und andererseits ist es nicht trivial für R zu erkennen, wann multicore Vor- und wann es Nachteile bringt. Du musst also i. d. R. selbst aktiv werden, wenn etwas zu parallelisieren ist. Eine recht anfängerfreundliche Variante stellt die foreach-Funktion im foreach-package dar. Du kannst Deine Daten beispielsweise in data.table in 10 Untergruppen aufteilen und dann die Suche in jedem der 10 Datenpakete mit foreach auf 10 Cores verteilen.

Es gibt viele weitere Möglichkeiten zum Parallelisieren. Einige besonders relevante Packages dafür listet der einschlägige CRAN Task View HighPErformanceComputing auf.

HTH,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Athomas
Beiträge: 768
Registriert: Mo Feb 26, 2018 8:19 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Athomas »

Mein PC sollte mit SSD, 16 Kernen und 90gb Ram eigentlich schneller sein als meine Portable Möhre, aber leider verwendet R nur 1-2 Kerne beim Code ausführen gibt es da einen Trick um die Leistung zu erhöhen?
Weitgehend unabhängige, nichttriviale Tasks: das lädt ja geradezu zur Parallelisierung ein! Ich habe deshalb nach Jahren des zufriedenen Programmierens dank data.table (das ja selber einiges parallelisiert) nochmal Versuche zu diesem Thema (mit doParallel und foreach) angestellt - und fand es einfacher, als ich es in Erinnerung hatte!

Dazu habe ich einige Vorbemerkungen:
  • Jeder „worker“ in diesem parallelen Ansatz muss Zugriff auf die im parallelisierten Teil verwendeten Packages haben (Parameter „.packages“). Ich habe daher mein Progrämmchen so umgeschrieben, dass nur noch „stringi“ als zusätzliches Package im parallelisierten Teil verwendet wird.
  • Ich hatte mir die Beschreibung des von mir angepriesenen Packages „stringr“ mal genauer angeguckt und folgenden Hinweis gefunden:
    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.
    Die haben sich also tatsächlich ein Stück vom stringi-Kuchen abgeschnitten und verwenden es unter dem Namen „stringr“ als Teil des „Tidyverse“ :shock: ! Ich habe jede Funktion aus stringr, die ich benutzt habe, in stringi wiedergefunden – hieß sie in stringr „str_*“, so heißt sie in stringi „stri_*“! Dementsprechend bin ich neuerdings „stringi“-Fan :D !
  • Ich habe (in den parallelisierten Teilen) auf die Verwendung von data.table verzichtet, da einerseits data.table selber vieles parallelisiert und ich Konflikte befürchtet habe, andererseits die beteiligten Tabellen nicht die Größe erreichen, in der data.table eindeutige (Performance-) Vorteile bietet. Die (wichtigen) data.table-Funktionen „fread“ und „rbindlist“ werden nach wie vor im nicht-parallelen Teil verwendet.
  • Meiner Meinung nach sollte jeder, der R optimal nutzen will (und in der glücklichen Lage ist, sich das Betriebssystem aussuchen zu können) es unter Linux installieren! Alles ist besser, runder, schneller! Die Syntax für die von mir verwendete Parallelisierung ist unterschiedlich, ich habe im Programmtext darauf hingewiesen.
  • Die Laufzeit sank gegenüber der unparallelisierten Version (auf unterschiedlichen Maschinen!) in Windows auf 45% (4 workers) und in Linux auf 30% (4 workers) bzw. 17% (16 workers). Als Testdatei habe ich Deine 1200 mal wiederholte Beispielsdatei verwendet – das ist vom Volumen her etwa das, was bei Dir tatsächlich ansteht.

Code: Alles auswählen

library(data.table)
library(openxlsx)
library(stringi)
library(foreach)
library(doParallel)

Basisordner     <- "P:/R/R Forum/Diagnose Auswertungen/Simulationen"

texte           <- fread(file.path(Basisordner, "Texte1200.csv"))

a <- proc.time()

cl <- makeCluster(4)
registerDoParallel(cl)

# für Linux: statt der letzten beiden Anweisungen:       registerDoParallel(cores=4)

x <- foreach(i=1:nrow(texte), .packages="stringi") %dopar% {
  Patient       <- texte[i, "TEXT"]
  Fundstellen   <- data.frame(stri_locate_all(Patient, regex="\\r\\n\\r\\n[ a-zA-Z]+:")[[1]])
  Fundstellen$topic <- stri_trim(stri_sub(Patient, Fundstellen$start + 2, Fundstellen$end))
  Fundstellen$Pnr  <- i
  Fundstellen}

Alles <- rbindlist(x)

stopCluster(cl)                        # entfällt in Linux-Version

#--- Vorbereitung, Erstellung der Vorlage für Übersetzungstabelle --------

Extrakt         <- Alles[  , .N, by=topic]
Extrakt[  , TOPIC:=stri_trim(toupper(topic))]

#        Rohtopics mit zugehöriger Großschreibung
write.xlsx(Extrakt, file.path(Basisordner, "Rohtopics.xlsx")) 


#        Topics mit Häufigkeiten bzgl. der Großschreibungs-Variante
zuErgänzen <- Extrakt[  , .(wie.oft=sum(N)), by=TOPIC]                   
write.xlsx(zuErgänzen, file.path(Basisordner, "TOPICS.xlsx"))             
#        in dieser Excel-Datei müssen die Übersetzungen (Spaltenname "Übersetzung" vergeben) hinzugefügt werden!
#        Das Ganze wieder unter "TOPICS plus Übersetzungen.xlsx" speichern.
#        Bitte auch uninteressante Topics übersetzen: nur echte Falschmeldungen
#        erhalten keine Übersetzung!

#-------- Wenn Übersetzungstabelle fertig: -------------------------------
#         Falls R zwischendurch beendet:
#         Datei "texte" (s.o.) und beteiligte libraries nochmal laden

Extrakt         <- read.xlsx(file.path(Basisordner, "Rohtopics.xlsx"))
Transl          <- read.xlsx(file.path(Basisordner, "TOPICS plus Übersetzungen.xlsx"))
Zsamma          <- merge(Extrakt, Transl, by="TOPIC")

verwenden       <- Zsamma[!is.na(Zsamma$Übersetzung), c("topic", "Übersetzung")]

#================================================

#        Hier wird der reine Text (ohne die Zeilenumbrüche) verwendet!

Muster          <- paste(verwenden$topic, collapse="|")

cl <- makeCluster(4)
registerDoParallel(cl)

# für Linux: statt der letzten beiden Anweisungen:       registerDoParallel(cores=4)

y <- foreach(i=1:nrow(texte), .packages="stringi") %dopar%{
  Patient       <- texte[i, "TEXT"]
  Fundstellen   <- data.frame(stri_locate_all(Patient, regex=Muster)[[1]])
  Fundstellen$topic <- stri_trim(stri_sub(Patient, Fundstellen$start, Fundstellen$end))
  Fundstellen$Patient <- i
  FundPlus      <- merge(Fundstellen, verwenden, by="topic")
  FundPlus <- FundPlus[order(FundPlus$start), ]
  Patend        <- nchar(Patient)
  FundPlus$text_start <- FundPlus$end + 1
  FundPlus$text_end   <- c(tail(FundPlus$start, -1) - 1, Patend)
  FundPlus$Beschreibung <- stri_trim(stri_sub(Patient, FundPlus$text_start, FundPlus$text_end))
  FundPlus
}

Patientendaten  <- rbindlist(y)

stopCluster(cl)                        # entfällt in Linux-Version

proc.time() - a
Nachtrag: 40 Worker arbeiten an der Durchsicht der Patientendaten :)
Nachtrag: 40 Worker arbeiten an der Durchsicht der Patientendaten :)
Zuletzt geändert von Athomas am Fr Sep 04, 2020 5:24 pm, insgesamt 1-mal geändert.
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von EDi »

Ich nutze zur parallelisierung eigentlich nur noch das future package: https://arxiv.org/abs/2008.00553

Passt sich mit dem furrr paket wunderbar ins tidyverse ein. Vorteil: Egal ob local sequentiell , parallel in einercloud machine oder ein Supercomputer im Keller, der Code bleibt gleich, ich registriere nur ein anderes backend...

data.table rockt aber trotzdem und kommt immer zum einsatz wenn ich die geschwindigkeit brauche... (rbindlist z.b. ist superduperschnell).
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
bigben
Beiträge: 2771
Registriert: Mi Okt 12, 2016 9:09 am

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von bigben »

Athomas hat geschrieben: Fr Sep 04, 2020 12:33 pm[*]Die Laufzeit sank gegenüber der unparallelisierten Version (auf unterschiedlichen Maschinen!) in Windows auf 45% (4 workers) und in Linux auf 30% (4 workers) bzw. 17% (16 workers).
Fünf bis Sechs Mal so schnell ist schon ein Wort. Aber auch wenn es sich hier um ein sehr paralleles Problem handelt zeigen die Zahlen so gut wie die Grafik:
Rplot08.jpeg
Der Zeitgewinn pro zusätzlichem Kern wird immer kleiner.

@EDi: Danke für den Hinweis auf rbindlist. Kommt gerade sehr gelegen.

LG,
Bernhard
---
Programmiere stets so, dass die Maxime Deines Programmierstils Grundlage allgemeiner Gesetzgebung sein könnte
Benutzeravatar
EDi
Beiträge: 1599
Registriert: Sa Okt 08, 2016 3:39 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von EDi »

Der Zeitgewinn pro zusätzlichem Kern wird immer kleiner.
Ja natürlich, man muss das Zeug ja auch verteilen und wieder einsammeln, das kommt ja auch nicht umsonst...
Bitte immer ein reproduzierbares Minimalbeispiel angeben. Meinungen gehören mir und geben nicht die meines Brötchengebers wieder.

Dieser Beitrag ist lizensiert unter einer CC BY 4.0 Lizenz
Bild.
Dörk
Beiträge: 10
Registriert: Sa Aug 29, 2020 7:06 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Dörk »

Hallo allerseits,

der Kipptaucher ist wieder da. Ich hab die parallelisierte Variante unter Linux bis zur Erstellung der Topics.xlsx durchlaufen lassen. Läuft schnell und ist sehr gründlich. Danke für den Code, Wie erwartet summieren sich da auch eine Menge Müll drunter. Ich zweifel langsam, ob meine Idee so viel Sinn ergibt, da "\\r\\n\\r\\n[ a-zA-Z]+:" auch teile des von mir später zu durchsuchenden Inhalts enthält. Und die Variationsbreite der Topics ist erschreckend. Ich mache jetzt mal bei 3513ten Topic eine Pause. Ich hab noch knapp 10000 vor mir.

Ich hab dennoch einen Testlauf mit der "TOPICS plus Übersetzungen.xlsx" gemacht. Leider erhalte ich da eine Fehlermeldung.

Fehler in { : task 1 failed - "replacement has 1 row, data has 0"

Mache ich da was falsch, ich habe die Topics die ich aktuell als uninteressant eingestuft habe in der Spalte "Übersetzung" leer gelassen. Liegt es möglicherweise an der Bearbeitung der xlsx-Datei mit LibreOffice?

Ich will ja nicht nerven, aber gibt es dazu Ideen?

Grüße
Dirk
Athomas
Beiträge: 768
Registriert: Mo Feb 26, 2018 8:19 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Athomas »

Das ist jetzt natürlich nicht einfach per Ferndiagnose...

Kannst Du bitte mal Deine "TOPICS plus Übersetzungen.xlsx" anhängen?
Welchen Wert hat "Muster"?
Athomas
Beiträge: 768
Registriert: Mo Feb 26, 2018 8:19 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Athomas »

Ich zweifel langsam, ob meine Idee so viel Sinn ergibt, da "\\r\\n\\r\\n[ a-zA-Z]+:" auch teile des von mir später zu durchsuchenden Inhalts enthält.
Da kann drinstehen was will, allein das Vorkommen in der Datei spielt noch keine Rolle für den weiteren Ablauf.
Du sammelst ja nur Textvorschläge für Topics - die, die Dir davon sinnvoll erscheinen, markierst Du ja anschließend für den 2. Schritt - und nur die werden extrahiert!?
Dörk
Beiträge: 10
Registriert: Sa Aug 29, 2020 7:06 pm

Re: Strings in Dataframe nach Unterthemen durchsuchen

Beitrag von Dörk »

Du sammelst ja nur Textvorschläge für Topics - die, die Dir davon sinnvoll erscheinen, markierst Du ja anschließend für den 2. Schritt - und nur die werden extrahiert!?
Ja, ich sammle die Topics und das was unter den Topics steht, so war der Plan.

Ich schicke dir morgen mal die .xlsx. Würde die gerne noch bearbeiten, vielleicht schaffe ich die ja bis zum Ende durch zu gehen und dann hast du die kompletten TOPICS plus Übersetzungen. Vielleicht verlinke ich die auch im Forum mal schauen.

Grüße
Dirk
Antworten