俺のOneNote

俺のOneNote

データ分析が仕事な人のOneNote愛とか、分析小話とか。

log_level_modelのパラメータ解釈

乗法モデル

単純なGLMにおいて、目的変数・説明変数(もしくは片方のみ)を対数変換したほうがより解釈しやすいケースがあります。
一般的に、目的変数・説明変数ともに対数変換したモデルは乗法モデル(弾力化モデル)と言われるようです。

(参考) 対数変換を行う意味について。回帰分析において対数変換する背景にある前提とは?|アタリマエ!

計量経済学分野では比較的ポピュラーな方法ですが、
使おうと思ったときに対数変換によってパラメータの解釈が代わる証明が不安だったので備忘録的に書きます。

なお、ここでは目的変数のみを対数変換する log-level-model になります。(※log-logがいいのか、level-logがいいのかはモデルの当てはまりや課題に応じて決めたほうが良さそうです)
log-level-modelのパラメータ解釈は、説明変数1単位の増加による目的変数の増加率(%)になるはずです。

(参考) Data Science Simplified Part 7: Log-Log Regression Models | by Pradeep Menon | Towards Data Science

証明

$$ \begin{eqnarray} \log y &=& \alpha + \beta x + \epsilon \ \end{eqnarray} $$

まず両辺を微分し、

$$ \begin{eqnarray} \dfrac{d}{dx} \log y &=& \dfrac{d}{dx} (\alpha + \beta x + \epsilon) \\ \beta &=& \dfrac{d \log y}{dx} \end{eqnarray} $$

ここで、合成関数の微分公式より

$$ \begin{eqnarray} \dfrac{d \log y}{dx} &=& \dfrac{d \log y}{dy} \cdot \dfrac{dy}{dx} \tag{1} \end{eqnarray} $$

$(1)$右辺の $d \log y / dy$ は対数関数の微分公式より

$$ \begin{eqnarray} \dfrac{d \log y}{dy} &=& (\log y)' &=& \dfrac{1}{y} \end{eqnarray} $$

したがって $(1)$ は以下のとおり

$$ \begin{eqnarray} \dfrac{d \log y}{dy} \cdot \dfrac{dy}{dx} &=& \dfrac{1}{y} \cdot \dfrac{dy}{dx} \\ &=& \dfrac{dy/y}{dx} \end{eqnarray} $$

よって、 $$ \begin{eqnarray} \beta &=& \dfrac{dy/y}{dx} \end{eqnarray} $$

  • $dy/y$ は $y$ の増加
  • $dx$ は xの増加

以上により、パラメータ$\beta$ は$x$の増加量に対する$y$の増加率であることが証明できました。
なお、log-log-modelも同じ手順で証明できます。

無事、log-level-modelのパラメータの解釈が理解できたところで、実データで解釈性を見ていきます。

利用データ

seaborntipsデータセットを利用します。参考

df =  sns.load_dataset("tips")

f:id:kopaprin:20220201005511p:plain

支払額や性別、人数などに応じて、チップがいくら払われたかのデータセットのようです。
これを題材にしていきます。

なお、モデリングには以下のようにダミーデータ化し、簡単のためdayは除外しています。 f:id:kopaprin:20220201010105p:plain

データの概観

目的変数とするtipは以下のような分布となっており、やや右すそが長い対数正規分布に近い形です。 f:id:kopaprin:20220201005925p:plain

データ上0以下にはならないため、ここだけ見ても通常の正規分布を仮定した一般線形モデルはあまり適さなそうであることが分かります。
が、今回の趣旨はパラメータ解釈の違いを見たいのでこの辺は論点にしません。

level-level-model

まずはlevel-level-model、つまり単純な一般線形モデルでのモデリング結果です。

level_level_model = """

data {
  int N ; // データ数
  int C ; //説明変数カラム数
  matrix[N,C] X ; //説明変数
  vector<lower=0>[N] Y ;  // tip 目的変数
}

parameters{
  vector[C] b ; //パラメータ
  real<lower=0> s_Y ; //標準誤差
}

model {
  Y ~ normal(X*b, s_Y) ;
}

generated quantities {
  real y_pred[N];
  y_pred = normal_rng(X*b, s_Y) ;
}

"""

log-level-model

次いで、log-level-model

log_level_model = """

data {
  int N ; // データ数
  int C ; //説明変数カラム数
  matrix[N,C] X ; //説明変数
  vector<lower=0>[N] Y ;  // tip 目的変数
}

parameters{
  vector[C] b ; //パラメータ
  real<lower=0> s_Y ; //標準誤差
}

model {
  log(Y) ~ normal(X*b, s_Y) ;
}

generated quantities {
  real y_pred[N];
  y_pred = normal_rng(X*b, s_Y) ;
}

"""

本来はWAICやWBICで評価したり、バリデーションデータセットで評価すべきなのでしょうが、 こちらも簡単のため(めんどくさい)とりあえず目的変数Yと事後予測分布のEAP定量のMAEで評価してみました。

