Pythonでアプリオリ・アルゴリズムを実装してPyPI登録

アソシエーション分析(バスケット分析)

Pythonでアプリオリ・アルゴリズムを実装したライブラリはいくつかありますが、リフト(Lift)値を考慮に入れたものは、Orangeしか見当たりませんでした。

しかし、Orangeはpip installできないので不便だと思い、自前で実装してPyPIにパッケージ登録しました。

https://github.com/aknd/akapriori

使用方法

$ pip install akapriori

インストールしておき、

from akapriori import apriori

transactions = [
    ("apricot", "apple", "cherry", "plum", "banana"),
    ("strawberry", "plum", "cherry"),
    ("persimmon", "peach", "banana", "apple"),
    ("kiwi fruit", "apple", "pear"),
    ("cherry", "pear", "banana"),
    ("watermelon", "apple"),
    ("plum", "banana"),
    ("pear", "peach", "cherry", "banana", "apricot"),
    ("pineapple", "apple", "plum"),
    ("banana", "plum", "peach"),
    ("grape", "cherry"),
    ("mandarin", "plum"),
    ("melon", "apple", "persimmon", "plum"),
    ("peach", "cherry", "apple"),
    ("apple", "mandarin", "plum", "persimmon"),
]

“support >= 0.05 and confidence >= 0.3 and lift > 2"を満たすルールを抽出したいなら、以下のように実装します。

rules = apriori(transactions, support=0.05, confidence=0.3, lift=2)
rules_sorted = sorted(rules, key=lambda x: (x[4], x[3], x[2]), reverse=True) # ORDER BY lift DESC, confidence DESC, support DESC

for r in rules_sorted:
    print(r)

出力結果

(frozenset(['kiwi fruit']), frozenset(['pear']), 0.06666666666666667, 1.0, 5.0)
(frozenset(['melon']), frozenset(['persimmon']), 0.06666666666666667, 1.0, 5.0)
(frozenset(['pear']), frozenset(['kiwi fruit']), 0.06666666666666667, 0.3333333333333333, 5.0)
(frozenset(['persimmon']), frozenset(['melon']), 0.06666666666666667, 0.3333333333333333, 5.0)
(frozenset(['apricot']), frozenset(['banana']), 0.13333333333333333, 1.0, 2.5)
(frozenset(['apricot']), frozenset(['cherry']), 0.13333333333333333, 1.0, 2.5)
(frozenset(['grape']), frozenset(['cherry']), 0.06666666666666667, 1.0, 2.5)
(frozenset(['strawberry']), frozenset(['cherry']), 0.06666666666666667, 1.0, 2.5)
(frozenset(['apricot']), frozenset(['pear']), 0.06666666666666667, 0.5, 2.5)
(frozenset(['mandarin']), frozenset(['persimmon']), 0.06666666666666667, 0.5, 2.5)
(frozenset(['banana']), frozenset(['apricot']), 0.13333333333333333, 0.3333333333333333, 2.5)
(frozenset(['cherry']), frozenset(['apricot']), 0.13333333333333333, 0.3333333333333333, 2.5)
(frozenset(['pear']), frozenset(['apricot']), 0.06666666666666667, 0.3333333333333333, 2.5)
(frozenset(['persimmon']), frozenset(['mandarin']), 0.06666666666666667, 0.3333333333333333, 2.5)

基本的な定義

トランザクション: 個々の客の1回の買い物(バスケット)

Ω: 全トランザクション

A: 商品Aの購入を含むトランザクション

n(Ω): 全トランザクション数(全バスケット数)

n(A): 商品Aの購入を含むトランザクションの総数(商品Aを含むバスケット数)

n(A ∩ B): 商品Aと商品Bの両方の購入を含むトランザクションの総数(商品Aと商品Bの両方を含むバスケット数)

P(A): 商品Aが購入される確率

P(A ∩ B): 商品Aと商品Bが同時購入される確率

P(B | A): 商品Aを購入しているという条件での、商品Bを購入している条件付き確率

A => B: 「商品Aを購入していると商品Bも購入している」というルール(左側を条件部、右側を結論部と呼ぶ)

Support

Supp(A): 商品AのSupport(支持度)

Supp(A) := n(A) / n(Ω) = P(A)

Supp(A => B): ルール A => B のSupport(支持度)

Supp(A => B) := n(A ∩ B) / n(Ω) = P(A ∩ B) = P(B ∩ A) = n(B ∩ A) / n(Ω) =: Supp(B => A)

矢印が付いていますが、Supp(A => B)に方向性はないことに注意しましょう。

Supportが大きいルールを抽出することが必要な理由は、そもそもほとんど売れていな商品Aと商品Bがたまたま同時に買われた様な場合に、そのルールを重要視してしまうことを防ぐためです。

また、Supportが小さいものは、そもそもほとんど売れていないので、たとえルールとして意味があったとしても、それを発見したところでビジネスとしての旨味はないとも考えられます。

Confidence

Conf(A => B): ルール A => B のConfidence(確信度)

Conf(A => B) := Supp(A => B) / Supp(A) = P(A ∩ B) / P(A) = P(B | A)

Confidenceが大きいルールほど、併売の結びつきが強いルールと言えます。

Lift

Lift(A => B): ルール A => B のLift(リフト)

Lift(A => B) := Conf(A => B) / Supp(B) = P(B | A) / P(B)

単純に商品Bを購入する割合よりも商品Aを購入した中で商品Bも購入した割合の方が高いとき、リフトは1を超えます。

したがって、リフトが1を超えたルールが意味のあるルールです。

リフトが大きいルールを抽出することで、ルールに関係なく売れている商品を除外することができます。