脱ヒストグラム!Google Sheets で滑らかな「カーネル密度推定」に入門

最終更新日

📊 関数で一撃。スプシでさくっとカーネル密度推定

例えば A1:A10 に、生徒 10 人分のテストの成績が入ってるとしよう。生徒たちのテストの点数分布の確率密度を図示するために、独自関数 KDE() を使ってみよう。

Google SheetsのKDE関数の使用例を示す画像。関数の入力と詳細が表示され、データ分析を行うための手順が説明されている。
KDE() を使う様子

KDE() は 3 つの引数を取る。

  1. データ。この場合は、生徒の点数
  2. 出力する行数。だいたい 50 くらいで十分
  3. 滑らかさ。基本的には 1 で

引数を設定して入力すると、引数 2 で指定した行数 (例えば 50 行) のデータがズラッと表示される。左列が点数、右列が確率密度だ。

Google SheetsでのKDE関数の使用例を示す、テストの成績データの表
計算結果が 2 列に渡って表示される

出力の左列を x 軸に、右列を y 軸に折れ線グラフを描けば、推定された確率密度曲線を見れる。

Google Sheetsのスプレッドシートにおけるデータ分布の推定結果を示すグラフ。KDE関数を使用して生成され、x軸にはデータ点、y軸には確率密度が表示されている。
滑らかな分布の曲線!

見慣れたヒストグラムと比べてみよう。ヒストグラムも、データの分布を可視化するのに便利な図だけど、集計の始点やビンの幅などの設定を変えると、同じデータでも見た目が全然変わってしまう弱点がある。

Google Sheetsのデータ分布推定を示した画面。左側にはKDE関数の出力結果をグラフ化した滑らかな曲線、右側にはヒストグラムのデータが表示されている。
ヒストグラムでは見えなかった「データ本来の姿」を炙り出せた…かも!

それに対し KDE() は、このビンの影響を排除できるのが大きな強み。KDE() の結果は、ヒストグラムの「ビンの幅」に相当する3 つ目の引数 (滑らかさ) の設定に依存するが、ヒストグラムのようにビンの境界に結果が左右されることはなく、データが本来持つ滑らかな分布形状をより忠実に推定できる。

📝 コピペで動く。カスタム関数 KDE() を使ってみよう

Google Sheets の名前付き関数に、以下の関数を登録して使ってね。

= let(
  _data, filter(data, isnumber(data)),
  n, count(_data),
  iqr, quartile(_data, 3) - quartile(_data, 1),
  h, 0.9 * min(stdev(_data), iqr / 1.34) * power(n, -0.2),
  lo, min(_data) - h * 3,
  hi, max(_data) + h * 3,
  xs, sequence(rows, 1, lo, (hi - lo) / (rows - 1)),
  kernel, map(xs, lambda(x, sum(arrayformula(norm.dist(x, _data, h * smoothness, false))) / n)),
  {xs, kernel}
)

設定画面はこんな感じ。引数は順番が大事なので注意してね。

Google SheetsでのKDE関数の詳細設定画面のスクリーンショット。引数や定義が表示されている。
名前付き関数の編集
Google Sheetsの関数KDE()の引数設定画面、データ、行数、滑らかさの説明が表示されている
補足情報

🔍 知って納得。裏の仕組みを覗いてみよう

一見すると複雑な KDE() も、その仕組みは 2 行で説明できるくらい単純だ。

  1. 各データ点の周りに小さなコブを置く
  2. 各コブを全部積み重ねる

置いたコブは、正規分布。平均は各データ点で、分散は適当に調整されている。

Google SheetsでKDE関数を使用して学生のテストの分布を示す折れ線グラフ
各データ点の周りに小さなコブを置く
Google Sheetsでのカーネル密度推定を示す折れ線グラフとその分布域。
各コブを全部積み重ねる

🛠️ もっと知りたい!詳しい実装の解説

KDE() は、ある種のカーネル密度推定を実行する関数。カーネル関数に正規分布を使い、バンド幅に Silverman のルールを適用したもの。仕様は、R の関数 density() のデフォルトを参考にした。

項目R の density() のデフォルト自作の KDE() の動作
カーネル正規分布 (ref)正規分布のみ
バンド幅Silverman のルール (ref, ref)Silverman のルールのみ
出力範囲の端点データ端からバンド幅 3 つ分 (ref, ref)データ端からバンド幅 3 つ分のみ
平滑化バンド幅 1 倍 (ref)引数で指定 (推奨: 1)
出力点の数512 点 (ref)引数で指定 (推奨: 50)
R の関数 density() と、自作関数 KDE() を比べてみると

Google Sheets で使うことを考えて、データを除いて引数は 2 つとシンプルに抑えてみた。

  • 「出力点の数」は、選べないと不便だと思う。引数で指定できるのが自然でしょう
  • 「平滑化」は、パラメータスタディする “楽しみ” のために入れてある。実用上は Silverman のルールで足りるでしょうから、不可欠ではないと思うけどね

それにしても、オープンソースの R は実装を参照できて素晴らしいね!統計ソフトで他に有名な Matlab は、商用ソフトなのでコードが非開示で研究できない。Matlab 互換な OSS GNU Octave は普及してるのかな?寡聞にして初めて知りました…😅

1件のコメント

コメントを残す

回れ右の内輪差をもっと見る

今すぐ購読し、続きを読んで、すべてのアーカイブにアクセスしましょう。

続きを読む