移動平均#
import numpy as np
import pandas as pd
import py4macro
# 警告メッセージを非表示
import warnings
warnings.filterwarnings("ignore")
はじめに#
インフレ率とマネーストックの増加率では,インフレ率とマネーストックの増加率の長期的な関係について考察し,resampleを使い分析を進めた。ここでは移動平均を使い,同様なデータ整形ができることを説明する。また,移動平均は季節調整やトレンド抽出にも使えることも覚えておこう。
移動平均とは#
次のDataFrame(変数名はdf_ex)を使って移動平均について説明する。
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と同じである。