俺、サービス売って家買うんだ

Swift, Kotlin, Vue.js, 統計, GCP / このペースで作ってればいつか2-3億で売れるのがポっと出来るんじゃなかろうか

カーネル密度推定とは何か?

こんにちは、Hayatoです。年末ですね。
カーネル密度推定をおさらいしようと何度かググったのですが良い感じの記事が見当たらなかったので、書き落としておきます。

Index

  • カーネル密度推定って?
  • どういうときに使うといいの?
  • カーネル密度の算出方法 (実際にPythonで)
  • 2次元でカーネル密度推定

カーネル密度推定って?

カーネル密度推定は、一言で表すと「なめらかなヒストグラム」です。
なめらかなヒストグラムを利用して、実際のいくつかのデータ(標本)から、全体の分布を推定する事ができます。 左がヒストグラムで、右がそれを元にして作成したカーネル密度分布のグラフです。 f:id:hayato1986:20161226164449p:plain

参照:Kernel density estimation - Wikipedia

どういうときに使うといいの?

ヒストグラムとは違い曲線になっているので、X値に対応するYを取ることが出来ます。あくまで推定ではありますが、おおよそX=0.2635ならY=2.45など、あらゆる値に対応できるようになります。

カーネル密度分布を書くことで、複数の突出(peak)がある場合に異なる複数の母集団から標本が抽出されている可能性がわかったり、複数のカーネル密度分布を足し合わせたときに視覚的な比較優位を取ることが出来ます。

カーネル密度の算出方法 (実際にPythonで)

さて、では実際にカーネル密度推定を順序立ててやっていきましょう。Githubに iPython Notebook を上げておいたのでそちらも参考にしてください。

1. サンプルデータを作成してヒストグラムを描画

正規分布に従うサンプルデータを作成して、ラグを表示しつつヒストグラムを書いてみます。ラグがたくさんあるところがグラフも高くなっていますね。

data = randn(50)
plt.hist(data, alpha=0.5)
sns.rugplot(data)

f:id:hayato1986:20161227112932p:plain

2. カーネル密度関数を重ねてみる

このグラフにカーネル密度関数を重ねてみます。やはりヒストグラムをなぞったような形になっています。

sns.rugplot(data)
sns.distplot(data)

f:id:hayato1986:20161227123707p:plain

こういうときSeabornはめちゃめちゃ便利ですねぇ。diplot(hoge)で一発描画。。

3. バンド幅とカーネル関数を選択する。

カーネル密度関数を調整するに当たり、バンド幅とカーネル関数を選択します。

バンド幅の違いでグラフを表示

バンド幅とは、データ(標本)一つ一つをどれくらい左右に広げるかの設定をします。0.1, 1.0などなど数値で表します。試しにいくつかのバンド幅を書いてみましょう。

sns.rugplot(data)
list =  [0.1, 0.3, 0.5]

for num in list:
    sns.kdeplot(data, bw=num, label=num)

f:id:hayato1986:20161227122014p:plain

選択するカーネル関数の違いでグラフを見比べる

カーネル関数は、データ(標本)一つ一つをどのような形で広げるかの設定です。ガウス分布(正規分布)が基本かと思いますが、三角、一様などなどいろいろ種類があります。詳しくはWikipediaを参考にしてください。 カーネル (統計学) - Wikipedia

[f:id:hayato1986:20161227121905p:plain]sns.rugplot(data)
options = ['biw', 'tri', 'gau']

for option in options:
    sns.kdeplot(data, kernel=option, label=option, bw=0.5)

f:id:hayato1986:20161227121917p:plain

やはりガウス分布安定ですかね。。 こんな感じでPythonを使ってさくっとカーネル密度推定ができちゃいます。便利!

2次元でカーネル密度推定

ちょっと応用して、2次元でのカーネル密度推定もやってみます。相関分析時に、どのようにデータが分布されているかを把握するのに便利。「複数の突出(peak)がある場合に異なる複数の母集団から標本が抽出されている可能性」を見分ける強い味方ですね。

いつものirisデータを引いてきて、plotします。

iris = sns.load_dataset("iris")
sns.kdeplot(iris.sepal_length, iris.petal_width, shade=True)

できた!のですが、Seabornでやったほうが楽だしきれいだし見やすいです。

sns.jointplot(x="sepal_length", y="petal_width", kind="kde", data=iris);

f:id:hayato1986:20161227122501p:plain

まとめ

今年はあんまり分析できず残念。。オラッオラッオラッ(ΦωΦ)