8. Data processing
Arbeitsverzeichnis, Daten und Pakete
Die Daten für dieses Tutorial werden über GitHub bereitgestellt Github. Um den Code mit Ihren eigenen Daten nachzubilden, ersetzen Sie die URL durch Ihren lokalen Dateipfad
Wenn Sie lokal arbeiten, können Sie das Arbeitsverzeichnis entsprechnd anpassen
setwd("YOUR/FILEPATH")
# this will not work. if you want to use it, define a path on your computer
Dies sollte ihre Arbeitsumgebung darstellen, d.h. der Ort an dem ihre Ordner und dazugehörigen Daten abgespeichert sind. Weitere Informationen finden Sie unter hier
Codeabschnitte zum Speichern von Daten und Ergebnissen sind in diesem Tutorial (mit einer #) gekennzeichnet. Bitte ersetzen Sie (“YOUR/FILEPATH”) durch Ihren eigenen lokalen Dateipfad.
Der Code ist so geschrieben, dass Pakete automatisch installiert (wenn nicht bereits installiert) und geladen werden. Die Pakete werden am Standardspeicherort Ihres Computers abgelegt.
Einführung
Das Paket “dplyr” bringt für die Datenaufbereitung eine Reihe nützlicher Funktionen mit, um Daten umzuformen, zu prüfen, zu bereinigen, zu gruppieren oder zusammenzufassen. Es bietet somit sinnvolle Funktionen als Voraussetzung für die eigentliche Datenanalyse. Typische Probleme die im Rahmen der Datenaufbereitung adressiert werden:
- Fehlende Werte, z.B. keine Angabe NA
- Unerwartete Daten, z.B. falscher Datentyp
- Umformung der Daten, z.B. Zusammenführung von zwei Tabellen oder Transposition einer Tabelle
- Neue Variablen (Spalten) berechnen, z.B. die Summe von Werten aus anderen Spalten
Das Paket “dyplr” ist im Paket “tidyverse” enthalten, das noch eine Reihe weiterer Pakete, wie z.B. ggplot2 oder “lubridate”, mitbringt (s. “tidyverse_packages()”). Laden Sie zunächst die benötigten Pakete:
if (!require(tibble)){install.packages("tibble"); library(tibble)}
## Warning: Paket 'tibble' wurde unter R Version 4.1.3 erstellt
if (!require(lubridate)){install.packages("lubridate"); library(lubridate)}
if (!require(tidyr)){install.packages("tidyr"); library(tidyr)}
## Warning: Paket 'tidyr' wurde unter R Version 4.1.3 erstellt
if (!require(ggplot2)){install.packages("ggplot2"); library(ggplot2)}
## Warning: Paket 'ggplot2' wurde unter R Version 4.1.3 erstellt
if (!require(dplyr)){install.packages("dplyr"); library(dplyr)}
## Warning: Paket 'dplyr' wurde unter R Version 4.1.3 erstellt
if (!require(nycflights13)){install.packages("nycflights13"); library(nycflights13)} #load flights data
## Warning: Paket 'nycflights13' wurde unter R Version 4.1.3 erstellt
Der Grundgedanken von “dyplyr”
Die Grundidee von “dyplyr” basiert darauf, dass komplexe Datenanalysen nach dem Lego-Prinzip in einzelne einfache Bausteine zerlegt werden. Darüber hinaus ist ein Grundprinzip des Paketes, dass alle Operationen ein Dataframe (tibble) erwarten (andere Datenstrukturen werden nicht akzeptiert) und wiederum ein solches weiterreichen. Somit können Dataframes entlang einer Arbeitskette, ähnlich einem Fließband, mit spezifischen Operationen bearbeitet werden. Für die lineare Aneinanderreihung der einzelnen Operationen kann mit dem Pipe-Befehl “%>%” schließlich eine Sequenz von auf die Dataframes angewandte Befehle konstruieren werden.
Daten Bereinigung mittels “tidy”
Hier ist ein Beispiel, wie die Funktion gather()
auf einem erfundenen Datensatz angewendet werden kann. In diesem Experiment haben drei Menschen zwei verschiedene Medikamente bekommen und ihre Herzfrequenz wurde aufgezeichnet (vgl. https://blog.rstudio.com/2014/07/22/introducing-tidyr/):
messy <- data.frame(
name = c("Wilbur", "Petunia", "Gregory"),
a = c(67, 80, 64),
b = c(56, 90, 50)
)
Es existieren drei Variablen (Name, Medikament und Herzschlag), aber nur der Name steht derzeit in einer Spalte. Mit gather()
kann die Spalte “a” und “b” entsprechend der Werte der Variablen “Medikament” und “Herzschlag” zusammengefasst werden:
gather(messy, drug, heartrate, a:b)
## name drug heartrate
## 1 Wilbur a 67
## 2 Petunia a 80
## 3 Gregory a 64
## 4 Wilbur b 56
## 5 Petunia b 90
## 6 Gregory b 50
Manchmal werden zwei Variablen in einer Spalte zusammengefasst. Die Funktion separate()
erlaubt es, sie zu trennen. Wir haben Daten, die angeben wie viel Zeit Menschen mit Telefonieren verbringen, gemessen an zwei Standorten (Arbeit und Zuhause). Jede Person wurde nach dem Zufallsprinzip entweder einer Untersuchungsgruppe oder einer Kontrollgruppe zugeordnet.
set.seed(10)
messy <- data.frame(
id = 1:4,
trt = sample(rep(c('control', 'treatment'), each = 2)),
work.T1 = runif(4),
home.T1 = runif(4),
work.T2 = runif(4),
home.T2 = runif(4)
)
Um diese Daten zu ordnen, wird zunächst wieder die Funktion gather()
verwendet, sodass die Spalten “work.T1”, “home.T1”, “work.T1”, “work.T2” und “home.T2” entsprechend der Variabeln “Schlüssel” und “Zeit” sortiert sind.
tidier <- gather(messy,key, time, -id, -trt)
head(tidier, 8)
## id trt key time
## 1 1 treatment work.T1 0.08513597
## 2 2 control work.T1 0.22543662
## 3 3 control work.T1 0.27453052
## 4 4 treatment work.T1 0.27230507
## 5 1 treatment home.T1 0.61582931
## 6 2 control home.T1 0.42967153
## 7 3 control home.T1 0.65165567
## 8 4 treatment home.T1 0.56773775
Als nächstes verwenden wir die Funktion separate()
, um die Einträge zu der Spalte “Schlüssel” in Ort und Zeit aufzuteilen, wobei wir einen regulären Ausdruck verwenden, um das Zeichen zu beschreiben, das sie trennt.
tidy <- separate(tidier, key, into = c("location", "time"), sep = "\\.")
head(tidy,8)
## id trt location time
## 1 1 treatment work T1
## 2 2 control work T1
## 3 3 control work T1
## 4 4 treatment work T1
## 5 1 treatment home T1
## 6 2 control home T1
## 7 3 control home T1
## 8 4 treatment home T1
Als weiteres Beispiel der Datenaufbereitung wird ein Datensatz aus der PanTHERIA-Datenbank (s. Ecology 90:2648. http://esapubs.org/archive/ecol/E090/184/) verwendet. Zur ersten Bereinigung und Aufbereitung der Daten werden in diesem Fall folgende Befehlen verwendet. Machen Sie sich bewusst, was in der folgende Codezeilen ausgeführt wird indem Sie die einzelnen Funktionen recherchieren.
urlfile <- "https://raw.githubusercontent.com/RafHo/teaching/master/angewandte_geodatenverarbeitung/datasource/PanTHERIA_1-0_WR05_Aug2008.txt.txt" # get url from github repositury
mammals <- read.table(urlfile, sep = "\t", header = TRUE, stringsAsFactors = FALSE)
names(mammals) <- sub("X[0-9._]+", "", names(mammals))
names(mammals) <- sub("MSW05_", "", names(mammals))
mammals <- select(mammals, Order, Binomial, AdultBodyMass_g, AdultHeadBodyLen_mm, HomeRange_km2, LitterSize)
names(mammals) <- gsub("([A-Z])", "_\\L\\1", names(mammals), perl = TRUE)
names(mammals) <- gsub("^_", "", names(mammals), perl = TRUE)
mammals[mammals == -999] <- NA
names(mammals)[names(mammals) == "binomial"] <- "species"
mammals <- tbl_df(mammals) # for prettier printing
## Warning: `tbl_df()` was deprecated in dplyr 1.0.0.
## Please use `tibble::as_tibble()` instead.
Die Daten geladenen Daten erkunden
Dataframes sehen bei der Erkundung mit “dplyr” etwas anders aus. Ein Dataframe kann in der Konsole einfach mit seinem Namen aufgerufen werden:
mammals
## # A tibble: 5,416 x 6
## order species adult_body_mass_g adult_he~1 home_~2 litte~3
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Artiodactyla Camelus dromedarius 492714. NA 196. 0.98
## 2 Carnivora Canis adustus 10392. 745. 1.01 4.5
## 3 Carnivora Canis aureus 9659. 828. 2.95 3.74
## 4 Carnivora Canis latrans 11989. 872. 18.9 5.72
## 5 Carnivora Canis lupus 31757. 1055 160. 4.98
## 6 Artiodactyla Bos frontalis 800143. 2700 NA 1.22
## 7 Artiodactyla Bos grunniens 500000 NA NA 1
## 8 Artiodactyla Bos javanicus 635974. 2075 NA 1.22
## 9 Primates Callicebus cupreus 1117. 355. NA 1.01
## 10 Primates Callicebus discolor NA NA NA NA
## # ... with 5,406 more rows, and abbreviated variable names
## # 1: adult_head_body_len_mm, 2: home_range_km2, 3: litter_size
Mit der Funktion glimpse
des Paketes “tibble” (tidyverse) kann er auch transponiert betrachtet werden:
glimpse(mammals)
## Rows: 5,416
## Columns: 6
## $ order <chr> "Artiodactyla", "Carnivora", "Carnivora", "Carn~
## $ species <chr> "Camelus dromedarius", "Canis adustus", "Canis ~
## $ adult_body_mass_g <dbl> 492714.47, 10392.49, 9658.70, 11989.10, 31756.5~
## $ adult_head_body_len_mm <dbl> NA, 745.32, 827.53, 872.39, 1055.00, 2700.00, N~
## $ home_range_km2 <dbl> 1.963200e+02, 1.010000e+00, 2.950000e+00, 1.888~
## $ litter_size <dbl> 0.98, 4.50, 3.74, 5.72, 4.98, 1.22, 1.00, 1.22,~
Spalten auswählen
Die Funktion select()
ermöglicht es, eine Untermenge nach Spalten auszuwählen. Es funktioniert ähnlich der Basis-R-Funktion subset()
, erlaubt aber auch eine ausgefallene Verwendung zusätzlicher Kriterien, wie z.B. contains()
, starts_with()
und ends_with()
:
select(mammals, adult_head_body_len_mm)
## # A tibble: 5,416 x 1
## adult_head_body_len_mm
## <dbl>
## 1 NA
## 2 745.
## 3 828.
## 4 872.
## 5 1055
## 6 2700
## 7 NA
## 8 2075
## 9 355.
## 10 NA
## # ... with 5,406 more rows
select(mammals, adult_head_body_len_mm, litter_size)
## # A tibble: 5,416 x 2
## adult_head_body_len_mm litter_size
## <dbl> <dbl>
## 1 NA 0.98
## 2 745. 4.5
## 3 828. 3.74
## 4 872. 5.72
## 5 1055 4.98
## 6 2700 1.22
## 7 NA 1
## 8 2075 1.22
## 9 355. 1.01
## 10 NA NA
## # ... with 5,406 more rows
select(mammals, adult_head_body_len_mm:litter_size)
## # A tibble: 5,416 x 3
## adult_head_body_len_mm home_range_km2 litter_size
## <dbl> <dbl> <dbl>
## 1 NA 196. 0.98
## 2 745. 1.01 4.5
## 3 828. 2.95 3.74
## 4 872. 18.9 5.72
## 5 1055 160. 4.98
## 6 2700 NA 1.22
## 7 NA NA 1
## 8 2075 NA 1.22
## 9 355. NA 1.01
## 10 NA NA NA
## # ... with 5,406 more rows
select(mammals, -adult_head_body_len_mm)
## # A tibble: 5,416 x 5
## order species adult_body_mass_g home_range_km2 litter_size
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 Artiodactyla Camelus dromedarius 492714. 196. 0.98
## 2 Carnivora Canis adustus 10392. 1.01 4.5
## 3 Carnivora Canis aureus 9659. 2.95 3.74
## 4 Carnivora Canis latrans 11989. 18.9 5.72
## 5 Carnivora Canis lupus 31757. 160. 4.98
## 6 Artiodactyla Bos frontalis 800143. NA 1.22
## 7 Artiodactyla Bos grunniens 500000 NA 1
## 8 Artiodactyla Bos javanicus 635974. NA 1.22
## 9 Primates Callicebus cupreus 1117. NA 1.01
## 10 Primates Callicebus discolor NA NA NA
## # ... with 5,406 more rows
select(mammals, contains("body"))
## # A tibble: 5,416 x 2
## adult_body_mass_g adult_head_body_len_mm
## <dbl> <dbl>
## 1 492714. NA
## 2 10392. 745.
## 3 9659. 828.
## 4 11989. 872.
## 5 31757. 1055
## 6 800143. 2700
## 7 500000 NA
## 8 635974. 2075
## 9 1117. 355.
## 10 NA NA
## # ... with 5,406 more rows
select(mammals, starts_with("adult"))
## # A tibble: 5,416 x 2
## adult_body_mass_g adult_head_body_len_mm
## <dbl> <dbl>
## 1 492714. NA
## 2 10392. 745.
## 3 9659. 828.
## 4 11989. 872.
## 5 31757. 1055
## 6 800143. 2700
## 7 500000 NA
## 8 635974. 2075
## 9 1117. 355.
## 10 NA NA
## # ... with 5,406 more rows
select(mammals, ends_with("g"))
## # A tibble: 5,416 x 1
## adult_body_mass_g
## <dbl>
## 1 492714.
## 2 10392.
## 3 9659.
## 4 11989.
## 5 31757.
## 6 800143.
## 7 500000
## 8 635974.
## 9 1117.
## 10 NA
## # ... with 5,406 more rows
select(mammals, 1:3)
## # A tibble: 5,416 x 3
## order species adult_body_mass_g
## <chr> <chr> <dbl>
## 1 Artiodactyla Camelus dromedarius 492714.
## 2 Carnivora Canis adustus 10392.
## 3 Carnivora Canis aureus 9659.
## 4 Carnivora Canis latrans 11989.
## 5 Carnivora Canis lupus 31757.
## 6 Artiodactyla Bos frontalis 800143.
## 7 Artiodactyla Bos grunniens 500000
## 8 Artiodactyla Bos javanicus 635974.
## 9 Primates Callicebus cupreus 1117.
## 10 Primates Callicebus discolor NA
## # ... with 5,406 more rows
Zeilen filtern
Die Funktion filter()
ermöglicht es, nach Zeilen eine eine Teilmenge zu filtern. Alle gültigen logischen Operatoren können verwendet werden:
filter(mammals, adult_body_mass_g > 1e7)[ , 1:3]
## # A tibble: 12 x 3
## order species adult_body_mass_g
## <chr> <chr> <dbl>
## 1 Cetacea Caperea marginata 32000000.
## 2 Cetacea Balaenoptera musculus 154321304.
## 3 Cetacea Balaenoptera physalus 47506008.
## 4 Cetacea Balaena mysticetus 79691179.
## 5 Cetacea Balaenoptera borealis 22106252.
## 6 Cetacea Balaenoptera edeni 20000000.
## 7 Cetacea Berardius bairdii 11380000.
## 8 Cetacea Eschrichtius robustus 27324024.
## 9 Cetacea Eubalaena australis 23000000.
## 10 Cetacea Eubalaena glacialis 23000000.
## 11 Cetacea Megaptera novaeangliae 30000000.
## 12 Cetacea Physeter catodon 14540960.
filter(mammals, species == "Balaena mysticetus")
## # A tibble: 1 x 6
## order species adult_body_mass_g adult_head_body~1 home_~2 litte~3
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Cetacea Balaena mysticetus 79691179. 12187. NA 1
## # ... with abbreviated variable names 1: adult_head_body_len_mm,
## # 2: home_range_km2, 3: litter_size
filter(mammals, order == "Carnivora" & adult_body_mass_g < 200)
## # A tibble: 3 x 6
## order species adult_body_mass_g adult_head_body_~1 home_~2 litte~3
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Carnivora Mustela altaica 180. 244. NA 5.44
## 2 Carnivora Mustela frenata 190. 229. 0.21 6.5
## 3 Carnivora Mustela nivalis 78.4 188. 0.07 5.07
## # ... with abbreviated variable names 1: adult_head_body_len_mm,
## # 2: home_range_km2, 3: litter_size
Zeilen anordnen
Mit der Funktion arrange()
können Zeilen nach einer oder mehreren Spalten in aufsteigender oder absteigender Reihenfolge sortiert werden. Ich wähle die ersten drei Spalten nur aus, um die Ausgabe besser lesbar zu machen:
arrange(mammals, adult_body_mass_g)[ , 1:3]
## # A tibble: 5,416 x 3
## order species adult_body_mass_g
## <chr> <chr> <dbl>
## 1 Chiroptera Craseonycteris thonglongyai 1.96
## 2 Chiroptera Kerivoula minuta 2.03
## 3 Soricomorpha Suncus etruscus 2.26
## 4 Soricomorpha Sorex minutissimus 2.46
## 5 Soricomorpha Suncus madagascariensis 2.47
## 6 Soricomorpha Crocidura lusitania 2.48
## 7 Soricomorpha Crocidura planiceps 2.5
## 8 Chiroptera Pipistrellus nanulus 2.51
## 9 Soricomorpha Sorex nanus 2.57
## 10 Soricomorpha Sorex arizonae 2.7
## # ... with 5,406 more rows
arrange(mammals, desc(adult_body_mass_g))[ , 1:3]
## # A tibble: 5,416 x 3
## order species adult_body_mass_g
## <chr> <chr> <dbl>
## 1 Cetacea Balaenoptera musculus 154321304.
## 2 Cetacea Balaena mysticetus 79691179.
## 3 Cetacea Balaenoptera physalus 47506008.
## 4 Cetacea Caperea marginata 32000000.
## 5 Cetacea Megaptera novaeangliae 30000000.
## 6 Cetacea Eschrichtius robustus 27324024.
## 7 Cetacea Eubalaena australis 23000000.
## 8 Cetacea Eubalaena glacialis 23000000.
## 9 Cetacea Balaenoptera borealis 22106252.
## 10 Cetacea Balaenoptera edeni 20000000.
## # ... with 5,406 more rows
arrange(mammals, order, adult_body_mass_g)[ , 1:3]
## # A tibble: 5,416 x 3
## order species adult_body_mass_g
## <chr> <chr> <dbl>
## 1 Afrosoricida Microgale pusilla 3.4
## 2 Afrosoricida Microgale parvula 3.53
## 3 Afrosoricida Geogale aurita 6.69
## 4 Afrosoricida Microgale fotsifotsy 7.7
## 5 Afrosoricida Microgale longicaudata 8.08
## 6 Afrosoricida Microgale brevicaudata 8.99
## 7 Afrosoricida Microgale principula 10.2
## 8 Afrosoricida Microgale drouhardi 10.5
## 9 Afrosoricida Microgale cowani 12.3
## 10 Afrosoricida Microgale taiva 12.4
## # ... with 5,406 more rows
Spalten erstellen
Mit der Funktion mutate()
können neue Spalten (Variablen) hinzufügt werden. Neu erstellte Spalten können auf der Grundlage schon bestehender Spalten erstellt bzw. errechnet werden. Zur besseren Sichtbarmachunug werden die erstelltebn Spalten mit glimpse()
ausgeführt:
glimpse(mutate(mammals, adult_body_mass_kg = adult_body_mass_g / 1000))
## Rows: 5,416
## Columns: 7
## $ order <chr> "Artiodactyla", "Carnivora", "Carnivora", "Carn~
## $ species <chr> "Camelus dromedarius", "Canis adustus", "Canis ~
## $ adult_body_mass_g <dbl> 492714.47, 10392.49, 9658.70, 11989.10, 31756.5~
## $ adult_head_body_len_mm <dbl> NA, 745.32, 827.53, 872.39, 1055.00, 2700.00, N~
## $ home_range_km2 <dbl> 1.963200e+02, 1.010000e+00, 2.950000e+00, 1.888~
## $ litter_size <dbl> 0.98, 4.50, 3.74, 5.72, 4.98, 1.22, 1.00, 1.22,~
## $ adult_body_mass_kg <dbl> 492.71447, 10.39249, 9.65870, 11.98910, 31.7565~
glimpse(mutate(mammals, g_per_mm = adult_body_mass_g / adult_head_body_len_mm))
## Rows: 5,416
## Columns: 7
## $ order <chr> "Artiodactyla", "Carnivora", "Carnivora", "Carn~
## $ species <chr> "Camelus dromedarius", "Canis adustus", "Canis ~
## $ adult_body_mass_g <dbl> 492714.47, 10392.49, 9658.70, 11989.10, 31756.5~
## $ adult_head_body_len_mm <dbl> NA, 745.32, 827.53, 872.39, 1055.00, 2700.00, N~
## $ home_range_km2 <dbl> 1.963200e+02, 1.010000e+00, 2.950000e+00, 1.888~
## $ litter_size <dbl> 0.98, 4.50, 3.74, 5.72, 4.98, 1.22, 1.00, 1.22,~
## $ g_per_mm <dbl> NA, 13.9436618, 11.6717219, 13.7428214, 30.1009~
glimpse(mutate(mammals, g_per_mm = adult_body_mass_g / adult_head_body_len_mm, kg_per_mm = g_per_mm / 1000))
## Rows: 5,416
## Columns: 8
## $ order <chr> "Artiodactyla", "Carnivora", "Carnivora", "Carn~
## $ species <chr> "Camelus dromedarius", "Canis adustus", "Canis ~
## $ adult_body_mass_g <dbl> 492714.47, 10392.49, 9658.70, 11989.10, 31756.5~
## $ adult_head_body_len_mm <dbl> NA, 745.32, 827.53, 872.39, 1055.00, 2700.00, N~
## $ home_range_km2 <dbl> 1.963200e+02, 1.010000e+00, 2.950000e+00, 1.888~
## $ litter_size <dbl> 0.98, 4.50, 3.74, 5.72, 4.98, 1.22, 1.00, 1.22,~
## $ g_per_mm <dbl> NA, 13.9436618, 11.6717219, 13.7428214, 30.1009~
## $ kg_per_mm <dbl> NA, 0.0139436618, 0.0116717219, 0.0137428214, 0~
Spalten zusammenfassen und Datensätze gruppieren
Mit der Funktion summarise()
können zusammenfassende Statistiken aus Spalten berechnet werden. Lediglich die Verwendung von summarise()
ist nicht sehr nützlich, aber in Kombination mit `group_by()´ können Datenblöcke sinnvoll zusammengefasst bzw. gruppiert werden.
summarise(mammals, mean_mass = mean(adult_body_mass_g, na.rm = TRUE))
## # A tibble: 1 x 1
## mean_mass
## <dbl>
## 1 177810.
head(summarise(group_by(mammals, order), mean_mass = mean(adult_body_mass_g, na.rm = TRUE)))
## # A tibble: 6 x 2
## order mean_mass
## <chr> <dbl>
## 1 Afrosoricida 94.8
## 2 Artiodactyla 121329.
## 3 Carnivora 47386.
## 4 Cetacea 7373065.
## 5 Chiroptera 57.7
## 6 Cingulata 4699.
Befehle aneinanderreihen
Sog. Pipes übernehmen die Ausgabe einer Funktion und leiten sie an das erste Argument der nächsten Funktion weiter. Das “magrittr
Paket enthält die Pipe-Funktion %>%
(s. ?magrittr::%>%
).
Pipes können für die Aneinanderreihung fast jeder Funktionen verwendet werden:
x <- rnorm(10)
x %>% max()
## [1] 1.10178
#Das gleiche Resultat liefert:
max(x)
## [1] 1.10178
Nun wird das Dataframe der Säugetiere an das erste Argument der Funktion arrange
übergeben und die Anordnung über die Spalte adult_body_mass_g
gewählt:
mammals %>% arrange(adult_body_mass_g)
## # A tibble: 5,416 x 6
## order species adult_body~1 adult~2 home_~3 litte~4
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Chiroptera Craseonycteris thonglongyai 1.96 31.0 NA 1
## 2 Chiroptera Kerivoula minuta 2.03 NA NA NA
## 3 Soricomorpha Suncus etruscus 2.26 NA NA 4
## 4 Soricomorpha Sorex minutissimus 2.46 52.0 NA 8.99
## 5 Soricomorpha Suncus madagascariensis 2.47 NA NA NA
## 6 Soricomorpha Crocidura lusitania 2.48 31.0 NA NA
## 7 Soricomorpha Crocidura planiceps 2.5 NA NA 3
## 8 Chiroptera Pipistrellus nanulus 2.51 NA NA 1.96
## 9 Soricomorpha Sorex nanus 2.57 52 NA 6.49
## 10 Soricomorpha Sorex arizonae 2.7 58.0 NA NA
## # ... with 5,406 more rows, and abbreviated variable names
## # 1: adult_body_mass_g, 2: adult_head_body_len_mm, 3: home_range_km2,
## # 4: litter_size
arrange(mammals, adult_body_mass_g) ### without pipe
## # A tibble: 5,416 x 6
## order species adult_body~1 adult~2 home_~3 litte~4
## <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 Chiroptera Craseonycteris thonglongyai 1.96 31.0 NA 1
## 2 Chiroptera Kerivoula minuta 2.03 NA NA NA
## 3 Soricomorpha Suncus etruscus 2.26 NA NA 4
## 4 Soricomorpha Sorex minutissimus 2.46 52.0 NA 8.99
## 5 Soricomorpha Suncus madagascariensis 2.47 NA NA NA
## 6 Soricomorpha Crocidura lusitania 2.48 31.0 NA NA
## 7 Soricomorpha Crocidura planiceps 2.5 NA NA 3
## 8 Chiroptera Pipistrellus nanulus 2.51 NA NA 1.96
## 9 Soricomorpha Sorex nanus 2.57 52 NA 6.49
## 10 Soricomorpha Sorex arizonae 2.7 58.0 NA NA
## # ... with 5,406 more rows, and abbreviated variable names
## # 1: adult_body_mass_g, 2: adult_head_body_len_mm, 3: home_range_km2,
## # 4: litter_size
Angenommen, die Art mit dem höchsten Verhältnis von Körpergewicht zu Länge wird gesucht:
#(Pfeife)
mammals %>%
mutate(mass_to_length = adult_body_mass_g / adult_head_body_len_mm) %>%
arrange(desc(mass_to_length)) %>%
select(species, mass_to_length)
## # A tibble: 5,416 x 2
## species mass_to_length
## <chr> <dbl>
## 1 Balaena mysticetus 6539.
## 2 Balaenoptera musculus 5063.
## 3 Megaptera novaeangliae 2334.
## 4 Eschrichtius robustus 2309.
## 5 Balaenoptera physalus 2302.
## 6 Elephas maximus 1704.
## 7 Eubalaena glacialis 1654.
## 8 Eubalaena australis 1625.
## 9 Balaenoptera edeni 1444.
## 10 Balaenoptera borealis 1203.
## # ... with 5,406 more rows
#Das gleiche Resultat liefert (Matrjoschka) / without pipe:
select(
arrange(
mutate(mammals, mass_to_length = adult_body_mass_g / adult_head_body_len_mm),
desc(mass_to_length)),
species, mass_to_length)
## # A tibble: 5,416 x 2
## species mass_to_length
## <chr> <dbl>
## 1 Balaena mysticetus 6539.
## 2 Balaenoptera musculus 5063.
## 3 Megaptera novaeangliae 2334.
## 4 Eschrichtius robustus 2309.
## 5 Balaenoptera physalus 2302.
## 6 Elephas maximus 1704.
## 7 Eubalaena glacialis 1654.
## 8 Eubalaena australis 1625.
## 9 Balaenoptera edeni 1444.
## 10 Balaenoptera borealis 1203.
## # ... with 5,406 more rows
Mit Zeitreihen arbeiten
Auf den ersten Blick erscheinen Angaben zum Datum und der Uhrzeit simple. Man verwendet sie ständig im normalen Leben. Je mehr man sich jedoch mit ihnen auseinandersetzt, desto komplizierter scheinen sie zu werden, z.B.: * Hat jedes Jahr 365 Tage? * Hat jeder Tag 24 Stunden Zeit? * Hat jede Minute 60 Sekunden?
Das Paket “lubridate” hilft mit ebensolchen Besonderheiten umzugehen und standardisiert Datums- bzw. Zeitangaben.
Ein tibble Dataframe kennt drei Typen von Datums- bzw. Zeitangaben
* Eine Datumsangabe (als
Um das aktuelle Datum oder die aktuelle Uhrzeit zu erhalten, kann today()
oder now()
verwendet werden:
today()
## [1] "2022-11-07"
now()
## [1] "2022-11-07 10:57:54 CET"
Ansonsonsten existieren drei Möglichkeiten, um eine Datums- bzw. Uhrzeitsangabe zu erstellen: * Aus einer Zeichenkette. * Aus einzelnen Datum-Uhrzeit-Komponenten. * Aus einem vorhandenen Datum-Uhrzeit-Objekt.
Aus einer Zeichenkette
ymd("2017-01-31")
## [1] "2017-01-31"
mdy("January 31st, 2017")
## [1] "2017-01-31"
dmy("31-Jan-2017")
## [1] "2017-01-31"
ymd(20170131)
## [1] "2017-01-31"
ymd_hms("2017-01-31 20:11:59")
## [1] "2017-01-31 20:11:59 UTC"
mdy_hm("01/31/2017 08:01")
## [1] "2017-01-31 08:01:00 UTC"
ymd(20170131, tz = "UTC")
## [1] "2017-01-31 UTC"
Aus einzelnen Datum-Uhrzeit-Komponenten
flights %>%
select(year, month, day, hour, minute)
## # A tibble: 336,776 x 5
## year month day hour minute
## <int> <int> <int> <dbl> <dbl>
## 1 2013 1 1 5 15
## 2 2013 1 1 5 29
## 3 2013 1 1 5 40
## 4 2013 1 1 5 45
## 5 2013 1 1 6 0
## 6 2013 1 1 5 58
## 7 2013 1 1 6 0
## 8 2013 1 1 6 0
## 9 2013 1 1 6 0
## 10 2013 1 1 6 0
## # ... with 336,766 more rows
flights %>%
select(year, month, day, hour, minute) %>%
mutate(departure = make_datetime(year, month, day, hour, minute))
## # A tibble: 336,776 x 6
## year month day hour minute departure
## <int> <int> <int> <dbl> <dbl> <dttm>
## 1 2013 1 1 5 15 2013-01-01 05:15:00
## 2 2013 1 1 5 29 2013-01-01 05:29:00
## 3 2013 1 1 5 40 2013-01-01 05:40:00
## 4 2013 1 1 5 45 2013-01-01 05:45:00
## 5 2013 1 1 6 0 2013-01-01 06:00:00
## 6 2013 1 1 5 58 2013-01-01 05:58:00
## 7 2013 1 1 6 0 2013-01-01 06:00:00
## 8 2013 1 1 6 0 2013-01-01 06:00:00
## 9 2013 1 1 6 0 2013-01-01 06:00:00
## 10 2013 1 1 6 0 2013-01-01 06:00:00
## # ... with 336,766 more rows
make_datetime_100 <- function(year, month, day, time) {
make_datetime(year, month, day, time %/% 100, time %% 100)
}
flights_dt <- flights %>%
filter(!is.na(dep_time), !is.na(arr_time)) %>%
mutate(
dep_time = make_datetime_100(year, month, day, dep_time),
arr_time = make_datetime_100(year, month, day, arr_time),
sched_dep_time = make_datetime_100(year, month, day, sched_dep_time),
sched_arr_time = make_datetime_100(year, month, day, sched_arr_time)
) %>%
select(origin, dest, ends_with("delay"), ends_with("time"))
flights_dt
## # A tibble: 328,063 x 9
## origin dest dep_delay arr_delay dep_time sched_dep_time
## <chr> <chr> <dbl> <dbl> <dttm> <dttm>
## 1 EWR IAH 2 11 2013-01-01 05:17:00 2013-01-01 05:15:00
## 2 LGA IAH 4 20 2013-01-01 05:33:00 2013-01-01 05:29:00
## 3 JFK MIA 2 33 2013-01-01 05:42:00 2013-01-01 05:40:00
## 4 JFK BQN -1 -18 2013-01-01 05:44:00 2013-01-01 05:45:00
## 5 LGA ATL -6 -25 2013-01-01 05:54:00 2013-01-01 06:00:00
## 6 EWR ORD -4 12 2013-01-01 05:54:00 2013-01-01 05:58:00
## 7 EWR FLL -5 19 2013-01-01 05:55:00 2013-01-01 06:00:00
## 8 LGA IAD -3 -14 2013-01-01 05:57:00 2013-01-01 06:00:00
## 9 JFK MCO -3 -8 2013-01-01 05:57:00 2013-01-01 06:00:00
## 10 LGA ORD -2 8 2013-01-01 05:58:00 2013-01-01 06:00:00
## # ... with 328,053 more rows, and 3 more variables: arr_time <dttm>,
## # sched_arr_time <dttm>, air_time <dbl>
#Mit diesen Daten kann die Verteilung der Abfahrtszeiten über das Jahr visualisiert werden:
flights_dt %>%
ggplot(aes(dep_time)) +
geom_freqpoly(binwidth = 86400) # 86400 seconds = 1 day
#Or within a single day:
flights_dt %>%
filter(dep_time < ymd(20130102)) %>%
ggplot(aes(dep_time)) +
geom_freqpoly(binwidth = 600) # 600 s = 10 minutes
Aus einem vorhandenen Datum-Uhrzeit-Objekt.
as_datetime(today())
## [1] "2022-11-07 UTC"
as_date(now())
## [1] "2022-11-07"
Mit den Funktionen year()
, month()
, mday()
(Tag des Monats), yday()
(Tag des Jahres), wday()
(Tag der Woche), hour()
, minute()
und second()
können einzelne Teile des Datums exrahiert werden:
datetime <- ymd_hms("2016-07-08 12:34:56")
year(datetime)
## [1] 2016
month(datetime)
## [1] 7
mday(datetime)
## [1] 8
yday(datetime)
## [1] 190
wday(datetime)
## [1] 6
Datumsarithmetik
Die Arithmetik im Umgang mit Datums- bzw. Uhrzeitsangabe umfasst Subtraktion, Addition und Division. Das Paket “lubridate” kennt drei wichtige Klassen, die Zeitspannen darstellen: * Dauer, die eine genaue Anzahl von Sekunden darstellen. * Perioden, die menschliche Einheiten wie Wochen und Monate darstellen. * Intervalle, die einen Start- und Endpunkt darstellen.
#Dauer
h_age <- today() - ymd(19791014)
h_age
## Time difference of 15730 days
as.duration(h_age)
## [1] "1359072000s (~43.07 years)"
#Perioden
one_pm <- ymd_hms("2016-03-12 13:00:00", tz="America/New_York")
one_pm
## [1] "2016-03-12 13:00:00 EST"
one_pm + days(1)
## [1] "2016-03-13 13:00:00 EDT"
#Intervalle
years(1) / days(1)
## [1] 365.25
next_year <- today() + years(1)
(today() %--% next_year) / ddays(1)
## [1] 365
(today() %--% next_year) %/% days(1)
## [1] 365
Übungen
Hierzu noch ein Fragen zur Übung:
* Warum gibt es months()
, aber keine dmonths()?
* Erklären Sie, wie days(overnight x 1)
funktioniert?
* Erstellen Sie einen Vektor von Daten, der den ersten Tag eines jeden Monats im Jahr 2015 angibt und einen Vektor von Daten, der den ersten Tag eines jeden Monats im aktuellen Jahr angibt.
* Schreiben Sie eine Funktion, die Ihren Geburtstag (als Datum) angibt und berechnet wie alt Sie in Jahren sind.
* Warum funktioniert (today() %--% (today() + years(1)) / months(1)
nicht?
In R ist die Zeitzone ein Attribut der Datums- bzw. Uhrzeitangabe, das ergänzend angegeben wird. Zum Beispiel repräsentieren diese drei Objekte den gleichen Zeitpunkt in der Zeit:
(x1 <- ymd_hms("2015-06-01 12:00:00", tz = "America/New_York"))
## [1] "2015-06-01 12:00:00 EDT"
(x2 <- ymd_hms("2015-06-01 18:00:00", tz = "Europe/Copenhagen"))
## [1] "2015-06-01 18:00:00 CEST"
(x3 <- ymd_hms("2015-06-02 04:00:00", tz = "Pacific/Auckland"))
## [1] "2015-06-02 04:00:00 NZST"
Durch Subtraktion kann geprüft werden, ob sie gleich sind:
x1 - x2
## Time difference of 0 secs
x1 - x3
## Time difference of 0 secs
“lubridate” verwendet immer UTC (Coordinated Universal Time), sofern nicht anderrs angegeben. Es hat keine Sommerzeit, was eine bequeme Darstellung für die Berechnung darstellt. Operationen, die Datumszeiten kombinieren, wie c()
, lassen die Zeitzone oft fallen. In diesem Fall werden die Datumszeiten in Ihrer lokalen Zeitzone angezeigt:
x4 <- c(x1, x2, x3)
x4
## [1] "2015-06-01 12:00:00 EDT" "2015-06-01 12:00:00 EDT"
## [3] "2015-06-01 12:00:00 EDT"
Zeitzonen können auf zwei Wegen geändert werden:
#Anzeige soll angepasst werden; Zeitzone mit angeben
x4a <- with_tz(x4, tzone = "Australia/Lord_Howe")
x4a
## [1] "2015-06-02 02:30:00 +1030" "2015-06-02 02:30:00 +1030"
## [3] "2015-06-02 02:30:00 +1030"
x4a - x4
## Time differences in secs
## [1] 0 0 0
#Der zugrunde liegenden Zeitpunkt in der Zeitangabe soll geändert werden.
x4b <- force_tz(x4, tzone = "Australia/Lord_Howe")
x4b
## [1] "2015-06-01 12:00:00 +1030" "2015-06-01 12:00:00 +1030"
## [3] "2015-06-01 12:00:00 +1030"
x4b - x4
## Time differences in hours
## [1] -14.5 -14.5 -14.5