移動平均#

in English or the language of your choice.

import numpy as np
import pandas as pd
import py4macro

# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")

はじめに#

インフレ率とマネーストックの増加率では,インフレ率とマネーストックの増加率の長期的な関係について考察し,resampleを使い分析を進めた。ここでは移動平均を使い,同様なデータ整形ができることを説明する。また,移動平均は季節調整やトレンド抽出にも使えることも覚えておこう。

移動平均とは#

次のDataFrame(変数名はdf_ex)を使って移動平均について説明する。

Hide code cell source
month_list = [f'{i}月' for i in range(1,13)]
df_ex = pd.DataFrame({'月':month_list,'A':range(10,130,10)})
df_ex['B'] = df_ex['A'].rolling(3).mean()
df_ex['C'] = df_ex['B'].iloc[2::3]
df_ex
A B C
0 1月 10 NaN NaN
1 2月 20 NaN NaN
2 3月 30 20.0 20.0
3 4月 40 30.0 NaN
4 5月 50 40.0 NaN
5 6月 60 50.0 50.0
6 7月 70 60.0 NaN
7 8月 80 70.0 NaN
8 9月 90 80.0 80.0
9 10月 100 90.0 NaN
10 11月 110 100.0 NaN
11 12月 120 110.0 110.0

Aには10から120までの数字が並んでおり,それぞれを1月から12月までの値と考えてみよう。1四半期には3ヶ月あるので,第1四半期は列0〜2となる。この3行をここではwindowと呼ぶ。最初のwindowの平均は20.0であり,それが列Bの2番目の行に入っている。次にwindowを1行下げると,2〜4月をカバーすることになり,その平均は30.0となり,列Bの3番目の行の値となっている。同じように,windowを1行下げると,3〜6月に移り,その平均40.0は列Bの4番目の値になっている。更にwindowを1行ずらすと第2四半期の4〜6月となり,平均50.0は列Bの5番目に入っている。この計算を最後まで続けると列Bが埋まる事になり,これが移動平均である。列Aから列Bを作るにはdf_exのメソッド.rolling().mean()を結合させて次のように使う。

df_ex['A'].rolling(window=3).mean()

引数windowが上の説明にあるwindowの数を指定している。.rollingはwindowが下に動いていることをイメージすれば良いだろうし,windowごとに何らかの計算を可能にするメソッドである。

Tip

平均を計算するために.mean()を使ったが,.rolling()には他のメソッドもある。例えば,

  • .rolling(3).sum()windowの合計を返す。

  • .rolling(3).max()windowの最大値を返す

  • .rolling(3).min()windowの最小値を返す

  • .rolling(3).median()windowの中央値を返す

実際にdf_exの列Aの移動平均を作成してみよう。

df_ex.loc[:,'A'].rolling(3).mean()
0       NaN
1       NaN
2      20.0
3      30.0
4      40.0
5      50.0
6      60.0
7      70.0
8      80.0
9      90.0
10    100.0
11    110.0
Name: A, dtype: float64

このコードではwindow=を省いている。df_exの列Bと同じであることが分かる。以上が移動平均の計算方法である。

Note

Bの0番目と1番目の行にNaNが入っており,移動平均には欠損値が必ず発生することになる。一方でNaNの位置を変えるために,.rolling()には引数center=Trueが用意されている。

df_ex.rolling(3, center=True).mean()

上の例では1四半期の平均値は四半期の最後の月に該当する行に入っているが,このcenter=Trueを使うと平均値は真ん中の月に該当する行に入り(例えば,第1四半期の平均は1番目の行に入る),NaNは0番目と最後の行に入ることになる。

四半期・年次・3年次データの作成方法#

次に,インフレ率とマネーストックの増加率で計算した四半期,年次,3年次データの作成方法を説明する。

df_exの列Cは四半期の平均だけを抜き取りその他はNaNになっている。月次データを四半期データに変換するには,NaNが含まれない列Cを作成すれば良い。即ち,列Bから該当する行だけを抽出すれば良いことになる。そのためにPandasの章で説明した.iloc[]を使う。.ilocDataFrameSeriesの行インデックを使い要素を抽出するメソッドであるが,スライシングの場合は次のように指定することになる。

