あなたのデータから学ぶ:Pythonとpandasでアソシエーション分析 (2021/11/30)

あなたのデータから学ぶ:Pythonとpandasでアソシエーション分析 (2021/11/30)

https://www.oracle.com/news/connect/association-analysis-data-python-pandas.html

トランザクションデータ内のアイテム間の関係を特定し、その関係に基づいてビジネス上の意思決定を行うことができます。

投稿者:Yuli Vasiliev



あなたの組織には大量のトランザクションデータがあり、毎日さらに多くのデータが作成されています。これらのデータベースレコードには、非常に貴重な知識があります。アソシエーション分析は、このデータから有用な情報を抽出し、組織に利益をもたらすことができます。この記事では、トランザクションデータ内の項目間の関係を特定し、実用的な洞察に変えるために、この技術を活用する方法を説明します。


関連付け分析の基本について簡単に説明した後、PythonとOracle Databaseでトランザクションデータのサンプルセットに関連付け分析技術を適用した例を比較します。この記事は、PythonとOracle Databaseに関する知識(pipでライブラリをインストールできるなど)を前提としています。


アソシエーション分析の紹介


アソシエーション分析は、コレクション内のアイテムの共起の確率を発見します。共起するアイテム間の関連性の強さは、アソシエーションルールと呼ばれる指標によって測定されます。本質的には、アソシエーションルールは、アイテム間の関係の確率を表すIF-THENステートメントです。ここで、XはルールのIFコンポーネントであり、先行詞と呼ばれ、YはTHENコンポーネントであり、結果詞と呼ばれます。もっとわかりやすく言うと、アソシエーション分析とは、データセットのあるレコードでXが発生した場合、Xが同じレコードに現れる可能性がどれくらいあるかを示すものです。


IF-THEN表記では、上記のルールはIF X THEN Yと表記されることがあります。


アソシエーションルールは、販売取引データの分析によく用いられ、小売業者が、人々がよく一緒に購入する商品間の関係を見つけるのに役立ちます。例えば、IF {bread, butter} THEN {cheese}というルールは、食料品店の取引データに含まれており、買い物客が同じ買い物でパンとバターを買ったときに、チーズも買う可能性があるかどうかを示しています。このような知識は、クーポンや特別価格の設定、商品の配置、在庫管理などに活かされます。直感的にわからないことでも、収益を上げる方法だけでなく、競争上の優位性を示すことができるかもしれません。


ルールの遵守状況を評価するためのメトリクスはいくつかあります。最も一般的な関連メトリクスは以下の通りです。


  •     サポート:トランザクションの総数に対する、あるアイテム(またはアイテムセット)を含むトランザクションの比率
  •     信頼度(Confidence): 先行詞と結果詞が一緒に発生するトランザクションの比率と先行詞が発生するトランザクションの数
  •     リフト:先行要素と結果要素の共同発生の、先行要素と結果要素が独立している場合の発生確率の積に対する比率


そもそも、サポート・メトリックを使用して、トランザクション・セット内の頻出アイテムセットを決定することができます(多くのトランザクションで発生するアイテムのセットは、頻出とみなされます)。そして、他のメトリックは、頻出アイテムセットの関連ルールを評価することができます。1990年代にRakesh AgrawalとRamakrishnan Srikantによって開発されたAprioriアルゴリズムは、まさにそのために設計されたもので、頻出アイテムセットを決定し、それに対する関連ルールを評価します。



Aprioriアルゴリズムによる連想パターンの解明


Aprioriアルゴリズムを使うには、以下の2つのステップを実行します。


  •     トランザクションデータセット内の頻出アイテムセットを決定
  •     それらの頻出アイテムセットに対する関連ルールを生成


    以下に、このアルゴリズムが実際にどのように適用されるかを示す簡単な例を示します。この例では、サンプルのトランザクションデータセットをPythonのリストのリストとして実装しています。このリストは、入れ子になった各リストが1つのトランザクションで見つかった製品のセットを表します。

