【時系列データ】pandasを使って特定のタイムスタンプを抽出し比較する


投稿日 2021年12月30日 >> 更新日 2023年3月1日

概要

時系列データで特定の範囲を抽出したり、月ごとの特定の日にちや曜日を抽出し比較する。例えば、1月~12月の火曜日のデータだけを抽出して見比べてみたり、第3水曜日のデータだけを抽出して見比べてみたりと、特定のタイムスタンプを抽出する。

実行環境&使用ライブラリ

実行環境
Windows Subsystem for Linux
Python 3.6.9
pip 9.0.1
jupyter notebook
使用ライブラリ ライセンス
pandas==1.0.0 BSD

時系列データの生成

pandasのdate_range関数を使って2020年1月~2021年12月までの時系列データを作成する。

import pandas as pd

dates = pd.date_range(start='2020-1-1', end='2021-12-31')
df = pd.DataFrame(range(len(dates)), index=dates, columns=['Value'])
df.head()
"""
           Value
2020-01-01  0
2020-01-02  1
2020-01-03  2
2020-01-04  3
2020-01-05  4
"""

df.tail()
"""
           Value
2021-12-27  726
2021-12-28  727
2021-12-29  728
2021-12-30  729
2021-12-31  730
"""

中身のデータは単純に0~2年分の長さの数を埋めただけです。

df.plot(figsize=(15, 8))

特定の西暦、月、日、曜日を抽出する

西暦

抽出したい西暦をインデックス参照するだけで取り出せます。

# 2021年のデータを抽出
df['2021']
"""
           Value
2021-01-01  366
2021-01-02  367
2021-01-03  368
2021-01-04  369
2021-01-05  370
... ...
2021-12-27  726
2021-12-28  727
2021-12-29  728
2021-12-30  729
2021-12-31  730
"""

スライスで特定の範囲を抽出する

# 2020年7月~2021年2月までのデータを抽出
df['2020-7':'2021-2']
"""
           Value
2020-07-01  182
2020-07-02  183
2020-07-03  184
2020-07-04  185
2020-07-05  186
... ...
2021-02-24  420
2021-02-25  421
2021-02-26  422
2021-02-27  423
2021-02-28  424
"""

真偽値を使用してインデックス参照する。

datetimeオブジェクトだと、西暦、月、日、曜日などを細かく取り出すことができる。

print(df.index)
"""
DatetimeIndex(['2020-01-01', '2020-01-02', '2020-01-03', '2020-01-04',
               '2020-01-05', '2020-01-06', '2020-01-07', '2020-01-08',
               '2020-01-09', '2020-01-10',
               ...
               '2021-12-22', '2021-12-23', '2021-12-24', '2021-12-25',
               '2021-12-26', '2021-12-27', '2021-12-28', '2021-12-29',
               '2021-12-30', '2021-12-31'],
              dtype='datetime64[ns]', length=731, freq='D')
"""

print('西暦')
print(df.index.year)
"""
西暦
Int64Index([2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020, 2020,
            ...
            2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021, 2021],
           dtype='int64', length=731)
"""

print('月')
print(df.index.month)
"""
月
Int64Index([ 1,  1,  1,  1,  1,  1,  1,  1,  1,  1,
            ...
            12, 12, 12, 12, 12, 12, 12, 12, 12, 12],
           dtype='int64', length=731)
"""

print('日')
print(df.index.day)
"""
日
Int64Index([ 1,  2,  3,  4,  5,  6,  7,  8,  9, 10,
            ...
            22, 23, 24, 25, 26, 27, 28, 29, 30, 31],
           dtype='int64', length=731)
"""

# 0(月曜)~6(日曜)の値で表記
print('曜日')
print(df.index.weekday)
"""
曜日
Int64Index([2, 3, 4, 5, 6, 0, 1, 2, 3, 4,
            ...
            2, 3, 4, 5, 6, 0, 1, 2, 3, 4],
           dtype='int64', length=731)
"""

真偽値で実行すると

df.index.year == 2021
"""
array([False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       ...
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True])
"""

上記の真偽を使用してインデックス参照する

df[df.index.year == 2021]
"""
           Value
2021-01-01  366
2021-01-02  367
2021-01-03  368
2021-01-04  369
2021-01-05  370
... ...
2021-12-27  726
2021-12-28  727
2021-12-29  728
2021-12-30  729
2021-12-31  730
"""

特定の月を抽出、

真偽値を使って各年の1月や2月といった特定の月を抽出する。

下記では2020年~2021年の範囲内にある5月のみのデータを抽出している。

# 各年の5月を抽出
df_may = df[df.index.month == 5]
df_may
"""
           Value
2020-05-01  121
2020-05-02  122
2020-05-03  123
2020-05-04  124
2020-05-05  125
... ...
2021-05-27  512
2021-05-28  513
2021-05-29  514
2021-05-30  515
2021-05-31  516
"""

2020年5月と2021年5月を比較するために2020年5月のデータを後方へシフトして見比べる。

