Pythonでアソシエーション分析

# はじめに
　Pythonで機械学習モデルを構築する場合、scikit-learnに含まれている処理パターン(分類・回帰・クラスタリング等)であればネット上にサンプルも数多くあり、それらを参照すれば簡単に実装可能なのですが、そうでない場合、ライブラリの選定から、実装サンプルの入手まで結構大変だったりします。
　その典型例が、マーケティング分析で多用される「**アソシエーション分析**」です。Rであればよく使われるライブラリで簡単にモデル構築が可能ですが、Pythonでは意外にそうしたサンプルコードが少ないです。
当記事は、その部分の紹介をします。
　ちなみに、より上流の業務観点でのユースケース、UCIのサンプルデータセットからの元データからの加工手段を含めた一連の手順とその解説は、私の著作「儲かるAI」の5.4節で詳しく記載しています。
関心ある方は、是非こちらの本も参照されて下さい。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/8a5e4550-3e3b-4b34-b4ef-f9cdbe3bfd81.jpeg" width=30%>

Amazon 単行本
https://www.amazon.co.jp/dp/4296106961/

Amazon Kindle
https://www.amazon.co.jp/dp/B08F9P726T/

書籍サポートページ
https://github.com/makaishi2/profitable_ai_book_info/blob/master/README.md

# 利用データ
次のリンク先のデータを利用します。

https://github.com/makaishi2/sample-data/blob/master/data/retail-france.csv

このデータはUCIデータセットから一定の加工を行ったあとのものです。
ここに至るまでの加工手順については、上述の書籍を参考にして下さい。

# 実装コード概要
以下に、このデータを使ったアソシエーション分析実装コードの概要を示します。
Notebook全体については、

https://github.com/makaishi2/sample-notebooks/blob/master/profitable-ai/association-sample.ipynb

にアップしておきました。

## 共通処理
書籍共通の事前処理のうち、今回のサンプルで関係ある部分を抽出しました。

```py3
# 共通事前処理

# 余分なワーニングを非表示にする
import warnings
warnings.filterwarnings('ignore')

# 必要ライブラリのimport
import pandas as pd
import numpy as np

# データフレーム表示用関数
from IPython.display import display

# 表示オプション調整
# pandasでの浮動小数点の表示精度
pd.options.display.float_format = '{:.4f}'.format

# データフレームですべての項目を表示
pd.set_option("display.max_columns",None)
```

## データ読込み
上で示した事前加工済みCSVデータをデータフレームに取り込みます。

```py3
url = 'https://raw.githubusercontent.com/makaishi2/sample-data/master/data/retail-france.csv'
df = pd.read_csv(url)
display(df[100:110])
```

display関数の結果はこんな形になるはずです。

![スクリーンショット 2020-09-22 9.20.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/c1643217-bc1c-7b5b-bec4-4045abd97194.png)

## データ加工
上記のデータに対してアソシエーション分析をするためには、データをヨコ持ち形式に変換する必要があります。
(ヨコ持ちとはそもそも何か知りたい方は書籍を参照して下さい)
そのための実装コードが下記になります。

```py3
# 発注番号と商品番号をキーに商品個数を集計する
w1 = df.groupby(['発注番号', '商品番号'])['商品個数'].sum()

# 結果確認
print(w1.head())
```

この段階でのw1の状態は以下のとおりです。

![スクリーンショット 2020-09-22 9.25.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/1a247f9c-3043-4ab5-2ae8-cabeffa572bb.png)

unstack関数を使って行にあった商品番号を列に移動します。

```py3
# 商品番号を列に移動 (unstack関数の利用)
w2 = w1.unstack().reset_index().fillna(0).set_index('発注番号')

# サイズ確認
print(w2.shape)

# 結果確認
display(w2.head())
```

結果は次のようになります。

![スクリーンショット 2020-09-22 9.27.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/66830e6e-c96f-9820-95ec-49e10b3f1cdf.png)

最後にデータフレームのapply関数で、各要素を数値から　True / False のバイナリ値に変換します。

```py3
# 集計結果が正か0かでTrue/Falseを設定
basket_df = w2.apply(lambda x: x>0)

# 結果確認
display(basket_df.head())
```

結果は次のとおりです。これでアソシエーション分析のための前処理は完了しました。

![スクリーンショット 2020-09-22 9.30.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/227bbcb1-ac4a-d5f3-6376-5c2030fabb7b.png)

## モデル構築
アソシエーション分析のライブラリとしてはmlextendを利用します。
mlextendは、sckit-learnほど有名ではないですが、scikit-learn同様の、Python機械学習用のライブラリです。

最初にmlxtendのライブラリを導入します。

```py3
# mlxtend の導入
!pip install mlxtend
```

次に分析で利用する関数``apriori``と``association_rules``をimportします。

```py3
# ライブラリの読み込み
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
```

最初にアプリオリ分析という手法で「**サポート**」と呼ばれる数値の値が高い商品間の関係を抽出します。

```py3
# アプリオリによる分析
freq_items1 = apriori(basket_df, min_support = 0.06, 
    use_colnames = True)

# 結果確認
display(freq_items1.sort_values('support', 
    ascending = False).head(10))

# itemset数確認
print(freq_items1.shape[0])
```

次のような結果になります。

![スクリーンショット 2020-09-22 10.21.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/1f98020d-b3ea-5546-4789-3e46fb39acf7.png)

最後に抽出したリストに対して「**リフト値**」の高い関係を抽出します。

```py3
# アソシエーションルールの抽出
a_rules1 = association_rules(freq_items1, metric = "lift",
    min_threshold = 1)

# リフト値でソート
a_rules1 = a_rules1.sort_values('lift',
    ascending = False).reset_index(drop=True)

# 結果確認
display(a_rules1.head(10))

# ルール数確認
print(a_rules1.shape[0])
```

以下のリストが最終結果です。

![スクリーンショット 2020-09-22 10.22.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/73f4c7ce-2ae3-f4e7-6ba1-2a8f24862407.png)

書籍の中では、上記の結果を元にNetworkXを使って下のような関係グラフを作ることもやっています。

![graph.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/206130/1ae03e70-a658-63c1-1d79-18aa61828690.png)

なお、ここで出てきた技術用語である「**サポート**」「**リフト値**」については、書籍の中で解説しているので、そちらを参照して下さい。