print("MAE")
print("level-level-model : ",mean_absolute_error(df_fix["tip"],fit_level_level.extract()["y_pred"].mean(axis=0)))
print("log-level-model : ",mean_absolute_error(df_fix["tip"],np.exp(fit_log_level.extract()["y_pred"].mean(axis=0))))

MAE
level-level-model : 0.736165905967111
log-level-model : 0.7633751430630242

うーん、log-level-modelのほうが悪いですね(爆)
この辺は自分のモデリングや評価が適当だったりすることにも起因する気がするので、あまり気にしないようにしましょう(白目)

パラメータ評価

level-level-modelとlog-level-modelのパラメータのEAP定量は以下のとおりです。

f:id:kopaprin:20220201012233p:plain

例えばsexを見ると、(ここではFemale = 1, Male = 0)
女性の場合level-level-modelでは0.026ドル(?) 男性より多くチップを払うことが期待されます。 一方log-level-modelでは、1.3%多く払うことが期待できます。

解釈の違いは上記の言葉のとおりですが、モデルの前提としては大きく異なります。
level-level-modelでは「どんなに高額な食事をして、大人数でも女性なら0.026ドル多く払うだけ」と考えています。
一方、log-level-modelは「総支払額が高ければ高いほど、女性の場合チップ支払い額が1.3%多くなる」と考えています。

なんとなくですが、10ドルの食事をしたケースと100ドルの食事をしたケースでは、チップの支払額も相対的に高くなりそうです。
このように、変数の影響の解釈とモデルの考え方が、対数変換するだけでかなり変わってくることがわかります。
うまく取り扱えば、マーケティングのための顧客理解や現象理解に役立てることができると思います。

おまけ

チップ支払い額には個人差が大きく関与しそうな気がします。
(これはダミーデータかもしれませんが・・・) 個人差 $mu$ をモデルに入れた階層モデルでもやってみました。

multi_log_level_model = """

data {
  int N ; // データ数
  int C ; //説明変数カラム数
  matrix[N,C] X ; //説明変数
  vector<lower=0>[N] Y ;  // tip 目的変数
}

parameters{
  vector[C] b ; //パラメータ
  vector[N] mu ; //個人差
  real<lower=0> s_Y ; //標準誤差
  real<lower=0> s_mu ; //個人差誤差
}

model {
  mu ~ normal(0, s_mu) ;
  log(Y) ~ normal(X*b + mu, s_Y) ;
}

generated quantities {
  real y_pred[N];
  y_pred = normal_rng(X*b + mu, s_Y) ;
}

"""

さてMAEは、

MAE
level-level-model : 0.736165905967111
log-level-model : 0.7633751430630242
multi-log-level-model : 0.31669395645238413

ほかと比べるとダントツで低いですね(当たり前なんですが)

個人差を考慮すると、パラメータの解釈も少し変わります。

f:id:kopaprin:20220201021545p:plain

通常のlog-level-modelは個人差を一切無視し、データ化された変数に応じてチップが決まるモデルです。
一方、階層モデルだと、データ化されていない個人差が背景にあることを仮定しているので、その影響を除いた本来の各説明変数の効果が計測されていると解釈することができます。

・・・と、ここまで書いておいて、個人差を考慮した真の効果というのは論理の飛躍で拡大解釈なのではないか?と考えてしまいました・・・。 その辺までちゃんと勉強していきたいと思うので、階層モデルの件はおまけ程度にとどめておきます。

二項分布→ポアソン分布導出

二項分布 B(n,p)のnpを一定とし、n→∞にするとポアソン分布 Po(λ)になります。

その導出過程をまた書きました。(間違ってたらごめんなさい)

f:id:kopaprin:20210503144030p:plain

Combinationの変換とかe導出のための指数公式の利用とかテクニカルすぎて完全忘れてたので、
よい復習になったよ。。。。

Binomial(n,p)の期待値・分散導出

ペンタブ練習。 二項分布の期待値と分散を導出する公式です。

f:id:kopaprin:20210430234316p:plain

多少慣れると細かい文字書くのもイケますねー。

ペンタブうんぬん以前に、 そもそもちょっと字が汚い・・・・

同ディレクトリ内データ結合はExcelで超簡単にできることが全世界に広まってほしい

今日のお悩み

あるディレクトリ内に、同じようなCSV・xlsxをたくさんつくって、後で結合しなきゃいけない

とか

100個レイアウトが同じデータがあるんだけど結合作業が死ぬ

とかで困ったことがある人は絶対いると思うんですが、

Excelで一発ですよ。

というお話です。

Power Queryを知らなくても簡単

機能的には Power Queryという機能なんですが、知らなくても大丈夫。 クリックだけでできちゃう。

こんなデータ構造はお仕事でよく見る話

f:id:kopaprin:20210204224410j:plain

ちなみに中に入っているのは全部同じテーブル構成。

サンプルはちょっとだけですが、100ファイル・100ディレクトリあったらうんざりです。

Excelデータタブ > データの取得 > ファイルから > フォルダーから

f:id:kopaprin:20210204224550j:plain

たくさんデータファイルが入っているディレクトリのパスをコピペすると・・・