transactions = [
 ['cabbage', 'cucumber'], ['cabbage', 'eggplant', 'cucumber'], ['carrot', 'potato', 'pepper'],
 ['carrot', 'pepper'], ['carrot', 'tomato'], ['spinach', 'eggplant', 'pumpkin'], ['carrot', 'tomato', 'corn'],
 ['lettuce', 'leek'], ['cabbage', 'cucumber', 'spinach'], ['corn', 'broccoli', 'tomato'],
 ['radishes', 'potato'], ['carrot', 'potato'], ['radishes', 'beets', 'potato'], ['cabbage', 'beans'],
 ['carrot', 'potato', 'pepper'], ['carrot', 'cucumber', 'pepper'], ['artichoke', 'cucumber'],
 ['cabbage', 'cucumber'], ['carrot', 'beets'], ['onion', 'garlic']
]


このサンプルデータセットは、20のトランザクションから構成されており、それぞれのトランザクションには2~3の記事が含まれています。(実際の取引データセットでは、何百万もの取引があり、それはかなり複雑なものになる可能性があります(家族のための1週間の食料品の買い物をカバーする典型的な店のレシートを考えてみてください)。


トランザクションに目を通すと、いくつかの製品が他の製品よりも頻繁に登場したり、いくつかの製品が一緒に登場する傾向があることに気づくかもしれません。例えば、「キャベツ」を含む取引が5件、「キュウリ」を含む取引が6件あり、そのうち「キャベツ」と「キュウリ」の両方を含む取引が4件あります。ここで、キャベツ→キュウリの連想ルールの主なメトリクスの計算方法を見てみましょう。


前述の通り、あるアイテムの支持率は、そのアイテムを含むトランザクションの、トランザクション総数に対する比率です。ですから、今回取り上げている例でのキャベツのサポート率は、次のように計算できます。

support(cabbage) = cabbage/total -> 5/20 -> 0.25


アイテムセットの場合、サポートはトランザクションの総数に対するアイテムセットが発生したトランザクションの比率です。したがって、例題で定義した「キャベツとキュウリ」というアイテムセットのサポートを計算するには、次のような式を使用します。

support(cabbage -> cucumber) = (cabbage & cucumber)/total -> 4/20 -> 0.2


Aprioriアルゴリズムでは、ユーザーが指定したサポートしきい値を使用して、アイテムセットが頻出であるかどうかを判断します。例えば、サポートしきい値を0.1に設定した場合、全てのトランザクションの少なくとも10%に一緒に現れるアイテムセットは、頻出とみなされます。


頻出アイテムセットのセットが決定されると、それらに対する連想ルールを評価することができる。信頼度とリフトが主な評価指標となる。例に戻ると、信頼度は、キャベツをキュウリと一緒に購入する可能性と解釈できます。つまり、「キャベツ→キュウリ」の連想ルールの信頼度は以下のように計算できます。

confidence(cabbage -> cucumber) = (cabbage & cucumber)/cabbage -> 4/5 -> 0.8


信頼度は0~1の範囲で設定できます。この指標は対称的ではありません。例えば、この例では、キャベツ→キュウリの信頼度と、キュウリ→キャベツの信頼度は異なります。

confidence(cucumber -> cabbage) = (cabbage & cucumber)/cucumber -> 4/6 -> 0.66


信頼度はアソシエーションルールの性能を表す指標で、結果が先行詞に続く頻度を示します。


前述の通り、リフトはアソシエーションルールを評価するためのもう一つの重要な指標です。関連規則 cabbage -> cucumber のリフトは、 cabbage -> cucumber の観測されたサポート率と、 cabbage と cucumber が互いに独立している場合に期待されるサポート率との比です。これは次のように計算できます。

lift(cabbage -> cucumber) = support(cabbage & cucumber)/(support(cabbage)*support(cucumber)) -> 0.2/(0.25*0.3) -> 2.66


liftの値の範囲は[0,∞]である。リフト比が1より大きい場合は、ルールで参照される先行詞と後続詞の関係が、それらが独立している場合に予想されるよりも強いことを示す。



Aprioriによるトランザクションデータセットの処理


トランザクションデータに対してアソシエーションルールのセットを自動的に生成することができます。Pythonでは、Aprioriアルゴリズムの実装を提供するMlxtendのようなライブラリを使ってこれを行うことができます。Mlxtendは以下のようにpipでインストールできます。

pip install mlxtend


その後、先ほどPythonのリストのリストとして定義したトランザクションデータセットにAprioriアルゴリズムを適用します。最初のステップは、データセットを後続の処理で使用できる形式に変換することです。Mlxtendを使う場合は、データセットをトランザクションのワンショットエンコード配列に変換する必要があります。次のスニペットでは、それを行い、エンコードされたトランザクションの配列をpandas DataFrameに保存しています。

import pandas as pd
from mlxtend.preprocessing import TransactionEncoder
encoder = TransactionEncoder()
encoded_array = encoder.fit(transactions).transform(transactions)
df_itemsets = pd.DataFrame(encoded_array, columns=encoder.columns_)


次に、エンコードされた配列からfrequent itemsetを抽出することができます。これは、mlxtend.frequent_patternsパッケージのapriori()関数を使って、以下のように行うことができます。

from mlxtend.frequent_patterns import apriori
frequent_itemsets = apriori(df_itemsets, min_support=0.1, use_colnames=True)


この例では、min_supportパラメータを0.1に設定して、少なくとも10%のサポートを持つアイテムおよびアイテムセットを返します。その結果、frequent_itemsets DataFrameの内容は以下のようになります。

    support                  itemsets
0      0.10                   (beets)
1      0.25                 (cabbage)
2      0.40                  (carrot)
3      0.10                    (corn)
4      0.30                (cucumber)
5      0.10                (eggplant)
6      0.20                  (pepper)
7      0.25                  (potato)
8      0.10                (radishes)
9      0.10                 (spinach)
10     0.15                  (tomato)
11     0.20       (cucumber, cabbage)
12     0.20          (pepper, carrot)
13     0.15          (carrot, potato)
14     0.10          (carrot, tomato)
15     0.10            (corn, tomato)
16     0.10          (pepper, potato)
17     0.10        (potato, radishes)
18     0.10  (pepper, potato, carrot)


これで、指定されたしきい値サポートを満たすアイテムとアイテムセットが揃ったので、Aprioriアルゴリズムの次のステップに進み、アイテムセットのための連想ルールを生成することができます。Mlxtend ライブラリは、そのための association_rules() メソッドを提供しています。

from mlxtend.frequent_patterns import association_rules
rules = association_rules(frequent_itemsets, metric="confidence", min_threshold=0.5)


しかし、生成されたルールを見てみると、support、confidence、lift以外のメトリクスも含まれていることに気づくかもしれません。混乱を最小限に抑えるために、この3つだけを表示したい場合は、以下のように明示的に指定します。

print(rules[['antecedents', 'consequents', 'support', 'confidence', 'lift']])


上記のコマンドでは、次のようなルールセットが出力されます。

         antecedents       consequents  support  confidence      lift
0         (cucumber)         (cabbage)     0.20    0.666667  2.666667
1          (cabbage)        (cucumber)     0.20    0.800000  2.666667
2           (pepper)          (carrot)     0.20    1.000000  2.500000
3           (carrot)          (pepper)     0.20    0.500000  2.500000
4           (potato)          (carrot)     0.15    0.600000  1.500000
5           (tomato)          (carrot)     0.10    0.666667  1.666667
6             (corn)          (tomato)     0.10    1.000000  6.666667
7           (tomato)            (corn)     0.10    0.666667  6.666667
8           (pepper)          (potato)     0.10    0.500000  2.000000
9         (radishes)          (potato)     0.10    1.000000  4.000000
10  (pepper, potato)          (carrot)     0.10    1.000000  2.500000
11  (pepper, carrot)          (potato)     0.10    0.500000  2.000000
12  (carrot, potato)          (pepper)     0.10    0.666667  3.333333
13          (pepper)  (carrot, potato)     0.10    0.500000  3.333333


ご覧のように、キャベツとキュウリの組み合わせごとに、また他のいくつかのアイテムの組み合わせごとに、個別のルールが生成されます。アイテムセットに対して生成されるメトリクスは、アイテムセット内のアイテムの順序に依存します。アイテムセットの前置詞と後置詞を入れ替えると、メトリックの信頼度も変わる可能性があります。


トランザクションデータに対する一連のアソシエーションルールを作成した後、それを活用して実用的なインサイトに変えるにはどうすればよいでしょうか。次のセクションでは、アソシエーションルールを構成するメトリクスにまとめられた購入履歴に基づいて、どのように顧客に推奨を行うことができるかについて説明します。



データを活用したレコメンデーション


お客様が既にバスケットに追加したアイテムに基づいてレコメンデーションを行うことは、お客様が購入したいと思うようなクロスセルアイテムを表示するために小売業者が使用する一般的なテクニックです。このようなレコメンデーションを行うには、お客様がよく一緒に購入するアイテムを特定する必要があります。ここで役に立つのがアソシエーションルールで、よく一緒に買われるアイテムを特定するための指標を提供します。


まず最初に、特定の基準でルールをフィルタリングすることができます。例えば、リフトメトリクスに設定されたしきい値を使用して、ルールのコレクションをフィルタリングすることができます。次のコードスニペットでは、リフトのしきい値は2.5に設定されています。また、先行詞と結果詞の列の名前を変更して、先行詞の推奨リストが最も一般的な結果詞で構成されていることを明確にすることをお勧めします。

recommendations = rules[rules['lift'] >= 2.5] [['antecedents','consequents']].rename(columns={'antecedents':'items', 'consequents':'recommendation'}).reset_index(drop=True)


そのため、推奨データフレームの内容は以下のようになります。

              items    recommendation
0        (cucumber)         (cabbage)
1         (cabbage)        (cucumber)
2          (pepper)          (carrot)
3          (carrot)          (pepper)
4            (corn)          (tomato)
5          (tomato)            (corn)
6        (radishes)          (potato)
7  (potato, pepper)          (carrot)
8  (potato, carrot)          (pepper)
9          (pepper)  (potato, carrot)


上の行を見てみると、items列に重複した値がある行があることに気づくかもしれません。例えば、pepperの行が2つありますが、これは推薦システムとしては適切ではありません。このような重複した値を1つの行にまとめる方法を以下に示します。

recommendations['recommendation'] = recommendations['recommendation'].apply(lambda x: list(x))
recommendations['recommendation'] = recommendations.groupby(recommendations['items'])['recommendation'].agg(sum).reset_index(drop=True)
recommendations = recommendations.drop_duplicates(subset=['items'])
recommendations['recommendation'] = recommendations['recommendation'].apply(lambda x: list(set(x)))


この後、推奨データフレームの行は以下のようになります。

              items    recommendation
0        (cucumber)         [cabbage]
1         (cabbage)        [cucumber]
2          (carrot)          [pepper]
3          (pepper)  [carrot, potato]
4          (tomato)            [corn]
5            (corn)          [tomato]
6        (radishes)          [potato]
7  (carrot, potato)          [pepper]
8  (potato, pepper)          [carrot]


Oracle Databaseで類似分析を行う


Oracle Databaseでは、Aprioriアルゴリズムによる連想分析を行うことができます。Oracle Database のDBMS_DATA_MININGパッケージを使用します。(Oracle Database 21cでは、Oracle Data MiningはOracle Machine Learning for SQLにブランド変更されました。しかし、PL/SQLパッケージ名は変更されておらず、DBMS_DATA_MININGのままです)。


ここでは、DBMS_DATA_MININGを使用して、一連のトランザクション・データに対する連想ルールを生成する簡単な例を示します。まず始めに、トランザクションデータを持つテーブルまたはビューが必要です。最も単純な形では、以下のようなテーブルが作成されます。

CREATE TABLE transactions (
  trans_id NUMBER(10),
  prod_name VARCHAR2(20)
);


trans_id列は、テーブル内のケース識別子列です。ここでいうケースとは、1つのトランザクションにおけるアイテムの集合体を想定しています。


トランザクションテーブルを作成したら、そこにデータを入力する必要があります。そのためには、この記事に添付されているtransactions.sqlファイルにある挿入ステートメントを実行します。また、次に作成するアソシエーションモデルのデフォルト設定をいくつか上書きするために、market_settingsテーブルを準備するとよいでしょう。

CREATE TABLE market_settings AS SELECT * FROM TABLE(DBMS_DATA_MINING.GET_DEFAULT_SETTINGS) WHERE setting_name LIKE 'ASSO_%';


その後、market_settingsテーブルにある設定のデフォルト値を変更し、アソシエーションモデルを構築しますが、これらはすべて1つのPL/SQLブロックで行うことができます。

BEGIN
 UPDATE market_settings
   SET setting_value = TO_CHAR(0.1)
 WHERE setting_name = DBMS_DATA_MINING.asso_min_support;
 DBMS_DATA_MINING.CREATE_MODEL(
  model_name           => 'market_model',
  mining_function      => DBMS_DATA_MINING.ASSOCIATION,
  data_table_name      => 'transactions',
  case_id_column_name  => 'trans_id',
  target_column_name   => NULL,
  settings_table_name  => 'market_settings');
END;
/


次の例のように、DBMS_DATA_MINING.GET_ASSOCIATION_RULESテーブル関数を使用して、トランザクション・テーブルにあるトランザクション・データに対して生成された関連規則を表示します。

SELECT A.attribute_str_value antecedent, C.ATTRIBUTE_STR_VALUE consequent, rule_support support, rule_confidence confidence, rule_lift lift
FROM TABLE(DBMS_DATA_MINING.GET_ASSOCIATION_RULES('market_model')) R,
     TABLE (R.antecedent) A,
     TABLE (R.consequent) C
WHERE rule_lift >=2.5 AND rule_confidence >=0.5;


上記のクエリでは、以下のような出力が得られるはずです。

ANTECEDENT CONSEQUENT SUPPORT CONFIDENCE     LIFT
---------- ---------- ------- -------------- --------------
pepper     carrot     .2      1              2.5
radishes   potato     .1      1              4
corn       tomato     .1      1              6.66666667
potato     carrot     .1      1              2.5
pepper     carrot     .1      1              2.5
cabbage    cucumber   .2     .8              2.66666667
cucumber   cabbage    .2     .666666667      2.66666667
potato     pepper     .1     .666666667      3.33333333
carrot     pepper     .1     .666666667      3.33333333
tomato     corn       .1     .666666667      6.66666667
carrot     pepper     .2     .5              2.5



まとめ


ある商品がお客様のバスケットに入った後、次に入るのはどの商品だろう?もちろん、確実なことは言えませんが、アソシエーション分析を使って、顧客の購入履歴に基づいて予測することができます。この記事では、PythonとOracle Databaseの両方を使用して、このタイプの分析がトランザクションのサンプルセットに対してどのように実行されるかを見ました。


イラスト Wes Rowell


コメント

このブログの人気の投稿

Oracle Database 19cサポート・タイムラインの重要な更新 (2024/11/20)

Oracle APEXのInteractive Gridで、Oracle Formsと比較して、重複行の検証を制御/通過させる方法 (2022/07/21)

Oracle APEX 24.1の一般提供の発表 (2024/06/17)