移動平均#
import numpy as np
import pandas as pd
import py4macro
# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")
はじめに#
インフレ率とマネーストックの増加率では,インフレ率とマネーストックの増加率の長期的な関係について考察し,resample
を使い分析を進めた。ここでは移動平均を使い,同様なデータ整形ができることを説明する。また,移動平均は季節調整やトレンド抽出にも使えることも覚えておこう。
移動平均とは#
次のDataFrame
(変数名はdf_ex
)を使って移動平均について説明する。
Show 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[]
を使う。.iloc
はDataFrame
やSeries
の行インデックを使い要素を抽出するメソッドであるが,スライシングの場合は次のように指定することになる。
.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\)列飛ばしという意味。
-1
は1
と同じだが逆の順番から抽出する。
例えば,次のコードでは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=2
の2
は第1四半期の平均がある行を指しており,そこからスタートとなる。row_step=3
の3
は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]
となる。
列C
のNaN
以外の値と同じであることが確認できる。
実際のデータを使って#
では実際にjpn-money
のデータを使いデータを整形しよう。まず月次データを読み込みmonth
に割り当てる。
month = py4macro.data('jpn-money')
month.tail()
cpi | money | |
---|---|---|
2020-08-01 | 102.026510 | 147.486589 |
2020-09-01 | 101.526496 | 148.714911 |
2020-10-01 | 101.293089 | 149.341961 |
2020-11-01 | 101.346909 | 150.335605 |
2020-12-01 | 101.231809 | 151.327058 |
いつもの通り.info()
を使ってデータの内容を確認しよう。
month.info()
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 792 entries, 1955-01-01 to 2020-12-01
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 cpi 792 non-null float64
1 money 792 non-null float64
dtypes: float64(2)
memory usage: 18.6 KB
行ラベルがDatetimeIndex
となっており,時系列データ用に設定されていることが分かる。
四半期データに変換して変数quarter
に割り当てることにする。
quarter = month.rolling(3).mean().iloc[2::3,:]
これで3ヶ月の値の平均からなる四半期データを作成した事になる。確かめてみよう。
quarter.head()
cpi | money | |
---|---|---|
1955-03-01 | 17.243521 | 0.347656 |
1955-06-01 | 16.867311 | 0.357257 |
1955-09-01 | 17.036744 | 0.384201 |
1955-12-01 | 16.873758 | 0.400080 |
1956-03-01 | 17.115098 | 0.394544 |
四半期の最後の日が行ラベルになっていることが分かる。同様に,年次データと3年期データを作成する。
annual= month.rolling(12).mean().iloc[11::12,:]
annual.head()
cpi | money | |
---|---|---|
1955-12-01 | 17.005334 | 0.372299 |
1956-12-01 | 17.072603 | 0.424722 |
1957-12-01 | 17.601583 | 0.478435 |
1958-12-01 | 17.517496 | 0.505580 |
1959-12-01 | 17.707073 | 0.588486 |
annual3= month.rolling(36).mean().iloc[35::36,:]
annual3.head()
cpi | money | |
---|---|---|
1957-12-01 | 17.226506 | 0.425152 |
1960-12-01 | 17.854861 | 0.599932 |
1963-12-01 | 20.666763 | 1.039100 |
1966-12-01 | 24.291933 | 1.641735 |
1969-12-01 | 28.080477 | 2.570458 |
ここで作成したquarter
,annual
,annual3
は,インフレ率とマネーストックの増加率の同じ変数名のDataFrame
と同じである。