f:id:kopaprin:20210204224730j:plain

勝手に一覧で読み込んでくれました

あとは結合を押して読み込むと。

f:id:kopaprin:20210204224830j:plain

ちゃんとテーブルにしてくれましたー!

ちなみにSource.Nameでファイル名もカラム化してくれるので大変に良き。

Excel Power Queryに詳しくなれば、 多少カラム内容が違うものでも処理できるようにプログラムできます。

support.microsoft.com

データが100個あってもあきらめないでくださいませ。

OneNoteのリンクを共有する時の注意点

表題のとおり、OneNoteのリンクを共有するときにちょっとハマったので覚書。

特定のページを誰かと共有したいときは多くありそうな気がしますが、上側の共有ボタンは「ページ」の共有には不適切。 f:id:kopaprin:20201216142926j:plain

f:id:kopaprin:20201216142940j:plain

f:id:kopaprin:20201216142952j:plain

ここで生成されたリンクを開くと、上記のとおりノートブックのトップに飛んでしまう。 あくまで「ノート」を共有したいときの機能。

「ページ」を共有したいときは、該当ページから右クリック→「ページへのリンクをコピー」を使う。 f:id:kopaprin:20201216143010j:plain

自動的にタイトルがハイパーリンクになって大変に良き。 f:id:kopaprin:20201216143029j:plain

だれかにメモ書きを共有したいときは忘れずこのページリンクを使いましょう。

TableauでUnitChartを作る

先般 Tableau Makeover Monday 2020/W36に参加しました。

そこでUnit Chartを使いたかったので少しお勉強した結果を備忘録します。

Unit Chart

ピクトグラム(Pictorial Fraction Chart)とか呼ばれたりもします。

Pictorial Fraction Chart | Data Viz Project

Viz作品では以下のような感じで、砂糖&食物繊維がどれくらい含まれているかを一目で理解できるようにするために用いました。

Tableau Public

f:id:kopaprin:20200923160338j:plain

作成方法は先駆者がすでに色々発信してくれていますので、こちらも参照するといいと思います。

Creating A Unit Chart in Tableau - The Data School

https://vizartpandey.com/unit-chart-in-tableau/

ここで紹介するのは、上記例よりかなり稚拙ですが、 簡素に実装した例です。

データ準備

まずはUnit Chartで表したい集計値を用意します。

f:id:kopaprin:20200923160354j:plain

以下紹介する実装内容は、集計済みテーブルがある場合にのみ対応しているので、
トランザクションデータからメジャーで集計・可視化する場合は別途他の方法をご検討いただけるとよいです。

つづいて、ピクトグラムの位置情報となる座標テーブルを用意します。

f:id:kopaprin:20200923160404j:plain

colピクトグラムのX座標、rowはY座標になります。
この例では1行10列のピクトグラムになることが分かります。
compareは色分け時に利用するものです。

先ほどの集計データは10が最大値でした。
そのため、ピクトグラムの最大も10にしています。
ここの数は、手持ちのデータを踏まえて最大値を決める必要があります。

データモデル設計

先ほど用意した集計データを読み込みます。

f:id:kopaprin:20200923160418j:plain

つづいて、作成した座標データをjoinします。 f:id:kopaprin:20200923160434j:plain が、もちろん結合キーが無いのでエラーになります。

ここで、集計データすべてに対して、ピクトグラムの座標情報を与えたいので、
Full Outer Joinできるよう関係式として1を作成します。

f:id:kopaprin:20200923160448j:plain

これで狙い通り、全組み合わせをJoinしたデータモデルを用意できます。

f:id:kopaprin:20200923160513j:plain

Vizの準備

col , row をそれぞれ列・行に配置します。
メジャーだと集計されてしまうので、ディメンションに変換するのを忘れずに。

f:id:kopaprin:20200923160537j:plain

以下色分け用のBooleanを用意します。

MAX([Value]) >= MAX([Compare])

これは、集計値(Value)よりも比較値(Compare)が大きければTrue,
小さければFalseを返します。

f:id:kopaprin:20200923160651j:plain

これを「色」マークに配置すれば、各Classごとの色分け条件を評価するため、集計値以下のマークと以上のマークの色分けができるようになります。

f:id:kopaprin:20200923160709j:plain

あとは適当に補助線を消したり、
アイコンを以下のようなサイトで選んで変更して完成です。

アイコン素材ダウンロードサイト「icooon-mono」 | 商用利用可能なアイコン素材が無料(フリー)ダウンロードできるサイト | 6000個以上のアイコン素材を無料でダウンロードできるサイト ICOOON MONO

f:id:kopaprin:20200923160936g:plain

Appendix

ちなみに最大値10のデータを1行10列で表現しましたが、 2行5列ではどんな感じになるでしょうか??

その場合は以下のような座標情報を用意してあげればOKです。

f:id:kopaprin:20200923173932j:plain

結果は以下のようなイメージ。

f:id:kopaprin:20200923161115g:plain

集計済みデータにしか対応していないので、中々使い勝手が悪いですが、
スポットの可視化に対しては手軽にできるので便利でした。