Python, Pandas und Zeitserien

Einführung

Time Series Pandas

In unserem nächsten Kapitel des Pandas-Tutorial behandeln wir Time Series. Eine Time Series ist eine Reihe von Datenpunkten, welche in chronologischer (zeitlicher) Reihenfolge gelistet (indiziert) sind. Für gewöhnlich ist eine Time Series eine Sequenz von Werten, mit gleichen zeitlichen Abständen.

Alle gemessenen Daten, die auch mit einem bestimmten Zeitpunkt in Verbindung stehen, können als Time Series angesehen werden. Messungen können durchaus unregelmäßig sein, haben aber in den meisten Fällen eine feste Frequenz bzw. Regelmässigkeit. D.h. dass Daten bspw. alle 5 Millisekunden, alle 10 Sekunden oder jede Stunde erhoben werden. Time Series werden oft in Liniencharts dargestellt.

Bevor Sie fortfahren möchten wir ihnen noch unser Tutorial empfehlen zum Thema Time Processing mit Standard Python-Modulen, wie z.B. datetime, time und calendar.

Wir wollen in diesem Kapitel die Pandas-Tools vorstellen um mit Time Series umzugehen. Sie werden also lernen mit grossen Time Series zu arbeiten und diese zu modifizieren:

Zeitreihen und Python

Wir können eine Pandas-Series definieren, welche als Index eine Reihe von Zeitstempeln enthält:

import numpy as np
import pandas as pd
from datetime import datetime, timedelta as delta
ndays = 10
start = datetime(2018, 12, 1)
dates = [start - delta(days = x) for x in range(0, ndays)]
values = [25, 50, 15, 67, 70, 9, 28, 30, 32, 12]
ts = pd.Series(values, index = dates)
print(ts)
2018-12-01    25
2018-11-30    50
2018-11-29    15
2018-11-28    67
2018-11-27    70
2018-11-26     9
2018-11-25    28
2018-11-24    30
2018-11-23    32
2018-11-22    12
dtype: int64

Wir ermitteln den Typ der soeben erstellen Time-Series:

print(type(ts))
<class 'pandas.core.series.Series'>

Was wir erzeugt haben ist eine Zeitreihe oder Time-Series, weil es auf den Series von Pandas basiert. Wie sieht der Index dieser Time-Series aus? Wir sehen es hier:

print(ts.index)
DatetimeIndex(['2018-12-01', '2018-11-30', '2018-11-29', '2018-11-28',
               '2018-11-27', '2018-11-26', '2018-11-25', '2018-11-24',
               '2018-11-23', '2018-11-22'],
              dtype='datetime64[ns]', freq=None)

Wir erstellen eine weitere Time-Series:

values2 = [32, 54, 18, 61, 72, 19, 21, 33, 29, 17]
ts2 = pd.Series(values2, index=dates)

Es ist möglich arithmetische Operationen auf Zeitreihen durchzuführen, wie bei anderen Series-Objekten auch. Als Beispiel addieren wir die beiden zuvor erstellten Time-Series:

print(ts + ts2)
2018-12-01     57
2018-11-30    104
2018-11-29     33
2018-11-28    128
2018-11-27    142
2018-11-26     28
2018-11-25     49
2018-11-24     63
2018-11-23     61
2018-11-22     29
dtype: int64

Arithmetischer Durchschnitt der beiden Series-Objekte:

print((ts + ts2) / 2)
2018-12-01    28.5
2018-11-30    52.0
2018-11-29    16.5
2018-11-28    64.0
2018-11-27    71.0
2018-11-26    14.0
2018-11-25    24.5
2018-11-24    31.5
2018-11-23    30.5
2018-11-22    14.5
dtype: float64

Dies kann auch mit Series-Objekten gemacht werden, die eine andere Indexierung haben.

