K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

季節調整

05.1.10

季節調整

最終更新 2020-06-03 読了時間 6 分
まとめ
季節調整は、月次の経済指標から「毎年 12 月に増える」「2 月に減る」といった季節のくせを取り除き、景気の実勢だけを見えるようにする処理です。このページでは総務省統計局の家計調査から 2000 年 1 月〜2022 年 5 月の消費支出(二人以上の世帯)を取り出し、まず np.polyfit の 3 次曲線で長期の傾向変動を推定して引き、次に月別平均法(12 か月それぞれの平均を求め、合計が 1200 になるよう修正係数を掛ける)で季節変動を引きます。各ステップで折れ線がどう滑らかになるかを図で追い、最後に残った「季節変動調整分」を CSV に保存して 外れ値 のページで使います。読み終えると、変動を「傾向・循環・季節・不規則」の 4 つに分ける考え方と、そのうち 2 つを pandas だけで除く手順が身につきます。

経済データの季節調整 #

総務省統計局の公開している「家計調査(家計収支編) 時系列データ(二人以上の世帯)」のデータを分析します。季節調整の手順は経済産業省が鉱工業指数で使っている方法の解説(季節調整手法)を参考にしています。

直感 #

家計の消費支出は 12 月に年間平均の 15% ほど多く、2 月に 8% ほど少なくなります。これは毎年繰り返す「季節変動」で、景気が良くなったわけでも悪くなったわけでもありません。消費が本当に増えたかを見るには、この毎年のくせと、人口減少などによる長期的な「傾向変動」を引いて残りを見る必要があります。月別平均法は 22 年分のデータから「1 月の平均」「2 月の平均」…「12 月の平均」を 12 個求め、各月の値からその月の平均を引くだけの素朴な方法ですが、季節のくせがどれだけ大きいかを数値で確かめられます。

データの前処理 #

配布されている CSV は Excel の見た目を保った形で、空白のセルや複数行にまたがる見出しが含まれています。read_csv で読んだあと、14 行目の消費支出の行だけを切り取り、数値に変換した new_df を用意します。

1
2
3
4
import pandas as pd

df = pd.read_csv("./支出金額.csv", encoding="cp932")
df.head(15)

二人以上の世帯_支出金額[円]Unnamed: 1Unnamed: 2Unnamed: 3Unnamed: 4Unnamed: 51234...260261262263264265266267268269
0NaNNaNNaNNaNNaNNaN2000年NaNNaNNaN...NaNNaNNaNNaNNaN2022年NaNNaNNaNNaN
1NaNNaNNaNNaNNaNNaN(平成12年)NaNNaNNaN...NaNNaNNaNNaNNaN(令和4年)NaNNaNNaNNaN
2表側連番階層大分類中分類小分類品目分類1月2月3月4月...8月9月10月11月12月1月2月3月4月5月
31----世帯数分布(抽出率調整)10000100001000010000...10000100001000010000100001000010000100001000010000
42----集計世帯数7887794279347922...7397737874077411741673537315736973577391
53----世帯人員(人)3.323.323.323.32...2.932.932.932.932.922.922.922.922.912.91
64----18歳未満人員(人)0.740.750.750.75...0.550.560.560.550.550.550.550.540.550.55
75----65歳以上人員(人)0.520.530.530.52...0.850.830.840.840.850.840.850.840.840.84
86----うち無職者人員(人)0.410.410.410.41...0.680.670.680.670.670.670.680.660.670.67
97----有業人員(人)1.511.511.511.52...1.331.331.331.341.331.331.311.331.331.34
108----世帯主の年齢(歳)52.452.652.752.6...60.159.959.959.960.26060.260.16060
119----持家率(%)7676.376.275.8...84.184.184.484.484.183.98484.48584.8
1210----家賃・地代を支払っている世帯の割合(%)22.12222.622.2...14.914.613.91414.814.614.913.813.413.8
13111---消費支出309621290663335341335276...266638265306281996277029317206287801257887307261304510287687
141221--食料73580733097972677344...81412766737954378490995187597471655799827701482066

15 rows × 275 columns

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
new_df = pd.DataFrame(
    {
        "日付": pd.date_range(start="2000/1/1", end="2022/5/1", freq="MS"),
        "消費支出": pd.to_numeric(df.iloc[13][6:]),
    }
)
new_df = new_df.set_index("日付")
new_df["消費支出"] = (new_df["消費支出"] / new_df["消費支出"].mean()) * 100.0

new_df.head(10)

消費支出
日付
2000-01-01105.629546
2000-02-0199.161881
2000-03-01114.404119
2000-04-01114.381944
2000-05-01105.269625
2000-06-01101.544867
2000-07-01111.381122
2000-08-01105.756457
2000-09-01101.138548
2000-10-01105.483531

データをプロットしてみる #

平均 100 に正規化した 消費支出 を lineplot で折れ線にして、季節のくせと長期の傾きを目で確かめます。

1
2
3
4
5
6
7
8
import japanize_matplotlib as jm
import matplotlib.pyplot as plt
import seaborn as sns

sns.set(rc={"figure.figsize": (15, 8)})
jm.japanize()
sns.lineplot(data=new_df, x="日付", y="消費支出")
plt.show()

データをプロットしてみる figure

傾向変動を取り除く #

