AIコード補完を活用してデータ分析をもっと手軽に！

# はじめに
データ分析と聞くと、PythonやRでのプログラミングを想像する方が多いのではないでしょうか。
近年は、GUIで分析可能なツールも様々出てきていますが、
分析が複雑になるとやはりプログラミングなしでは限界があると感じます。

例えば、**Dataiku**は、ノーコード・ローコードでハイレベルな分析や機械学習を行うことが可能なツールです。
一般的な分析はもちろん、AutoMLのような機能により非常に高度な機械学習もノーコードで行うことができます。
一方で、高度なデータ変換処理や機械学習以外の手法（データマイニングや統計分析）を活用する場合、どうしてもコードによる操作が求められる時があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/3c3b2cc4-cb5e-25c5-442e-50c1c53cc0be.png)

プログラミングは、経験がない人にとっては難しく思えます。
ただ、最近ではAIがコードを自動で書いてくれるようなツールも登場し、
プログラミングの敷居は下がってきているように感じます。

そこで、今回は、コード補完機能を追加し、データマイニングの手法の一つであるバスケット分析を行ってみたところ、データ分析が非常にお手軽になったのでご紹介します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/b01d9456-d4bb-cbc0-c645-dee30c9380d9.png)


# コード補完機能を使った分析
今回行う分析は、バスケット分析です。
バスケット分析とは、主に小売業について行われるもので、顧客の購買履歴などから関連性のある商品やアイテムを探し出し、**一緒に購買される傾向のあるアイテムを特定する手法**です。

この分析を行うには、Pythonで特定のアルゴリズムを使用したり、というのが必要になります。
そのあたりのコードをしっかり補完してくれるかどうか、ちょっと試してみました。

## 分析環境
ではまず、今回の分析環境について見ていきます。

今回はDataiku上のJupyterNotebookを使用します。
ここに補完機能をつける手段として、今回は**Azure OpenAI service**を使ったマジックコマンドを採用しました。

理由として、今回のJupyterNotebook上ではAzure OpenAI Studioが使えないため、APIを使用、すなわちAzure OpenAI serviceにプロンプトを投げ、コードを返してもらうようなマジックコマンドを採用しました。

マジックコマンドの定義は以下の通りです。
~~~Python
import openai
from IPython.core.magic import register_cell_magic

@register_cell_magic
def gpt3_magic(line, cell):
    prompt = cell.strip()
    response = openai.Completion.create(
        engine="code-davinci-002",
        prompt=prompt,
        temperature=0.0,
        max_tokens=1000,
        top_p=1,
        frequency_penalty=0,
        presence_penalty=0,
        stop=None)

    print(response['choices'][0]['text'])
~~~
使用したモデルは"code-davinci-002"、Codexのモデルです。
以下のようにマジックコマンドを宣言し、プロンプトを記述して実行することでレスポンスが出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/929ad7f9-4a95-d8a0-72be-5a266e2b03b6.png)


## 使用するデータ
今回用意したデータは、以下のような購買データです。
「購入日時」「トランザクション」「購入された商品」の情報を持っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/5cff000d-b099-a1b5-1da3-b951c216f244.png)