df_may_side = df_may.copy()
df_may_side['2020 Value'] = df_may.shift(len(df_may['2020']))
df_may_side['2021'].head()
"""
           Value 2020 Value
2021-05-01  486 121.0
2021-05-02  487 122.0
2021-05-03  488 123.0
2021-05-04  489 124.0
2021-05-05  490 125.0
"""

可視化してみると

df_may_side['2021'].plot(figsize=(15, 5))

特定の日にちを抽出する

真偽値を使って2021年各月の特定の日にちを抽出する。

# 各月の10日を抽出
df_10th = df['2021'][df['2021'].index.day == 10]
df_10th
"""
           Value
2021-01-10  375
2021-02-10  406
2021-03-10  434
2021-04-10  465
2021-05-10  495
2021-06-10  526
2021-07-10  556
2021-08-10  587
2021-09-10  618
2021-10-10  648
2021-11-10  679
2021-12-10  709
"""

各月の10日を可視化して比較する。

df_10th.plot.barh(figsize=(15, 5))

特定の曜日を抽出

この記事では、datetimeオブジェクトのstrftimeメソッドとpandasのasfreqメソッドを使って特定の曜日を抽出してくる。

まずはdatetimeオブジェクトのstrftimeメソッドを使用して抽出する。

strftimeメソッドにdatetimeオブジェクトの日付フォーマット「%a」を渡すことで、曜日を取得できます。

print(df.index.strftime('%a'))
"""
Index(['Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri',
       ...
       'Wed', 'Thu', 'Fri', 'Sat', 'Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
      dtype='object', length=731)
"""

新たに曜日列を作成し、真偽値でインデックス参照します。

df_days = df.copy()
df_days['day of week'] = df.index.strftime('%a')
df_days.head()
"""
           Value day of week
2020-01-01  0   Wed
2020-01-02  1   Thu
2020-01-03  2   Fri
2020-01-04  3   Sat
2020-01-05  4   Sun
"""

# 各月の木曜日(Thu)を抽出
df_days[df_days['day of week'] == 'Thu']
"""
           Value day of week
2020-01-02  1   Thu
2020-01-09  8   Thu
2020-01-16  15  Thu
2020-01-23  22  Thu
2020-01-30  29  Thu
... ... ...
2021-12-02  701 Thu
2021-12-09  708 Thu
2021-12-16  715 Thu
2021-12-23  722 Thu
2021-12-30  729 Thu
"""

ちなみにdatetimeオブジェクトのweekdayメソッド使えば0(月曜)~6(日曜)の値で曜日を取得できる。

df_days['weekday'] = df.index.weekday
df_days
"""
           Value day of week weekday
2020-01-01  0    Wed         2
2020-01-02  1    Thu         3
2020-01-03  2    Fri         4
2020-01-04  3    Sat         5
2020-01-05  4    Sun         6
... ... ... ...
2021-12-27  726  Mon         0
2021-12-28  727  Tue         1
2021-12-29  728  Wed         2
2021-12-30  729  Thu         3
2021-12-31  730  Fri         4
"""

# weekday列を除外
_ = df_days.drop('weekday', axis=1, inplace=True)

pandasのasfreqメソッドを使って特定の曜日を抽出する。

asfreqメソッドは、痒い所に手が届くような細かい抽出ができます。

手前で作成したデータdf_daysに「day of week」列があるので、どのように抽出できたか分かりやすいかもしれません。

# 各月の木曜日(Thu)を抽出
df_days.asfreq(freq='W-THU')
"""
           Value day of week
2020-01-02  1   Thu
2020-01-09  8   Thu
2020-01-16  15  Thu
2020-01-23  22  Thu
2020-01-30  29  Thu
... ... ...
2021-12-02  701 Thu
2021-12-09  708 Thu
2021-12-16  715 Thu
2021-12-23  722 Thu
2021-12-30  729 Thu
"""

asfreqメソッドの引数に指定した頻度の「W-THU」はpandasの日付ロジックです。

詳しくはpandas公式ドキュメントのオフセットエイリアスにあります。

さらに細かい抽出では、月ごとの第何何曜日まで指定することができます。

# 各月の第3金曜日を抽出
df_days.asfreq('WOM-3FRI')
"""
           Value day of week
2020-01-17  16  Fri
2020-02-21  51  Fri
2020-03-20  79  Fri
2020-04-17  107 Fri
2020-05-15  135 Fri
...
2021-08-20  597 Fri
2021-09-17  625 Fri
2021-10-15  653 Fri
2021-11-19  688 Fri
2021-12-17  716 Fri
"""

ただし各月で同じ頻度の曜日が存在していなければエラーとなる。

以下では各月の第5金曜日を抽出しようとしているがエラー。

# 2月は第5までが無いので
df_days.asfreq('WOM-5FRI')
"""
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
...
ValueError: Invalid frequency: WOM-5FRI
"""

以上です。最後までご覧いただきありがとうございました。