傾向変動は人口の増減や所得水準の変化による、10 年単位でゆっくり進む動きです。移動平均で滑らかにする方法と、最小二乗法で直線や曲線を当てる方法があり、ここでは np.polyfit で 3 次の多項式を当てます。

参考:numpy.polyfit — NumPy v1.23 Manual

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import numpy as np

idx = [i for i in range(new_df.shape[0])]

傾向変動の関数の係数 = np.polyfit(idx, new_df["消費支出"], 3)
傾向変動の関数 = np.poly1d(傾向変動の関数の係数)
new_df["傾向変動"] = 傾向変動の関数(idx)
new_df["傾向変動調整分"] = new_df["消費支出"] - 傾向変動の関数(idx) + np.mean(傾向変動の関数(idx))

sns.set(rc={"figure.figsize": (15, 8)})
jm.japanize()
sns.lineplot(data=new_df, x="日付", y="消費支出", label="消費支出")
sns.lineplot(data=new_df, x="日付", y="傾向変動", label="傾向変動")
# sns.lineplot(data=new_df, x="日付", y="傾向変動調整分", label="傾向変動調整分")
plt.show()

23 Manual figure

循環変動 #

在庫投資の増減で 3〜4 年周期に動く キチンサイクル など、数年周期の変動を循環変動と呼びます。このページでは取り除かず、季節変動調整分の中に残します。

季節変動を取り除く #

1 年を周期とする変動を「季節変動」と呼び、除き方には月別平均法と連環比率法があります。ここでは月別平均法を 4 つの手順で進めます。まず過去 22 年分の月別平均値を 12 個求め、次にその合計を出し、合計が 1200(= 100 × 12 か月)になるように修正係数を計算し、最後に修正係数を掛けた月別平均を各月の値から引きます。

① 過去の複数年の月別平均値を求める #

1
2
3
new_df["月"] = new_df.index.month
季節ごとの平均値 = new_df.groupby("月").mean()["消費支出"]
季節ごとの平均値
月
1     100.083036
2      92.102619
3     107.280556
4     104.477264
5      97.832924
6      94.348753
7      98.973205
8      99.165835
9      95.138160
10     99.351828
11     96.230671
12    114.934402
Name: 消費支出, dtype: float64

② 月別平均値の合計を求める #

1
2
月別平均値の合計 = 季節ごとの平均値.sum()
print(f"月別平均値の合計 = {月別平均値の合計}")
月別平均値の合計 = 1199.9192545557726

③ 修正係数を計算する #

1
2
修正係数 = 1200.0 / 月別平均値の合計
print(f"修正係数 = {修正係数}")
修正係数 = 1.0000672923981517

④ 月別平均に修正係数を乗じる #

1
修正済みの季節ごとの平均値 = 修正係数 * 季節ごとの平均値
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 各月のデータから修正済みの季節ごとの平均値を引いています
new_df["季節変動調整分"] = new_df["消費支出"] - new_df["月"].apply(lambda m: 修正済みの季節ごとの平均値[m])
new_df.to_csv("支出金額_加工済みデータ.csv", encoding="utf-8-sig")

# グラフを作成
sns.set(rc={"figure.figsize": (15, 8)})
jm.japanize()
sns.lineplot(data=new_df, x="日付", y="消費支出", label="消費支出")
sns.lineplot(data=new_df, x="日付", y="傾向変動", label="傾向変動")
sns.lineplot(data=new_df, x="日付", y="季節変動調整分", label="季節変動調整分")
plt.show()

④月別平均に修正係数を乗じる figure

実行結果の読み方 #

青の消費支出には毎年 12 月の山と 2 月の谷が並び、オレンジの傾向変動はその中心をゆるやかに下る 3 次曲線です。緑の季節変動調整分では毎年の山谷がほぼ消え、2014 年 3 月(消費増税前の駆け込み)と 2020 年 4〜5 月(外出自粛)の跳ねが孤立した動きとして残っています。季節のくせを引いた後に残る動きこそが「普段と違う月」であり、これを次のページで外れ値として検出します。

使いどころと落とし穴 #

月別平均法は「季節のくせが 22 年間ずっと同じ」と仮定しています。2000 年代と 2020 年代で 12 月の消費の増え方が変わっていれば、1 つの季節指数では前半か後半のどちらかで調整が過不足になります。公式統計で使われる X-12-ARIMA は季節指数を年ごとに変化させます。より正確な調整が必要なら statsmodels の x13_arima_analysis や seasonal_decompose(model="additive", period=12) に進んでください。polyfit の次数は 3 を使いましたが、new_df の期間を変えると適切な次数も変わるため、傾向線が季節の山谷を追い始めていないかを図で確認してから次数を決めてください。

まとめ #

季節調整の手順は 2 回の引き算です。消費支出を平均 100 の指数にした上で、np.polyfit(idx, y, 3) の 3 次曲線で傾向変動を、groupby("月").mean() に修正係数 1200 / 合計 を掛けた 12 個の季節指数で季節変動を、それぞれ引きました。2 月の 92 と 12 月の 115 という季節指数が「毎年のくせ」の大きさで、これを引いた季節変動調整分には消費増税やコロナ禍のような一時的な動きだけが残ります。残った系列は 支出金額_加工済みデータ.csv に保存してあり、外れ値 のページで異常検出の入力になります。