アソシエーション分析 -mlxtendを使ったリフト値の算出方法-

この記事でわかること

  • アソシエーション分析(バスケット分析)にてよく参照されるリフト値の定義とその読み取り方
  • pythonにてアソシエーション分析を実行する方法(mlxtend の apriori, association_rulesを利用)
  • association_rules関数にて返される各種指標の定義
  • (おまけ:リフト値を重みとして用いた共変量と目的とする行動のネットワーク可視化)
    • 長くなりそうなので,これは後日作成します.

アソシエーション分析とは

本記事で利用するデータセット

 アソシエーション分析を説明する前に,本記事で利用するデータセットと用語の説明を行います.本記事では,Online Retail Datasetというデータセットを利用します.データはおなじみのUCI machine learning repositoryからDL可能です.このデータセットはイギリスのオンラインショップの購買履歴データで,領収書番号ごとに,どの商品がどれくらい購入されたかが記録されています.今回は,一つの領収書(InvoiceNo)で10商品以上購入された取引のみに限定し,アソシエーション分析を用いて,ある商品が購入されやすくなるようなその他の商品の組み合わせを同定します.

InvoiceNoStockCodeDescriptionQuantityInvoiceDateUnitPriceCustomerIDCountry
1234568512Awhite plate12012/4/42000T2134987UK
1234567Y85white cup12012/4/41000T2134987UK
236789432Wchristmas tree12012/12/14500T4313512Japan
245698219Jlantern12012/10/53000T5436548Canada
利用データのイメージ.値は仮想的に振っている.

アソシエーション分析

 先ほど,「ある商品が購入されやすくなるようなその他の商品の組み合わせ」と書きましたが,それを観念的に(≒正確ではないざっくりとしたイメージで)書くと,

$$A\rightarrow C$$

のように書けます.これは,(こちらも観念的ですが,)Aという商品を買うと,Cという商品が買われやすくなると解釈されます.この時のAを先行事象(antecedents),Cを結果事象(consequents)と呼ぶこととします.アソシエーション分析は,先行事象Aが起こった時の結果事象Cの起こりやすさの程度をリフト値により定量化する分析と見ることができます.

リフト値とは

\(A\rightarrow C\)のリフト値\(lift(A\rightarrow C)\)は以下のように定義されます.

$$lift(A\rightarrow C) := \frac{P(C|A)}{P(C)}$$

定義から明らかなように,リフト値とは,無条件の結果事象Cの生起確率と比較して先行事象Aが生起した集団に絞った場合の結果事象Cの生起確率は何倍になるか?を定量化したものと考えられます.以下で実際に計算して見ましょう.単純な定義であるため,具体的な計算が不要な方は,次節へお進みください.下表のようなデータがあったとします.

商品Xを購入商品Yを購入商品Zを購入
Aさんしたしたした
Bさんしたしてないしてない
Cさんしてないしたした
Dさんしてないしてないした
Eさんしてないしたした
Fさんしたしてないしてない
Gさんしてないしたした
Hさんしてないしてないしてない
Iさんしたしたしてない
Jさんしたしてないしてない
仮想データ

この時,結果事象を「商品Zを購入した」,先行事象を「商品Xを購入した」「商品Yを購入した」とすると,

$$\begin{align} P(Z)&=0.5\\ P(X\cap Z) &= 0.1\\P(Y\cap Z) &= 0.4\\P(Z|X) &= P(Z\cap X)/P(X) = 0.1/0.5 = 0.2\\P(Z|Y) &= P(Z\cap Y)/P(Y) = 0.4/0.5 = 0.8\end{align}$$

より,

$$\begin{align}lift(X\rightarrow Z) &= 0.2/0.5 = 0.4\\lift(Y\rightarrow Z) &= 0.8/0.5 = 1.6\end{align}$$

のように計算されます.この時商品Yのリフト値が1を超えていることから,商品Yを購入した場合,商品Zが多少買われやすくなっていると解釈します.

mlxtendライブラリを用いた実行例

本節では,細かい前処理などは説明せず,

  1. aprioriに入力するデータ形式への変換方法
  2. aprioriの結果をassociation_rulesに入力し,リフト値を算出する方法

のみを紹介します.全ノートブックはgithubに後日上げる予定なので,実際に動かして見たい方はそちらをご参照ください.

1. aprioriに入力するデータ形式

aprioriに入力するデータは先ほどの表のように,顧客xある商品を購入したかのテーブルです.今回利用データの例だと,InvoiceNo単位でuniqueになるように,データを一度集約し,その後ダミー変数かします.

# ...この前にデータ読み込みなどがあるが,割愛
## InvoiceNo単位でどの商品を購入したかを集約
df = df_.groupby(["InvoiceNo", "Description"]).agg({"Description":"count"})

## 1つのInvoiceNoで同じ商品を複数回買っている場合は,その回数を1に置き換える.
df["Description"] = df["Description"].apply(lambda x: 1 if x >= 1 else 0)

## 集約したデータを顧客x商品のダミー変数のテーブル形式へ変換する(0: 購入してない,1:購入した)
df = df.unstack().fillna(0)

2. リフト値の降順に先行事象を表示する

 aprioriに入れられるデータ形式に変換してからは,aprioriにデータを入れて出てきた結果をassociation_rulesに入れるだけで,リフト値を算出できます.

# サイズが大きいため,少し時間がかかる
freq_items = apriori(df, min_support = 0.01, use_colnames=True)
freq_items.sort_values("support", ascending=False)

# アソシエーション分析の実行
rules = association_rules(freq_items, metric="lift", min_threshold = 0.00).sort_values(by=["lift", "support"], ascending=False) # アソシエーション分析を実行し,リフト値の降順に並び替える降順に並び替える
rules["n_antecedents"] = rules["antecedents"].apply(lambda x: len(x)) # 先行要素の個数の追加
rules["n_consequents"] = rules["consequents"].apply(lambda x: len(x)) # 結果要素の個数の追加

# 同時に購入されやすい商品の組み合わせのリフト値&その他の表示
rules.loc[(rules["n_antecedents"] == 1) & (rules["n_consequents"] == 1), ["antecedents", "consequents", "lift"]]

まとめ

本記事では,

  • アソシエーション分析(バスケット分析)にてよく参照されるリフト値の定義とその読み取り方
  • pythonにてアソシエーション分析を実行する方法(mlxtend の apriori, association_rulesを利用)
  • association_rules関数にて返される各種指標の定義

について紹介いたしました.今回ご紹介したカート内の併売されやすい商品の組み合わせの特定の他にもさまざまなEDAとして利用できるアソシエーション分析をぜひ利用して見てください!

References

コメント

タイトルとURLをコピーしました