import pandas as pd
from datetime import datetime, timedelta as delta
ndays = 10
start = datetime(2018, 6, 1)
dates = [start - delta(days=x) for x in range(0, ndays)]
start2 = datetime(2018, 5, 28)
dates2 = [start2 - delta(days=x) for x in range(0, ndays)]
values = [25, 50, 15, 67, 70, 9, 28, 30, 32, 12]
values2 = [32, 54, 18, 61, 72, 19, 21, 33, 29, 17]
ts = pd.Series(values, index = dates)
ts2 = pd.Series(values2, index = dates2)
print(ts + ts2)
2018-05-19      NaN
2018-05-20      NaN
2018-05-21      NaN
2018-05-22      NaN
2018-05-23     31.0
2018-05-24    104.0
2018-05-25     91.0
2018-05-26     46.0
2018-05-27     63.0
2018-05-28    102.0
2018-05-29      NaN
2018-05-30      NaN
2018-05-31      NaN
2018-06-01      NaN
dtype: float64

Datums-Bereiche erstellen

Die Methode date_range() aus dem Pandas-Modul kann für die Erstellung eines Datumsstempel-Index verwendet werden:

import pandas as pd
index = pd.date_range('12/24/1970', '01/03/1971')
print(index)
DatetimeIndex(['1970-12-24', '1970-12-25', '1970-12-26', '1970-12-27',
               '1970-12-28', '1970-12-29', '1970-12-30', '1970-12-31',
               '1971-01-01', '1971-01-02', '1971-01-03'],
              dtype='datetime64[ns]', freq='D')

Wir haben ein Start- und ein Ende-Datum an die date_range-Methode übergeben. Ebenso ist es möglich nur einen Start oder nur ein Ende zu übergeben. In diesem Fall muss jedoch die Anzahl der Perioden, über den Schlüsselwort-Parameter periods, angegeben werden:

index = pd.date_range(start='12/24/1970', periods=7)
print(index)
DatetimeIndex(['1970-12-24', '1970-12-25', '1970-12-26', '1970-12-27',
               '1970-12-28', '1970-12-29', '1970-12-30'],
              dtype='datetime64[ns]', freq='D')
index = pd.date_range(end='12/24/1970', periods=7)
print(index)
DatetimeIndex(['1970-12-18', '1970-12-19', '1970-12-20', '1970-12-21',
               '1970-12-22', '1970-12-23', '1970-12-24'],
              dtype='datetime64[ns]', freq='D')

Ebenso ist es möglich Zeitreihen zu erstellen, welche nur die Arbeitstage beinhalten. Dazu muss der Schlüsselwort-Paremter freq auf B gesetzt werden:

index = pd.date_range('2017-04-07', '2017-04-13', freq="B")
print(index)
DatetimeIndex(['2017-04-07', '2017-04-10', '2017-04-11', '2017-04-12',
               '2017-04-13'],
              dtype='datetime64[ns]', freq='B')

Im nächsten Beispiel generieren wir eine Zeitreihe, welche die Monatsenden zwischen zwei Zeitpunkten enthält. Dabei sehen wir, dass das Jahr 2016 den 29. Februar hatte, weil es ein Schaltjahr war:

index = pd.date_range('2016-02-25', '2016-07-02', freq="M")
print(index)
DatetimeIndex(['2016-02-29', '2016-03-31', '2016-04-30', '2016-05-31',
               '2016-06-30'],
              dtype='datetime64[ns]', freq='M')

Weitere Abkürzungen:

Alias Description
B business day frequency
C custom business day frequency (experimental)
D calendar day frequency
W weekly frequency
M month end frequency
BM business month end frequency
MS month start frequency
BMS business month start frequency
Q quarter end frequency
BQ business quarter endfrequency
QS quarter start frequency
BQS business quarter start frequency
A year end frequency
BA business year end frequency
AS year start frequency
BAS business year start frequency
H hourly frequency
T minutely frequency
S secondly frequency
L milliseonds
U microseconds
index = pd.date_range('2017-02-05', '2017-04-13', freq="W-Mon")
print(index)
DatetimeIndex(['2017-02-06', '2017-02-13', '2017-02-20', '2017-02-27',
               '2017-03-06', '2017-03-13', '2017-03-20', '2017-03-27',
               '2017-04-03', '2017-04-10'],
              dtype='datetime64[ns]', freq='W-MON')