ablaette / learningR

Course taught at the University of Duisburg-Essen to get started with R.
Creative Commons Attribution 4.0 International
2 stars 3 forks source link

Merkwürdige Notationd einiger Daten im Datensatz der Corona Statistik Stadt Duisburg #11

Open AlexanderJungesblut opened 3 years ago

AlexanderJungesblut commented 3 years ago

Hallo Zusammen,

bei der Bearbeitung der Aufgabe zu den Corona-Fällen der Stadt Duisburg bin ich auf ein Problem im Datensatz gestoßen. Und zwar scheinen die ersten 59 Einträge in der zweiten Spalte (bestätigten Fälle) anders notiert zu sein, als alle darauf folgenden Einträge in der selben Spalte.

Ich habe folgende Lösung gefunden, bin mir aber nicht sicher, ob sie wirklich richtig ist. Was denkt ihr?

# Laden der Tabelle als CSV Datei aus dem Netz
corona <- read.csv("https://opendata-duisburg.de/sites/default/files/Corona%2028.02.2021.csv", sep=";")

# Umbenennung der Spalten
colnames(corona) <- c("datum", "bestaetigt", "aktuell", "genesen", "verstorben")
View(corona) # In der zweiten Spalte sehen wir, dass die ersten 59 Einträge anders notiert sind, als die darauf folgenden.

# Ich möchte testen, ob die Einträge in der Spalte numerisch sind.
is.numeric(corona$bestaetigt) # Der Output ist True, damit gehe ich davon aus, dass alle Werte numerisch sind

# Angleichen der ersten 59 Einträge in der Spalte bestaetigt durch Multiplikation
corona[1:59,2] <-  corona[1:59,2] * 1000

is.numeric(corona$bestaetigt) # Das Ergebnis ist immer noch numerisch

Ich freue mich auf den Austausch.

Alexander

timobornfleth commented 3 years ago

Der Unterschied liegt hier darin, dass read.csv() als default dezimalzeichen den Punkt hat: dec = '.' Damit wird (entgegen der Notation mit einem Komma als Dezimalzeichen) die Zahl 19.177 als 19,177 gespeichert und ist damit numerisch. Dein Fix, einfach alle Zahlen auf die das zutrifft mit 1000 zu multiplizieren kommt mir schlau vor :) Das ganze wird vielleicht mit folgendem code klar:

corona_1 <- read.csv('https://opendata-duisburg.de/sites/default/files/Corona%2028.02.2021.csv', sep = ';', dec = '.')
colnames(corona_1) <- c("datum", "bestaetigt", "aktuell", "genesen", "verstorben")
is.numeric(corona_1$bestaetigt)

Wird TRUE liefern, aber die ersten 59 Einträge sind sehr klein gegenüber den Folgenden. dagegen

corona_2 <- read.csv('https://opendata-duisburg.de/sites/default/files/Corona%2028.02.2021.csv', sep = ';', dec = ',')
# oder
corona_3 <- read.csv2('https://opendata-duisburg.de/sites/default/files/Corona%2028.02.2021.csv')
colnames(corona_2) <- c("datum", "bestaetigt", "aktuell", "genesen", "verstorben")
colnames(corona_3) <- c("datum", "bestaetigt", "aktuell", "genesen", "verstorben")
is.numeric(corona_2$bestaetigt) 
is.numeric(corona_3$bestaetigt) 

liefert FALSE. Die Daten werden hier als 'character' gespeichert, weil der read befehl nicht weiß, wie er mit dem Punkt zwischen den Zahlen anders umgehen soll:

typeof(corona_2$bestaetigt) # 'character'
typeof(corona_3$bestaetigt) # 'character'
is.character(corona_2$bestaetigt) # TRUE
is.character(corona_3$bestaetigt) # TRUE

