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

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

言語 JA

外れ値

05.1.11

外れ値

最終更新 2020-06-17 読了時間 3 分
まとめ
外れ値検出は、系列の中で「普段の変動幅から飛び出した点」を機械的に見つける処理です。このページでは総務省統計局の家計調査から作った月次の消費支出のうち、傾向(トレンド)と季節性を除いた「季節変動調整分」の列を対象にします。検出には DHI/tsod の DiffDetector(direction="positive") を使い、先頭 10 か月の前月差で「普段の上がり幅」を学習させてから、detect で全期間のうち異常に大きく上がった月を取り出します。検出された 2000 年 12 月、2014 年 3 月、2019 年 10 月、2020 年 6 月を実際の出来事(景気後退、消費増税前の駆け込み、移動制限の解除)と照らすと、外れ値が「データの誤り」ではなく「経済イベント」を指していることが分かります。

直感 #

家計の消費支出は毎年 3 月と 12 月に増えるといった季節のくせと、長期的なゆるやかな減少トレンドを持っています。そのままの金額で「飛び出した月」を探すと、毎年 12 月が外れ値になってしまいます。そこでまずトレンドと季節性を引いた残り(季節変動調整分)を作り、「普段ならこの程度しか動かない」という前月差の幅を求め、それを大きく超えて上がった月だけを外れ値とします。消費増税の前月に駆け込み消費で支出が跳ねる、といったイベントがこの方法で浮かび上がります。

元データは総務省統計局の「家計調査(家計収支編) 時系列データ(二人以上の世帯)」です。トレンドと季節性の分解は 季節調整済みの経済指標 のページで行い、その結果を CSV に保存してあります。

加工済みデータを読み込む #

CSV には元の消費支出に加えて、分解で得た傾向変動・季節変動調整分などの列が入っています。

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

data = pd.read_csv("./支出金額_加工済みデータ.csv", index_col="日付")
data.index = pd.to_datetime(data.index)
data.head(10)

消費支出傾向変動傾向変動調整分月季節変動調整分
日付
2000-01-01105.629546107.63941197.99013515.539775
2000-02-0199.161881107.53083491.63104727.053064
2000-03-01114.404119107.423056106.98106237.116344
2000-04-01114.381944107.316075107.06586849.897649
2000-05-01105.269625107.20988798.05973857.430118
2000-06-01101.544867107.10448994.44037867.189765
2000-07-01111.381122106.999877104.381245712.401256
2000-08-01105.756457106.89604898.86040986.583948
2000-09-01101.138548106.79299894.34555095.993986
2000-10-01105.483531106.69072698.792805106.125017

季節変動調整分 の列だけを折れ線にして、普段の揺れ幅と飛び出した月を目で確かめます。

1
2
3
4
sns.set(rc={"figure.figsize": (15, 8)})
jm.japanize()
sns.lineplot(data=data, x="日付", y="季節変動調整分", label="季節変動調整分")
plt.show()

外れ値 figure

何が起きているか(ステップで見る) #

コードを読む前に、この手法が図の上で何をしているかを追ってみましょう。「再生」を押すか、スライダーを動かすと 1 手順ずつ進みます。

見るポイント:帯の幅を σ 何個分にするかで外れ値の数が変わる。3σ の外はかなり珍しい値。DiffDetector は値そのものではなく前月差にこの考え方を当てています。

tsod で異常値を検出する #

DHI/tsod は時系列向けの外れ値検出器を集めたライブラリです。DiffDetector は「隣の点との差」が学習期間の差の分布から外れた点を異常とみなします。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import tsod

magd = tsod.DiffDetector(direction="positive")
series = data["季節変動調整分"]
magd.fit(series[0:10])

res = magd.detect(series)
plt.figure(figsize=(16, 4))
plt.plot(series)
plt.plot(series[res], "ro", label="Anomaly")

for d in series[res].index:
    plt.axvline(d, alpha=0.5, linewidth=0.75, color="k")
    plt.text(
        d + pd.DateOffset(10),
        10,
        f'{d.strftime("%Y/%m/%d")}',
        rotation=90,
    )
plt.legend()
plt.show()

DHI/tsodを用いて異常値を検出してみます。 figure

実行結果の読み方 #

赤丸は 2000 年 12 月、2014 年 3 月、2019 年 10 月、2020 年 6 月の 4 か所に付いています。2014 年 3 月と 2019 年 10 月は消費税率が 8%、10% に上がった直前・直後の月で、駆け込み消費と反動の動きが季節変動調整分の急上昇として現れています。学習に使った 2000 年の 10 か月の中には赤丸が無く、fit の期間が正常とみなされていることも確認できます。

ピークの点付近にあった出来事 #

2000/12 頃 #

日本経済は、2000年10月に(1)景気の山を越え、景気後退局面に入った。その後、2001年を通じて、生産は大幅に減少するとともに、失業率も既往最高水準を更新し、景気は悪化を続けた。(経済財政白書/経済白書 > 平成14年度 年次経済財政報告)

2014/03 頃 #

消費税率が 5% から 8% に上がる直前の月で、駆け込み消費が起きました。2014年の消費増税時を振り返る データから見えた消費への影響と小売店の対策とは?

2019/10 頃 #

消費税率が 8% から 10% に上がった月です。2019年10月に消費税率は10%になりました。 | 財務省

2020/06 頃 #

緊急事態宣言の解除後に都道府県をまたぐ移動が緩和され、4〜5 月に抑えられていた支出が戻った月です。都道府県をまたぐ移動、6月19日から全国的に緩和

使いどころと落とし穴 #

DiffDetector は「前月からの差」だけを見るので、数か月かけてじわじわ上がる変化は検出できず、1 か月で跳ねた点だけを拾います。fit に渡す期間に外れ値が混ざると上限が緩み、2014 年 3 月のような点も見逃すので、学習期間はイベントの無い時期から選びます。direction="positive" のままだと 2020 年 4 月の急落(外出自粛)は拾えないため、下落も見たいときは "both" にします。季節変動調整分ではなく元の 消費支出 列に同じ検出器を当てると、毎年 12 月の季節的な増加が外れ値になってしまうので、季節調整 を先に済ませておくことが前提です。

まとめ #

外れ値検出は、トレンドと季節性を除いた季節変動調整分に対して tsod.DiffDetector(direction="positive") を使い、fit(series[0:10]) で平穏な 10 か月の前月差から正常範囲を学び、detect(series) で全期間の急上昇した月を取り出す流れです。検出された 2000/12、2014/03、2019/10、2020/06 はいずれも景気の山、消費増税、移動制限解除という出来事に対応し、外れ値がデータの誤りではなく経済イベントの印になっていました。direction と fit の期間を変えると拾われる点が変わるので、自分のデータでは平穏期を学習に使い、上下どちらの変化を見たいかを先に決めてください。