<- gisco_get_nuts(country = "Germany", nuts_level = 0, resolution = 03) d_de
3 Ausführliche Erläuterung der Musterlösung
3.1 Aufgabe 1: Deutschlandkarte mit Zählstellendaten
Als ersten Schritt interessieren uns besonders stark befahrene Streckenabschnitte von Autobahnen und wir wollen diese in einer Deutschlandkarte darstellen. Wir gehen hierbei schrittweise vor:
- Erstellung einer Deutschlandkarte.
- Hinzufügen des Autobahnnetzes in die Deutschlandkarte.
- Die Daten der Zählstellen in die Deutschlandkarte plotten.
3.1.1 Deutschlandkarte
Wie in [Videoquelle] benötigen wir für die Erstellung einer Deutschlandkarte die Pakete giscoR
(https://ropengov.github.io/giscoR/), sf
(https://r-spatial.github.io/sf/) und ggplot2
(https://ggplot2.tidyverse.org/).
Mithilfe des Pakets giscoR
werden geografische Informationen abgerufen, die mithilfe von sf
in ggplot2
dargestellt werden können.
Mit dem Befehl gisco_get_nuts()
werden NUTS-Regionen als sf
(simple feature) Polygone, Punkte und Linien ausgegeben. Wir interessieren uns für die deutschen Grenzen (nuts_level = 0
) und wollen diese als Datensatz speichern.
Die verwendeten Elemente lassen sich in drei Abschnitte unterteilen:
country =
gibt an um welches Land es sich handelt.nuts_level =
gibt Ebene der NUTS an. (0 für Staat, 1 für Bundesländer, 2 für Regierungsbezirke)resolution =
bestimmt die Auflösung.
Für zusätzliche Informationen ist es hilfreich, die Dokumentation des Pakets zu lesen.
Weitere Details zu den NUTS(Nomenclature of territorial units for statistics)-Regionen können auf der Seite des Statistischen Amtes der Europäischen Union gefunden werden.
Zur ersten Überprüfung, ob dieser Schritt entsprechend unserer Erwartung funktioniert hat, können wir mithilfe des Datensatzes bereits mit ggplot2
plotten. Dafür leiten wir die erstellten simple features an ggplot2
weiter und visualisieren diese mit der Funktion geom_sf()
. Diese Funktion arbeitet nach dem bekannten Muster aus Kapitel [Referenz]. Als zusätzliche Option geben wir mit fill = NA
an, dass die Deutschlandkarte nicht farblich eingefärbt werden soll.
ggplot() +
geom_sf(data = d_de, fill = NA, size = 0.5)
Wir sehen, dass dies eine funktionierende Deutschlandkarte darstellt. In den weiteren Schritten schauen wir uns an, wie wir weitere Informationen in diese Karte hinzufügen.
3.1.2 Autobahnverlauf
Wie in [Videoquelle] benötigen wir für die Erstellung des Autobahnverlaufs das Paket osmdata
https://cran.r-project.org/web/packages/osmdata/vignettes/osmdata.html. Dieses Paket verwendet Daten auf Grundlage von Open Street Map.
Um nur die Daten aus Deutschland zu verwenden, müssen wir zuerst eine Anfrage (engl. query) mit der Bounding Box Deutschland erstellen. Die Funktion opq()
erstellt die Anfrage und die Funktion getbb()
legt den Koordinatenbereich der Bounding Box fest. Wir interessieren uns für "Deutschland"
und müssen noch spezifieren, dass wir uns für das Land als Merkmal (featuretype = "country"
) interessieren. Diese Anfrage speichern wir als Objekt zur späteren Verwendung ab. Da dieser Prozess länger dauern kann, ist es hilfreich mit timeout = 600
zu spezifizieren, dass dieser Befehl nach 600 Sekunden aufhört, sollte die Ausführung diese Zeit in Anspruch nehmen.
<- opq(bbox = getbb("Deutschland", featuretype = "country"), timeout = 600) q
Nun können wir unserer Anfrage Objekte mit der Funktion add_osm_feature()
hinzufügen. Mit den Spezifikationen key
für die Kategorie und value
für die genauen Objekte wird festgelegt, welche Arten von Objekten der Anfrage hinzugefügt werden. In unserem Fall interessieren uns nur die Autobahnen: Ein Blick in die Dokumentation von Open Street Map zeigt uns, dass wir key = "highway"
und value = "motorway"
benötigen. Dies leiten wir nun an die Funktion osmdata_sf()
weiter, damit unsere Anfrage im simple feature-Format weiterverarbeitet wird. Wir verwenden nur die osm_lines
und nicht die anderen Objekte wie osm_points
und osm_polygons
. Diesen Datensatz speichern wir als d_bab_raw
.
<- (add_osm_feature(q, key = "highway", value = "motorway") |> osmdata_sf())$osm_lines d_bab_raw
Diese Daten müssen nun noch weiter aufbereitet werden. Dabei handelt es sich um den schwierigsten Schritt in diesem Baustein: Ein Blick in den Datensatz zeigt, dass dort viele für unseren Fall uninteressante Variablen und einige nicht vorhandene Werte vorliegen. Außerdem werden die Autobahnen über die deutschen Grenzen hinaus dargestellt, wir interessieren uns aber momentan nur für die Werte in Deutschland.
Um nur den Autobahnverlauf in Deutschland dazustellen benötigen wir einen Filter mit filter()
. Als Element des Filters verwenden wir die Funktion st_contains()
aus dem Paket sf
und fügen unsere Datensätze d_de
und d_bab_raw
ein, sodass nur die Werte aus d_bab_raw
übernommen werden, die sich in d_de
befinden. Zusätzlich geben wir mit sparse = FALSE
an, dass kein “sparse index” ausgegeben werden soll. Mit drop_na(ref)
werden alle Reihen exkludiert, die einen nicht vorhandenen (NA englisch für not available) Wert für die Variable ref
besitzen. Die Variable ref
stellt die Bezeichnung der jeweiligen Autobahn da. Wir wollen also alle Objekte, die nicht zugeordnet werden entfernen.Mit group_by(ref)
und summarise()
wird der Datensatz nach der ref
-Variable gruppiert und alle Reihen mit demselben Wert werden zusammengefasst. Zuletzt verwenden wir st_simplify()
um den Autobahnverlauf zu vereinfachen und nicht jeden Eckpunkt darzustellen. Mit dTolerance =
stellen wir den Toleranzparameter für unsere Vereinfachung in Metern ein (in unserem Fall beträgt dies 100 Meter). Diesen Datensatz speichern wir als d_bab
ab.
<- opq(bbox = getbb("Deutschland", featuretype = "country"), timeout = 600)
q <- (add_osm_feature(q, key = "highway", value = "motorway") |> osmdata_sf())$osm_lines
d_bab_raw <- d_bab_raw |>
d_bab filter(st_contains(d_de, d_bab_raw, sparse = FALSE)[1,]) |>
drop_na(ref) |>
group_by(ref) |>
summarise() |>
st_simplify(dTolerance = 100)
save(d_bab, d_bab_raw, file = "data/bab.RData")
Um zu verhindern, dass die durchaus lange Bearbeitungsdauer der ‘add_osm_features’-Funktion jedes Mal beim Rendern des Dokuments durchgeführt wird, lohnt es sich die rohen RData-Dateien abzuspeichern und mithilfe einer if-Abfrage zu schauen, ob diese Dateien bereits vorhanden sind und dann zu laden. Beispielhaft könnte dies mit einer if-Abfrage so aussehen:
if (!file.exists("data/d_bab.RData")) {
<- opq(bbox = getbb("Deutschland", featuretype = "country"), timeout = 600)
q <- (add_osm_feature(q, key = "highway", value = "motorway") |> osmdata_sf())$osm_lines
d_bab_raw <- d_bab_raw |>
d_bab filter(st_contains(d_de, d_bab_raw, sparse = FALSE)[1,]) |>
drop_na(ref) |>
group_by(ref) |>
summarise() |>
st_simplify(dTolerance = 100)
save(d_bab, d_bab_raw, file = "data/bab.RData")
else {
} load(file = "data/d_bab.RData")
}
Wenn man diese Daten nun mit der bereits erstellten Deutschlandkarte kombiniert, erhält man diese Darstellung:
ggplot() +
geom_sf(data = d_de, fill = NA, size = 0.5) +
geom_sf(data = d_bab, size = 0.35, show.legend = FALSE)
3.1.3 Zählstellendaten
Zuguterletzt fügen wir die tatsächlichen Verkehrsdaten zu unserer Darstellung hinzu. Wir verwenden hier die Daten von Dauerzählstellen auf Autobahnen für das Jahr 2022, die die Bundesanstalt für Straßenwesen (BASt) online zur Verfügung stellt. Die heruntergeladene CSV-Datei importieren wir mithilfe der read_csv2()
-Funktion des Pakets readr
aus der Paketsammlung tidyverse
.
<- read_csv2("data/Jawe2022.csv", locale = locale(encoding = 'iso-8859-1')) d_Jawe
Durch locale = locale(encoding = 'iso-8859-1')
bestimmen wir die Kodierung nach der ISO-Norm 8859-1, damit die Datei auch in anderen Systemen geladen werden kann. Danach müssen wir den Datensatz aufbereiten (siehe [Referenz]) und für unseren Zweck relevante Daten filtern (siehe [Referenz]). Dazu benötigen wir die ebenfalls online verfügbare Datensatzbeschreibung der BASt.
Dort sehen wir, dass die Variable Str_Kl
die Straßenklasse beschreibt. Diese Variable hat die Ausprägungen “A” für Autobahnen und “B” für Bundesstraßen. In unserem Fall interessieren uns nur die Daten für Autobahnen, also die Ausprägung “A”. Dies können wir mit filter(Str_Kl == "A")
erreichen.
Da dieser Datensatz ebenfalls viele nicht vorhandene, sogenannte NA(englisch not available)-Werte beinhaltet, können wir diese ebenfalls herausfiltern. Dies geschieht zum Beispiel mit filter(DTV_Kfz_MobisSo_Q != "NA" )
. Diese beiden Filter können mit dem Operator “&” verknüpft werden. Eine elegantere Lösung ist die Verwendung der drop_na()
-Funktion aus dem Paket tidyr
des tidyverse
.
Eine weitere Maßnahme für unseren speziellen Fall, ist die Sortierung des Datensatzes: ggplot2
geht den Datensatz von oben nach unten durch, um Datenpunkte zu plotten. Wir wollen aber, dass besonders befahrene Abschnitte vor den anderen Punkte liegen und somit gut sichtbar auf der Karte sind. Dazu benutzen wir die arrange()
-Funktion und sortieren den Datensatz aufsteigend nach der Variable DTV_Kfz_MobisSo_Q
.
<- d_Jawe |>
d_JaweNA filter(Str_Kl == "A") |>
drop_na(DTV_Kfz_MobisSo_Q) |>
arrange(DTV_Kfz_MobisSo_Q)
Nun können wir alle Elemente kombinieren: Wir plotten nun also die Deutschlandkarte, die Karte des Autobahnverlaufs und die Daten der Zählstellen in eine Grafik. Ebenfalls in der Datensatzbeschreibung können wir die Variablen für die Länge (Koor_WGS84_E
) und Breite (Koor_WGS84_N
) der Lagekoordinaten in WGS84 für die jeweilige Zählstelle finden. Diese Werte setzen wir als x-Koordinate und y-Koordinate ein.
Um die Darstellung zu verschönern, verwenden wir einige zusätzliche Optionen von ggplot2
. scale_color_distiller
ist Teil der Farbpalette “brewer”, entwickelt von Cynthia Brewer. Mit palette = 8
benutzen wir in unserem Fall die 8. Palette und direction = 1
invertiert die Skala, damit hohe Werte dunkler dargestellt werden und niedrige Werte heller. Mit theme_void
sorgen wir dafür, dass ggplot
-Thema komplett leer ist, wir also keine Achsen, Achsenbeschriftungen, Hintergründe oder Gitternetzlinien in unserer Grafik sehen.
ggplot() +
geom_sf(data = d_de, fill = NA, size = 0.5) +
geom_sf(data = d_bab, size = 0.35, show.legend = FALSE) +
geom_point(data = d_JaweNA, mapping = aes(x = Koor_WGS84_E, y = Koor_WGS84_N, color = DTV_Kfz_MobisSo_Q), size = 1.5, na.rm = FALSE) +
scale_color_distiller(palette = 8 , direction = 1) +
theme_void()
3.2 Aufgabe 2:
Als weitere wichtige Größe in der Verkehrsdatenanalyse schauen wir uns die Tagesganglinien an. Dazu benötigen wir die Daten einer Zählstelle für jeden Tag. Eine Auflistung der Zählstellen und ihres Datensatzes findet sich ebenfalls auf der Seite der BASt.
Exemplarisch verwenden wir hier die Zählstelle 5116 der A42 in Wanne-Eickel. Diese Daten müssen wir zuerst einlesen:
<- read_csv2("data/zst5116_2022.csv", locale = locale(encoding = 'iso-8859-1')) ZST5116
Auch hier hilft es, sich die Datensatzbeschreibung der BASt anzuschauen.
3.2.1 Aufgabe 2 a):Tagesganglinien
3.2.1.1 Einzelne Wochentage
Wir wollen nun die Tagesganglinien der ausgewählten Zählstelle für jeden Wochentag erstellen. Wir brauchen also Mittelwerte für jede Stunde jedes Wochentages. Dazu benötigen wir das Paket dplyr
aus der Paketsammlung tidyverse
.
Mithilfe der Funktion group_by()
können wir unseren Datensatz nach Variablen gruppieren. Für unseren Fall sind dies die Variablen Stunde
für die Erhebungsstunde und Wotag
für den Wochentag.
Danach leiten wir diese Werte an die summarise()
-Funktion weiter. Diese gibt für jede Kombination der Gruppierungsvariable eine Reihe aus. Dazu benötigen wir für Kombination ebenfalls die Mittelwerte für beide Fahrtrichtungen (KFZ_R1
und KFZ_R2
). Diesen Datensatz speichern wir als neues Element ZST5116_DTV
. Für die weitere Verwendung bietet es sich an, die Variable Wotag
mit factor ()
in einen Faktor umzuwandeln und die Ebenen des Faktors (levels =
) korrekt nach den Wochentagen zu benennen (labels =
).
<- ZST5116 |>
ZST5116_DTV group_by(Stunde, Wotag) |>
summarise(avg_KFZ_R1 = mean(KFZ_R1),avg_KFZ_R2 = mean(KFZ_R2))
$Wochentag <- factor(ZST5116_DTV$Wotag,
ZST5116_DTVlevels = c(1,2,3,4,5,6,7),
labels = c("Mo","Di","Mi","Do","Fr","Sa","So"))
Nun können wir diese Daten (exemplarisch hier Fahrtrichtung 1 mit KFZ_R1
) in ggplot2
verwenden. Wir wollen für eine Tagesganglinie nun für jede Stunde einen Datenpunkt darstellen und diese mit einer Linie verbinden.
Zuerst erstellen wir mit ggplot()
unsere Umgebung zum Erstellen von Grafiken. Da wir wie angesprochen zwei Formen (Datenpunkte und Linien) verwenden, bietet es sich an, die Einstellungen wie der verwendete Datensatz und die verwendeten Variablen global in ggplot()
und nicht bei den einzelnen Elementen festzulegen. Dazu legen wir mit data = ZST5116_DTV
den neu erstellten Datensatz als Datensatz fest. Mit aes()
legen wir fest, wie Variablen visuelle Eigenschaften zugeordnet werden. Mit x = Stunde
und y = avg_KFZ_R1
bestimmen wir, dass die Stunde auf der X-Achse abgetragen wird und unsere neu erstellten Mittelwerte auf der y-Achse. Wir wollen unsere Daten aber noch nach Wochentagen aufteilen und einfärben und dies geschieht mit group = Wochentag
und color = factor(Wochentag)
. All diese Eigenschaften werden an nachfolgende geoms “weitervererbt”. Mit geom_point
fügen wir die Datenpunkte hinzu und mit geom_line
die Linie. Die Zusatzoptionen size = 2
und linewidth = 1
verändern die Größe der Elemente und dienen der Ästhetik, sind aber natürlich persönliche Präferenz. Zuguterletzt beschriften wir mit labs()
unsere Grafik. Dazu ändern wir mit title =
den Titel, mit x =
und y =
die Beschriftung der jeweiligen Achse und mit color =
die Legende für die Farben.
Als Zusatzoption verwenden wir mit scale_color_viridis_d
die Viridisfarbpalette, die so gestaltet wurde, dass Personen mit häufigen Formen von Farbenblindheit diese besser wahrnehmen können.
Mit theme_light()
verwenden wir ein vorgefertigtes Thema (https://ggplot2.tidyverse.org/reference/ggtheme.html), um die Darstellungsform aller nicht Daten-Elemente zu steuern. Auch hier handelt es sich natürlich um eine persönliche Präferenz und andere Themen können ebenfalls gewählt werden und gute Grafiken erzeugen.
ggplot(data = ZST5116_DTV, aes(x = Stunde, y = avg_KFZ_R1 ,group = Wochentag ,color = factor(Wochentag), shape = Wochentag)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Tagesganglinien Zählstelle 5116 Richtung 1",
x = "Stunde",
y = "Verkehrsaufkommen Richtung 1 in Kfz/h",
color = "Wochentag",
shape = "Wochentag") +
scale_color_viridis_d() +
theme_light()
3.2.2 Aufgabe 2 b) Mittlerer Werktag von vier Zählstellen
Für den Einstieg in das Thema beginnen wir mit einer einzelnen Zählstelle. Die Lösung für mehrere Zählstellen befindet sich weiter unten in diesem Abschnitt.
Häufig können in der Analyse sogenannte mittlere Werktage verwendet werden, um der Varianz vom Beginn und Ende der Woche zu entgehen. In diesem Fall interessieren uns also die Wochentage Dienstag, Mittwoch und Donnerstag an normalen Werktage außerhalb der Schulferien. Ein Blick in die Datensatzbeschreibung der BASt zeigt uns, dass diese Unterteilung im Datensatz bereits vorliegt. Die Variable Fahrtzw
besitzt die Ausprägungen w für Werktags, u für Urlaubswerktage und s für Sonn- und Feiertage. Somit müssen wir in unseren Filter lediglich die Abfrage Fahrtzw == "w"
einfügen.
$Wotag <- factor(ZST5116$Wotag,
ZST5116levels = c(1,2,3,4,5,6,7),
labels = c("Mo","Di","Mi","Do","Fr","Sa","So"))
<- ZST5116 |>
data_werktag filter(Fahrtzw == "w", Wotag %in% c("Di", "Mi", "Do"))
<- data_werktag |>
data_werktag_mean group_by(Stunde) |>
summarise(avg_KFZ_R1 = mean(KFZ_R1),avg_KFZ_R2 = mean(KFZ_R2))
$Anteil = (data_werktag_mean$avg_KFZ_R1/sum(data_werktag_mean$avg_KFZ_R1)*100) data_werktag_mean
Diese Daten können wir nun analog zum ersten Teil dieser Aufgabe plotten:
ggplot(data = data_werktag_mean, aes(x = Stunde, y = avg_KFZ_R1, group = 1)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Verkehrsaufkommen mittlerer Werktage Zählstelle 5116 R1",
x = "Stunde",
y = "KFZ_R1 in KFZ pro Stunde") +
theme_light()
Um Ein Verständnis zu bekommen wie groß der Anteil der jeweiligen Stunde am Verkehrsaufkommen ist, können wir dies ebenfalls plotten:
ggplot(data = data_werktag_mean, aes(x = Stunde, y = Anteil, group = 1)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Verkehrsaufkommen mittlerer Werktage Zählstelle 5116 R1",
x = "Stunde",
y = "Prozentualer Anteil") +
theme_light()
Oft möchte man nicht nur die Daten einer Zählstelle auswerten, sondern mehrere Zählstellen miteinander vergleichen oder Entwicklungen über Jahre auswerten. Um mehrere Zählstellen miteinander zu vergleichen gehen wir zuerst exakt so vor wie in Kapitel 3.2. Wir importieren hier nun die Datensätze der Zählstellen 5113,5116,5125 und 5128.
<- read_csv2("data/zst5113_2022.csv", locale = locale(encoding = 'iso-8859-1'))
ZST5113 <- read_csv2("data/zst5116_2022.csv", locale = locale(encoding = 'iso-8859-1'))
ZST5116 <- read_csv2("data/zst5125_2022.csv", locale = locale(encoding = 'iso-8859-1'))
ZST5125 <- read_csv2("data/zst5128_2022.csv", locale = locale(encoding = 'iso-8859-1')) ZST5128
Bei einer großen Anzahl an Datensätze mit gleichen Einlesungsoperationen bieten sich Funktionen an, um effizienter zu arbeiten und mögliche Fehler bei copy-and-paste zu verhindern: Siehe dazu [Referenz zu anderem Kapitel] https://r4ds.hadley.nz/functions.html
Um diese verschiedenen Datensätze in einem Datensatz zu kombinieren, verwenden wir die bind_rows()
-Funktion des Pakets dplyr
aus dem tidyverse
. Dazu geben wir dem Befehl eine Liste der zu kombinierenden Datensätze mit list()
und fügen mit .id =
eine Identifizierungsspalte hinzu. Standardmäßig werden diese Variable der Identifizierungsspalte einfach durchnummeriert. Es bietet sich aber an die jeweilige Nummer oder den Namen der Zählstelle zu verwenden. In unserem Fall entscheiden wir uns für den Namen. Analog zu Kapitel 3.2 wandeln wir die Variable Zaehlstelle
in einen Faktor mit den Namen als Ebenen um. Zusätzlich benennen wir auch die Wochentage wie bereits getan erneut um.
<- bind_rows(list(ZST5113,ZST5116,ZST5125,ZST5128), .id = "Zaehlstelle")
all_data
$Zaehlstelle <- factor(all_data$Zaehlstelle, levels = c("1", "2", "3", "4"), labels = c("Bochum", "Wanne-Eickel", "Waltrop-Brambauer", "Wenden-Dahl"))
all_data
$Wotag <- factor(all_data$Wotag,
all_datalevels = c(1,2,3,4,5,6,7),
labels = c("Mo","Di","Mi","Do","Fr","Sa","So"))
<- all_data |>
data_werktag_all filter(Fahrtzw == "w", Wotag %in% c("Di", "Mi", "Do"))
<- data_werktag_all |>
data_werktag_mean_all group_by(Stunde, Zaehlstelle) |>
summarise(avg_KFZ_R1 = mean(KFZ_R1),avg_KFZ_R2 = mean(KFZ_R2))
Wenn wir diese gefilterten Daten wie bereits gelernt darstellen, erhalten wir folgende Plots:
ggplot(data = data_werktag_mean_all, aes(x = Stunde, y = avg_KFZ_R1, group = Zaehlstelle, color = Zaehlstelle)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Verkehrsaufkommen mittlerer Werktage aller Zählstellen",
x = "Stunde",
y = "KFZ_R1",
color = "Wotag") +
scale_color_viridis_d() +
theme_light()
Analog zu den Werktagen filtern wir unsere Daten nun für Samstage.Für die Sonntage ist ein Blick in die Datensatzbeschreiben (siehe oben) hilfreich. In den Daten werden Sonn- und Feiertage gemeinsam aufgeführt, sodass wir unseren Filter dort nicht anwenden können.
#Samstag
<- all_data |>
data_samstag_all filter(Fahrtzw == "w", Wotag == "Sa")
<- data_samstag_all |>
data_samstag_mean_all group_by(Stunde, Zaehlstelle) |>
summarise(avg_KFZ_R1 = mean(KFZ_R1),avg_KFZ_R2 = mean(KFZ_R2))
`summarise()` has grouped output by 'Stunde'. You can override using the
`.groups` argument.
#Sonntag
<- all_data |>
data_sonntag_all filter(Wotag == "So")
<- data_sonntag_all |>
data_sonntag_mean_all group_by(Stunde, Zaehlstelle) |>
summarise(avg_KFZ_R1 = mean(KFZ_R1),avg_KFZ_R2 = mean(KFZ_R2))
`summarise()` has grouped output by 'Stunde'. You can override using the
`.groups` argument.
Plot für Samstage:
ggplot(data = data_samstag_mean_all, aes(x = Stunde, y = avg_KFZ_R1, group = Zaehlstelle, color = Zaehlstelle)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Verkehrsaufkommen an Samstagen aller Zählstellen",
x = "Stunde",
y = "KFZ_R1",
color = "Wotag") +
scale_color_viridis_d() +
theme_light()
Plot für Sonntage:
ggplot(data = data_sonntag_mean_all, aes(x = Stunde, y = avg_KFZ_R1, group = Zaehlstelle, color = Zaehlstelle)) +
geom_point(size = 2) +
geom_line(linewidth = 1) +
labs(title = "Verkehrsaufkommen an Sonntagen aller Zählstellen",
x = "Stunde",
y = "KFZ_R1",
color = "Wotag") +
scale_color_viridis_d() +
theme_light()
3.2.3 Aufgabe 2 c): 50. Stunde
Als einen weiteren wichtigen Kennwert schauen wir uns das Verkehrsaufkommen in der 50. Stunde an. Für eine rein deskriptive Beschreibung der 50. Stunden können wir den Datensatz absteigend sortieren und dann den 50. Wert auswählen. Dazu benutzen wir erneut die arrange()
-Funktion, dieses Mal aber mit dem Zusatz desc()
(kurz für englisch descending = absteigend). Um eine Reihe anhand der Position auszuwählen, verwenden wir den slice()
-Befehl. Dies leiten wir nun an die select()
-Funktion weiter, die es uns ermöglicht anhand des Namens auszuwählen, welche Variablen wir für unsere Darstellung behalten möchten. In diesem Fall wählen wir das Datum (Datum
), den Wochentag (Wotag
), die Stunde des Tages (Stunde
) und den tatsächlichen Verkehrswert (KFZ_R1
) aus.
<- ZST5116 |>
ZST5116_50 arrange(desc(KFZ_R1)) |>
slice(50) |>
select(Datum,Wotag,Stunde,KFZ_R1)
Mit der Funktion kable()
aus dem Paket kableExtra
können wir dies nun tabellarisch darstellen. Wir sehen, dass es sich um Freitag (Wotag 5), den 11. Februar (Datum 220211) in der 14. Stunde handelt und in diesem zeitraum 3173 KFZ erfasst wurden.
kable(ZST5116_50)
Datum | Wotag | Stunde | KFZ_R1 |
---|---|---|---|
220211 | 5 | 14 | 3173 |
Dies zeigt uns aber nur den einzelnen Wert der 50. Stunde ohne dass wir ihn in Relation zu den anderen Werten setzen können. Ein wichtiger Bestandteil der 50. Stunde ist die Einschätzung des Verkehrsaufkommens und wie hoch der Anteil der 50. Stunde im Vergleich zur Topstunde ist. Dafür bietet sich eine Darstellung als Säulendiagramm an.
Wir erstellen einen neuen Datensatz, der das Verkehrsaufkommen in absteigender Reihenfolge darstellt (dieselbe Vorgehensweise wie für unsere deskriptive Beschreibung). Im nächsten Schritt fügen wir eine Variable hinzu, die für uns die Position im Datensatz durchnummeriert (simple Lösung mit 1:nrow()
).
# Erstellen des Streudiagramms für den stündlichen DTV Zählstelle 5116 Richtung 1
<- ZST5116 |>
ZST5116_top arrange(desc(KFZ_R1))
$Nummer = 1:nrow(ZST5116_top) ZST5116_top
Nun können wir unsere Säulendiagramme plotten: Um nicht alle (in unserem Fall 8760) Beobachtungen zu plotten, wird der zu plottende Datensatz mithilfe von dem Zusatz [1:80,]
bei der Festlegung des Datensatzes auf die ersten 80 Beobachtungen reduziert. Es bietet sich an , die 50. Stunde farblich hervorzuheben und mit einem Label zu versehen.
Dazu verwenden wir einen logischen Operator mit fill = Nummer == 50
und können dann mit scale_fill_manual()
das Aussehen festlegen. Durch das Einfügen von values = c("black", "red")
bestimmen wir, dass für den Fall dass der Operator stimmt ( also die 50. Stunde), die Farbe rot verwendet wird, andernfalls die Farbe schwarz. Der Zusatz guide = "none"
sorgt dafür, dass diese Logikabfrage nicht in der Legende aufgeführt wird.
Das Label wird mithilfe der Funktion geom_label
, die analog zu bereits bekannten geoms aus ggplot2
funktioniert, erstellt. Wir filtern den Datensatz mit data = filter(ZST5116_top,Nummer == 50)
, sodass nur die 50. Stunde ein Label erhält und wählen als Inhalt des Labels den KFZ-Wert mit mapping = aes(label = KFZ_R1)
. Die restlichen Optionen dienen der Ästhetik:
nudge_y
verschiebt das Label um eine festgestelegte vertikale Distanz zur besseren Lesbarkeit. Für horizontale Positierung wird analognudge_x
verwendet.size
bestimmt die Größe des Labels.alpha
stellt die Transparenz ein.
ggplot(data = ZST5116_top[1:80, ], aes(x = Nummer,y = KFZ_R1, fill = Nummer == 50, width = .65)) +
geom_bar(stat = "identity") +
labs(title = "Verkehrsaufkommen pro Stunde Zählstelle 5116 Richtung 1",
x = "Sortierte Topstunde",
y = "Verkehrsaufkommen in Kfz/h",
legend = "Wochentag") +
scale_fill_manual(values = c("grey", "red"), guide = "none") +
geom_label(
data = filter(ZST5116_top,Nummer == 50),
mapping = aes(label = KFZ_R1),
nudge_y = 200, size = 4.5, alpha = 0.5
+
) theme_light()
3.2.4 Aufgabe 2 d): Schwerverkehr-Anteile über die Jahre
Nun schauen wir uns, wie wir den Verlauf der Schwerverkehr-Anteile über mehrere Jahre hinweg ansehen können. Dies kann z.B. bei der Beantwortung der Frage helfen, ob durch steigende Globalisierung auch der Anteil am Schwerverkehr steigt.
Um mehrere Dateien gleichzeitig einzulesen, bietet es sich an eine function
zu verwenden, damit dieser Schritt in einem Durchlauf erledigt wird und man mögliche Fehler beim Kopieren und Einfügen vermeidet.
Leider besitzt der Datensatz der Zählstellen keine Variable wie Jahr
anhand derer wir die Identifikation herstellen können. Allerdings besitzen die Dateinamen eine Jahreszugehörigkeit. Daher verwenden wir die Namen der Zählstellendateien als Identifikation und benennen diese Variable mit id = "Jahr"
als Jahr. Nun müssen wir die anderen Elemente des Strings aus den Dateinamen mit str_remove_all
entfernen. Am Schluss wandeln wir den String des Dateinamens, der nun nur noch die Jahreszahl enthält mit as_numeric
in eine Zahl um.
<- list.files(path = "data_jw",
list_of_files recursive = TRUE,
pattern = "\\.csv$",
full.names = TRUE)
<- readr::read_csv2(list_of_files, id = "Jahr", locale = locale(encoding = 'iso-8859-1'))
df $Jahr <- str_remove_all(df$Jahr, "[data_jw/Jawe]")
df$Jahr <- str_remove_all(df$Jahr, "[.csv]")
df$Jahr <- as.numeric(df$Jahr)
df
<- df |>
df_NA filter(DTV_Kfz_MobisSo_Q != 'NA' & DTV_SV_MobisSo_Q != 'NA')
<- df_NA |>
df_schwer group_by(Jahr) |>
summarise(SV = sum(DTV_SV_MobisSo_Q),Alle = sum(DTV_Kfz_MobisSo_Q),Anteil = (SV/Alle)*100)
Diesen nun angepassten Datensatz können wir nun ähnlich wie in #sec-50stunde verwenden, um mit ggplot
ein Balkendiagramm zu erstellen. Damit für jedes Jahr ein Balken erzeugt wirkt, setzen wir manuell die Skala auf der X-Achse mit scale_x_continuous
und stellen diese mit breaks=seq(2003,2018,1)
so ein, dass für 2003 bis 2018 ein Abschnitt (engl. break) erstellt wird.
ggplot(data = df_schwer, aes(x = Jahr, y = Anteil)) +
geom_bar(stat='identity', fill = "blue") +
labs(title ="Anteil des Schwerverkehrs von 2003 bis 2018", x = "Jahr", y = "Anteil am gesamten Verkehrsaufkommen") +
scale_x_continuous(breaks=seq(2003,2018,1)) +
theme_light()