Datumsangaben, Zeitpunkte und Uhrzeiten in R
Bei der Datenanalyse arbeitet man häufig mit Datumsangaben und Zeiten. Sie werden außerdem genutzt, um Trends, Überleben und vieles mehr zu untersuchen. Jeder Datenanalytiker muss mit Datums- und Zeitvariablen umgehen können. Tatsächlich lassen sich Datums- und Zeitvariablen wie numerische Variablen behandeln: Jedem Datum bzw. jeder Zeit kann ein numerischer Wert zugeordnet werden, der dann in verschiedenen Operationen verwendet werden kann. Um einem bestimmten Datum bzw. Zeitpunkt einen numerischen Wert zuzuordnen, muss ein anderes Datum als Referenzdatum oder Startpunkt dienen. In R ist dieses Datum auf 1970-01-01 00:00:00 GMT festgelegt. Jedes spätere Datum bzw. jede spätere Zeit lässt sich dann als Anzahl der Tage, Stunden oder Sekunden berechnen, die seit dem Startpunkt vergangen sind. Selbstverständlich können Sie das Referenzdatum ändern, doch das ist selten notwendig.
Um mit Datumsangaben und Zeiten als numerischen Variablen zu arbeiten, verwendet R atomare Vektoren der Klasse POSIXct oder POSIXt, die eigentlich Doubles sind. Obwohl diese Vektortypen tatsächlich numerische Werte sind, können Sie sie mithilfe von Strings definieren. Beginnen wir damit, zwei atomare Vektoren mit Datumsangaben zu erzeugen:
## Wir erzeugen zwei einfache Zeichenvektoren
birth_date <- c("1990-01-01", "1999-01-04", "2002-05-05", "2001-12-12")
death_date <- c("2005-02-02", "2009-11-14", "2018-01-01", "2011-11-09")
class(birth_date)## [1] "character"class(death_date)## [1] "character"R gibt an, dass beide Vektoren vom Typ character sind, wie wir erwartet haben. Wandeln wir diese Zeichenvektoren mithilfe von Funktionen aus Base R (also den Grundfunktionen von R) in Datumsvektoren um:
birth_date <- as.POSIXct(birth_date)
death_date <- as.POSIXct(death_date)## Ergebnis für birth_date anzeigen
birth_date## [1] "1990-01-01 CET" "1999-01-04 CET" "2002-05-05 CEST" "2001-12-12 CET"## Ergebnis für death_date anzeigen
death_date## [1] "2005-02-02 CET" "2009-11-14 CET" "2018-01-01 CET" "2011-11-09 CET"## Klasse prüfen
class(birth_date)## [1] "POSIXct" "POSIXt"## Klasse prüfen
class(death_date)## [1] "POSIXct" "POSIXt"Die Zeitdifferenz zwischen Geburt und Tod können wir mit der Funktion difftime() berechnen:
difftime(death_date, birth_date)## Time differences in days
## [1] 5511.000 3967.000 5720.042 3619.0005511.000 ist die Zeitdifferenz zwischen dem ersten Element in birth_date (1990-01-01) und dem ersten Element in death_date (2005-02-02 CET). 3967.000 ist die Zeitdifferenz zwischen dem zweiten Element in birth_date (1999-01-04 CET) und dem zweiten Element in death_date (2009-11-14 CET), und so weiter.
R hat die Zeichenstrings in Datums-Zeit-Werte mit den Klassen POSIXct und POSIXt umgewandelt. Mit POSIXct wird jedes Datum als Anzahl der Sekunden dargestellt, die seit 12:00 Uhr UTC (Universal Time Coordinated) am 1. Januar 1970 vergangen sind. difftime() berechnet die Zeitdifferenz jedoch in Tagen, was eine Standardeinstellung ist. Sie können dies ändern. Wenn Sie die Zeitdifferenz z. B. in Sekunden haben möchten, schreiben Sie:
difftime(death_date, birth_date, units="secs")## Time differences in secs
## [1] 476150400 342748800 494211600 312681600Betrachten Sie noch einmal den folgenden Befehl:
## Ergebnis für death_date
death_date## [1] "2005-02-02 CET" "2009-11-14 CET" "2018-01-01 CET" "2011-11-09 CET"Aus der Ausgabe geht hervor, dass R Zeitzonen hinzugefügt hat; CET ist die Mitteleuropäische Zeit. Das war etwas unerwartet, und tatsächlich können die Base-R-Funktionen für den Umgang mit Datumsangaben und Zeiten kompliziert oder sogar problematisch sein. Deshalb haben Garrett Grolemund, Hadley Wickham und Vitalie Spinu das Package lubridate entwickelt, das den Umgang mit Datumsangaben und Zeiten sehr einfach macht. Installieren und laden wir das Package:
## Zunächst lubridate installieren
install.packages("lubridate")
## Das Package laden, damit seine Funktionen verwendet werden können
library(lubridate)## Attaching package: 'lubridate'## The following object is masked from 'package:base':
##
## dateLubridate speichert Datumsangaben als Anzahl der Tage seit 1970-01-01. Das konkrete Datum 18000 Tage nach 1970-01-01 erhalten Sie mit folgendem Befehl:
as_date(18000)## [1] "2019-04-14"18000 Tage nach 1970-01-01 landen wir beim Datum 2019-04-04.
Speichern wir einige Datumswerte mit lubridate. Dafür gibt es in lubridate viele Funktionen. Das Prinzip für ihre Verwendung ist folgendes:
- Bestimmen Sie die Reihenfolge von Jahr (y), Monat (m), Tag (d), Stunde (h), Minute (m) und Sekunden (s) im Datumsstring.
- Verwenden Sie die passende Funktion, deren Reihenfolge der Elemente zu Ihren Daten passt.
Beispiel:
- Wir haben Datumsangaben im Format „1990-01-01“, das Format ist also „YYYY-MM-DD“. Die Reihenfolge lautet somit Y, M, D.
- Die passende lubridate-Funktion heißt:
ymd(). - Die Funktion
ymd()erzeugt aus Ihrem String einen Datumsvektor.
Probieren wir das aus, indem wir einen Data Frame mit 3 Personen erstellen, der ihre Namen, Geburtsdaten, Operationsdaten und Sterbedaten enthält. Alle Datumsangaben erhalten unterschiedliche Trennzeichen, um zu testen, ob die Funktion ymd() verschiedene Varianten von Datumsangaben verstehen kann:
## Unsere Vektoren (Variablen) erzeugen
names <- c("David", "Mohammed", "Christina")
birth <- ymd("1990-01-01", "1999-01-04", "2002-05-05")
operation <- ymd("1990.01.01", "1999.01.04", "2002.05.05")
death <- ymd("2005/02/02", "2009/11/14", "2018/01/01")
## Combine the vectors into a data frame
my_data <- data.frame(names, birth, operation, death)
## View the data frame
my_data## names birth operation death
## 1 David 1990-01-01 1990-01-01 2005-02-02
## 2 Mohammed 1999-01-04 1999-01-04 2009-11-14
## 3 Christina 2002-05-05 2002-05-05 2018-01-01Wie Sie in der obigen Ausgabe sehen, hat R die verschiedenen Datumsformate erkannt. Nun ändern wir die Reihenfolge von Jahr, Monat und Tag. Dabei müssen wir die Funktion wechseln, sodass wir eine Funktion verwenden, die versteht, in welcher Reihenfolge Jahr, Monat und Tag im String vorkommen:
## Datumsstring in der Reihenfolge Tag, Monat und Jahr
dmy("30-01-2000", "25-12-2001")## [1] "2000-01-30" "2001-12-25"## Datumsstring in der Reihenfolge Monat, Tag, Jahr
mdy("12-25-1999", "09-29-2004")## [1] "1999-12-25" "2004-09-29"## Datumsstring in der Reihenfolge Jahr, Monat, Tag
ymd("20181230", "20191129")## [1] "2018-12-30" "2019-11-29"Auch hier hat R die Datumsangaben korrekt interpretiert. In lubridate gibt es viele weitere Funktionen für den Umgang mit Datumsangaben. Sie können das Cheat Sheet für lubridate herunterladen.
Im nächsten Beispiel speichern wir ein Datum, das eine Uhrzeit enthält. Um es korrekt zu interpretieren, verwenden wir eine Funktion, die auch h (Stunden), m (Minuten) und s (Sekunden) verarbeiten kann:
ymd_hms("2011-06-04 12:00:00")## [1] "2011-06-04 12:00:00 UTC"Sie sehen, dass R dem Datum die Zeitzone UTC zugewiesen hat. R kann etwa 600 Zeitzonen verarbeiten, für die jeweils Informationen über die Zeitzone, die Sommerzeit und historische Kalendervariationen des Gebiets vorliegen. R weist jedem Vektor eine Zeitzone zu. Eine Liste aller Zeitzonen erhalten Sie, indem Sie den folgenden Befehl ausführen (aus Platzgründen werden nur die ersten 20 Zeitzonen angezeigt):
OlsonNames()## [1] "Africa/Abidjan" "Africa/Accra"
## [3] "Africa/Addis_Ababa" "Africa/Algiers"
## [5] "Africa/Asmara" "Africa/Asmera"
## [7] "Africa/Bamako" "Africa/Bangui"
## [9] "Africa/Banjul" "Africa/Bissau"
## [11] "Africa/Blantyre" "Africa/Brazzaville"
## [13] "Africa/Bujumbura" "Africa/Cairo"
## [15] "Africa/Casablanca" "Africa/Ceuta"
## [17] "Africa/Conakry" "Africa/Dakar"
## [19] "Africa/Dar_es_Salaam" "Africa/Djibouti"Erzeugen wir einen Datumsvektor, bei dem wir die Zeitzone auf die US-Pazifikregion festlegen:
ymd_hms("2011-06-04 12:00:00", tz="US/Pacific")## [1] "2011-06-04 12:00:00 PDT"Zeitintervalle in R berechnen
Erstellen wir einige Daten mit 3 Personen und ihren Geburts- und Sterbedaten:
## Vektoren erzeugen
names <- c("David", "Mohammed")
birth <- ymd("1990-01-01", "1999-01-04")
death <- ymd("2005/02/02", "2009/11/14")
## Vektoren zu einem Data Frame kombinieren
my_data <- data.frame(names, birth, death)
## Data Frame anzeigen
my_data## names birth death
## 1 David 1990-01-01 2005-02-02
## 2 Mohammed 1999-01-04 2009-11-14Wir möchten in unserem Data Frame my_data eine neue Variable bzw. einen neuen Vektor oder eine neue Spalte erstellen. Die neue Variable, die wir dayslived nennen, soll die Zeitdifferenz zwischen Geburts- und Sterbedatum sein.
## Zeitdifferenz durch Subtraktion berechnen
my_data$dayslived <- my_data$death-my_data$birth
## Daten anzeigen
my_data## names birth death dayslived
## 1 David 1990-01-01 2005-02-02 5511 days
## 2 Mohammed 1999-01-04 2009-11-14 3967 daysMit der Funktion interval() können wir ein Zeitintervall definieren, das anschließend für verschiedene Vergleiche verwendet werden kann. Erstellen wir eine Zeitintervallvariable und nennen sie time_interval:
my_data$time_interval <- interval(my_data$birth, my_data$death)
my_dataDas Ergebnis ist dasselbe, was Sie selbst überprüfen können.
Prüfen wir, ob David und Mohammed während des Zweiten Weltkriegs gelebt haben.
## Beginn des Zweiten Weltkriegs definieren:
ww2start <- ymd_hms("1939-01-01 00:00:00")
## Ende des Zweiten Weltkriegs definieren:
ww2end <- ymd_hms("1945-12-31 00:00:00")
## Ein Zeitintervall definieren
ww2interval <- interval(ww2start, ww2end)
#Prüfen, ob sich die Zeitintervalle überschneiden (d. h. ob David und Mohammed während des Zweiten Weltkriegs gelebt haben:
int_overlaps(my_data$time_interval, ww2interval)## 1 FALSE
## 2 FALSEOffenbar hat keiner von beiden während des Zweiten Weltkriegs gelebt, da das Ergebnis sowohl für David als auch für Mohammed FALSE war.
Durations
Eine Duration ist die Zeitdifferenz zwischen zwei Zeitpunkten. Durations berechnen Sie mit lubridate, indem Sie Datumsangaben subtrahieren, wie das Beispiel zeigt:
ymd("2018-01-01") - ymd("1999-01-04")## Time difference of 6937 daysPerioden
Mit einfachen Funktionen können Sie Perioden addieren oder subtrahieren, und zwar wie folgt:
ymd(20110101) + years(1)## [1] "2012-01-01"ymd(20110101) + months(12)## [1] "2012-01-01"ymd(20110101) - days(2)## [1] "2010-12-30"ymd(20110101) - seconds(2000)## [1] "2010-12-31 23:26:40 UTC"