Wenn die Datenspalte als character eingelesen wird ist der Fix etwas schwieriger, also würde ich sagen ist deine Lösung wahrscheinlich sogar die bessere. Allerdings können Probleme auftauchen, wenn die Verwendung von Punkten weniger klar geordnet ist als hier (die oberen 59 Einträge haben einen Punkt, die darunter keinen mehr). Wenn zum Beispiel die Punkte in unregelmäßigen Abständen vorkommen müsste man auf irgend eine Weise danach suchen.

Grüße Timo

ablaette commented 3 years ago

Das Beispiel ist leider echt etwas tückenreich. Wenn unser Ziel ist, die Daten robust einzulesen, dann sollte man nicht bekannte Probleme nachbereiten (postprocessing), sondern ein Verfahren wählen, durch das die Tausendertrennzeichen schon beim Einlesen (preprocessing) entfernt werden.

Hilfreich bei der Suche nach einer kompakten und robusten Lösung find ich diesen Thread.

Die m.E. beste Lösung bietet das readr-Paket. Die read.csv()-Funktion von base R stößt bei unserem Szenario an Grenzen. Bei der Funktion read_delim() kann man die Spaltentypen spezifizieren und Angaben zu dem Tausendertrennzeichen machen (Argument grouping_mark bei locale()). Dadurch werden dann bei Spalten mit Nummern (definiert über col_number()) die Tausendertrennzeichen ignoriert.

install.packages("readr")
library(readr)
tab <- readr::read_delim(
  file = "https://opendata-duisburg.de/sites/default/files/Corona%2028.02.2021.csv",
  col_types = cols(col_character(), col_number(), col_integer(), col_number(), col_number()),
  locale = locale(decimal_mark = ",", grouping_mark = "."),
  delim = ";"
)

Wie lässt sich der Weg zu dieser Lösung nachvollziehen? Wühlen Sie etwas in der Dokumentation der Funktionen...

ablaette commented 3 years ago

Wir hatten hier mehr Schwierigkeiten als es der Fall sein sollte. Ich habe daher folgende Nachricht Open Data Duisburg geschickt:

Beginn der Nachricht

Sehr geehrte Damen und Herren,

vielen Dank für das wunderbare "Open Data Duisburg"-Angebot! Dieses nutze ich gerne, derzeit für meinen Kurs "Wissenschaftliches Programmieren mit R", den ich für Studierende der Sozialwissenschaften studiengangsübergreifend an der Universität Duisburg-Essen unterrichte.

Konkret arbeite ich in diesem Sommersemester mit den Statistiken mit den Corona-Fallzahlen. Folgende Schwierigkeiten möchte ich gerne rückmelden.

Erstens werden im csv-Datenformat neben dem Dezimal-Trennzeichen (",") Tausender-Trennzeichen (".") verwendet. Das verkompliziert das Einlesen der Daten m.E. unnötig. Ich fände es viel besser und nutzerfreundlicher, wenn das Tausender-Trennzeichen bei csv-Datenformaten generell nicht zum Einsatz käme. Meine Rückmeldung bezieht sich konkret auf diese Datei: https://opendata-duisburg.de/sites/default/files/Corona%2030.04.2021.csv Desweiteren tritt in dieser Datei das NO-BREAK-SPACE Zeichen (\u00A0) auf, was ebenfalls die Datenverarbeitung erschwert.

Meine zweite Rückmeldung betrifft das JSON-Datenformat: https://opendata-duisburg.de/api/action/datastore/search.json?resource_id=00766064-4cab-4f40-8f67-82ec6b14d6ca Die Zahlen hier stimmen nicht mit denen im Excel bzw. csv-Format überein. Meine Vermutung ist, dass Tausender-Trennzeichen in einem ursprünglichen Excel-Sheet bei der Umwandlung in JSON fälschlich als Dezimal-Trennzeichen interpretiert wird, d.h. berichtete Zahlen sind die Ganzzahlwerte, die nach einer Division der Zahl durch 1000 übrig bleiben.

Ich finde Ihr Angebot großartig und möchte helfen, dass es noch besser wird!

Herzlicher Gruss Ihr Andreas Blätte

Ende der Nachricht