.iloc[row_start:row_end:row_step, col_start:col_end:col_step]
  • row_start:スライスする最初の行番号

  • row_end:スライスする最後の行番号の次の番号

  • row_step:何行ごとに抽出するかを指定する

    • 1は「1行ごと」で全ての行という意味。デフォルトなので:1は省略可能。

    • 2は「2行ごと」で1行飛ばしという意味。

    • 3は「3行ごと」で2行飛ばしという意味。

    • 一般的に\(n\geq1\)は「\(n\)行ごと」で\(n-1\)行飛ばしという意味。

    • -1は1と同じだが逆の順番から抽出する。

  • col_start:スライスする最初の列番号

  • col_end:スライスする最後の列番号の次の番号

  • col_step:何列ごとに抽出するかを指定する

    • 1は「1列ごと」で全ての列という意味。デフォルトなので:1は省略可能。

    • 2は「2行ごと」で1列飛ばしという意味。

    • 3は「3行ごと」で2列飛ばしという意味。

    • 一般的に\(n\geq1\)は「\(n\)列ごと」で\(n-1\)列飛ばしという意味。

    • -11と同じだが逆の順番から抽出する。

例えば,次のコードでは2番目の行から10番目の行の全ての列を抽出しており,:row_stepは省いているのでrow_step=1と設定されている。

.iloc[2:11,:]

一方,次のコードは2番目の行から10番目の行を2行ごと((2-1=)1行飛ばしで)抽出することになる。

.iloc[2:11:2,:]

df_exに戻ろう。四半期の平均は列Bの2番目,5番目,8番目,11番目の行であり,それらを抽出するには

.iloc[2::3,:]

となる。row_start=22は第1四半期の平均がある行を指しており,そこからスタートとなる。row_step=33は3行ごとに四半期の平均があるので,その3を表している。従って,月次データを四半期データに変換するには

df_ex['A'].rolling(3).mean().iloc[2::3]

実際に実行してみよう。df_ex['A'].rolling(3).mean()Seriesを返すので.iloc[2::3]となっている。

df_ex['A'].rolling(3).mean().iloc[2::3]
2      20.0
5      50.0
8      80.0
11    110.0
Name: A, dtype: float64

同様に,月次データを年次データに変換する場合は

.rolling(12).mean().iloc[11::12]

となり,3年期データに変換する場合は

.rolling(36).mean().iloc[35::36]

となる。

CNaN以外の値と同じであることが確認できる。

実際のデータを使って#

では実際にjpn-moneyのデータを使いデータを整形しよう。まず月次データを読み込みmonthに割り当てる。

month = py4macro.data('jpn-money')
month.tail()
cpi money
2021-08-31 101.618532 158.215194
2021-09-30 101.729035 158.977241
2021-10-31 101.401104 160.060574
2021-11-30 101.956670 161.054055
2021-12-31 102.045185 161.869633

いつもの通り.info()を使ってデータの内容を確認しよう。

month.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 804 entries, 1955-01-31 to 2021-12-31
Data columns (total 2 columns):
 #   Column  Non-Null Count  Dtype  
---  ------  --------------  -----  
 0   cpi     804 non-null    float64
 1   money   804 non-null    float64
dtypes: float64(2)
memory usage: 18.8 KB

行ラベルがDatetimeIndexとなっており,時系列データ用に設定されていることが分かる。

四半期データに変換して変数quarterに割り当てることにする。

quarter = month.rolling(3).mean().iloc[2::3,:]

これで3ヶ月の値の平均からなる四半期データを作成した事になる。確かめてみよう。

quarter.head()
cpi money
1955-03-31 17.236707 0.347656
1955-06-30 16.874004 0.357257
1955-09-30 17.035517 0.384201
1955-12-31 16.875107 0.400080
1956-03-31 17.108284 0.394544

四半期の最後の日が行ラベルになっていることが分かる。同様に,年次データと3年期データを作成する。

annual= month.rolling(12).mean().iloc[11::12,:]
annual.head()
cpi money
1955-12-31 17.005334 0.372299
1956-12-31 17.072603 0.424722
1957-12-31 17.601583 0.478435
1958-12-31 17.517496 0.505580
1959-12-31 17.707073 0.588486
annual3= month.rolling(36).mean().iloc[35::36,:]
annual3.head()
cpi money
1957-12-31 17.226506 0.425152
1960-12-31 17.854861 0.599932
1963-12-31 20.666763 1.039100
1966-12-31 24.291933 1.641735
1969-12-31 28.080477 2.570458

ここで作成したquarterannualannual3は,インフレ率とマネーストックの増加率の同じ変数名のDataFrameと同じである。