概要
時系列データで特定の範囲を抽出したり、月ごとの特定の日にちや曜日を抽出し比較する。例えば、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
"""
以上です。最後までご覧いただきありがとうございました。