## 前処理＆分析
さっそくですが、ここでコードの力を借りて前処理（テーブル加工）と分析をやっていきます。
今回はコードを補完機能として、マジックコマンドを使用してプロンプトをAPIに投げる方式で実装しました。（詳細は[後述](#コード補完機能の実装)）
ここで、より良いレスポンスを得るために、プロンプトになるべく情報を盛り込みます。
まず、「分析に使うテーブルがどんな列を持っているか」を冒頭で記述します。
そして、データの読み込む処理と分析に必要な閾値の設定だけコードを記述し、続きを書いてもらうよう命令します。
（Dataikuの場合、Jupyternotebookのファイルを作成した時点でデータ読み込むためのコードがすでに記述してあります。なのでそれをそのまま使用すればOKです）
~~~Python
%%gpt3_magic
"""
'BreadBasket_DMS'データセットは、'Date'列、'Time'列、'Transaction'列、'Item'列で構成されたテーブルです。
'Transaction'列が意味するのはトランザクションIDですが、重複が許されています。
'Item'列には1レコードにつき1アイテムのみが存在します。
'BreadBasket_DMS'データセットを使い、バスケット分析を行うよう以下のコードを完成させて下さい。

import dataiku
import pandas as pd, numpy as np
from dataiku import pandasutils as pdu

# データセットの読み込み
BreadBasket_DMS = dataiku.Dataset("BreadBasket_DMS")
BreadBasket_DMS_df = BreadBasket_DMS.get_dataframe()

support_threshold = 0.005
confidence_threshold = 0.005

# バスケット分析
"""
~~~

レスポンスのコードは以下のようなものでした。
~~~Python
import dataiku
import pandas as pd, numpy as np
from dataiku import pandasutils as pdu
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules

# データセットの読み込み
BreadBasket_DMS = dataiku.Dataset("BreadBasket_DMS")
BreadBasket_DMS_df = BreadBasket_DMS.get_dataframe()

support_threshold = 0.005
confidence_threshold = 0.005

# バスケット分析
basket = (BreadBasket_DMS_df.groupby(['Transaction', 'Item'])['Item']
          .count().unstack().reset_index().fillna(0)
          .set_index('Transaction'))
basket_sets = basket.applymap(lambda x: 1 if x >= 1 else 0)
frequent_itemsets = apriori(basket_sets, min_support=support_threshold, use_colnames=True)
rules = association_rules(frequent_itemsets, metric="lift", min_threshold=confidence_threshold)
~~~
正直驚きました。
まず、バスケット分析のためにグループ化やピボット処理、欠損値処理、インデックス付与などをしてくれています。（可読性は少し気になりますが。。）
また、バスケット分析のためのモジュールを新しくインポートし、アイテムセットの抽出やアソシエーションルールの算出を行ってくれました。

これをデータとして書き出すと以下のようなものになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/7a6e7afd-3b78-aff4-cc66-912fbee79566.png)
テーブルに書いてある数値はアソシエーションルールと呼ばれ、商品が一緒に購入されるかどうかを判断するための指標になります。
以下に簡単に意味を示しますので、興味がある方はご覧ください。

> Support：一回の買い物で購入される確率
> Confidence：antecedentが購入されたときにconsequentが購入される確率
> Lift：ConfidenceをconsequentのSupportで除したもの。Confidenceが高くてもLiftが低かったら明確な関係性はないかも、、みたいな解釈で良いかと思います。

これで、一緒に購入されている確率の高いアイテムセットを抽出することができました。




## 可視化
テーブルのままでは見づらいので、Dataikuの標準機能を使って可視化していきます。
いくつか見ていきましょう。

以下の4つのグラフは、コードで加工する前の最初のデータから得ることができます。
トランザクション数の推移を日別、月別で確認することができたり、特定の商品にフォーカスして販売数の推移を確認することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/02dc2674-1d8f-adab-a697-7c064e062542.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/f307fc8f-0cf3-fd85-1727-f318643aebe1.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/222f85c7-6645-4685-d4aa-c5e18735a702.png)
今回の例では、この店舗の全体的な販売数は2016年を境に下降から若干の上昇に転じたことや、主力商品はコーヒーとパンであること、商品の多くはお昼前に（お茶やケーキはお昼過ぎに）売れる傾向があることなどがわかります。

また、コードによって新たに作成したデータからは、以下のようなネットワーク図やヒートマップが得られます。
ネットワーク図は矢印が太いほど、ヒートマップは色が濃いほど、一緒に購入される確率が高いことを示しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/e5292aa3-a8d9-286a-5256-9609ebdd62aa.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3457621/1b86ba8b-773b-0489-92b2-0afb0af652e3.png)
今回の例では、トーストや地産品（Keeping It Local）などが買われるとコーヒーがよく購入される傾向などがわかります。
一方で、ヒートマップや加工前のデータからもわかる通り、そもそもコーヒーやパンは購入されることが多いため、キャンペーンなどの判断は慎重に考える必要があることが示唆されます。


# おわりに
いかがだったでしょうか。
Dataikuはもとよりノーコード・ローコードでの機械学習ツールとして優秀な性能を持っていますが、そこにコード補完機能を加えることで、使用難易度をさして上げることなく、さらに柔軟な活用が可能になります。

なお今回、単純にコード補完機能を実装するだけならGithub copilotでも良かったのですが、
今回はビジネスシーンでの利用を意識してAzureを使ってみました。
というのも、ビジネス利用で最も気になるのはやはりセキュリティ面で、現状コードを最もセキュアに管理できるのはAzureだと感じたからです。

https://learn.microsoft.com/ja-jp/legal/cognitive-services/openai/data-privacy?context=%2Fazure%2Fai-services%2Fopenai%2Fcontext%2Fcontext#generating-completions-images-or-embeddings

今回はAzureを使ってみましたが、十分すぎる性能を発揮してくれたかなと思います。


また、最近ではcode interpreterも登場し、分析の手軽さを加速させています。
次回以降はこれについても記事を投稿していこうと思いますので、よろしくお願いいたします。