買い物かごの中の組み合わせ
頻出パターンとは、買い物かごの中によく一緒に入っている品物の組のことです。これが見つかると、棚の並べ方やセット割引を、記録から決められます。
データマイニングとは、大量の記録から役に立つ決まりを探す作業です。このレッスンでは、数えることだけで頻出パターンを見つけます。
このレッスンのゴール
メモ
買い物かごの記録から、よく一緒に買われる品物の組を見つけられる。
キーワード
| ことば | いみ | れい |
|---|---|---|
| バスケット | 1回の買い物で買った品物のまとまり | |
| アイテム集合 | 品物の組 | おにぎりとお茶 |
| 支持度 | その組が入っているバスケットの割合 | 5 ÷ 10 = 0.5 |
| 最小支持度 | 頻出とみなす、支持度の下限 | |
| 頻出アイテム集合 | 支持度が最小支持度以上の組 |
学生が入力するセルは、このプレビューでは空白です。
支持度は、入っているかごの割合
バスケットの記録では、1回の買い物が1行です。ある品物が何行に入っているかを数えます。それを全部の行数で割った値が支持度です。
10行のうち6行におにぎりが入っていれば、支持度は 0.6 です。品物が2つなら、2つとも入っている行だけを数えます。
例: 10回の買い物
| バスケット | 入っていた品物 |
|---|---|
| 1 | おにぎり、お茶 |
| 2 | おにぎり、お茶、たまご |
| 3 | パン、牛乳 |
| 4 | おにぎり、お茶、パン |
| 5 | パン、牛乳、たまご |
| 6 | おにぎり、お茶 |
| 7 | パン、牛乳 |
| 8 | おにぎり、たまご |
| 9 | パン、たまご |
| 10 | おにぎり、お茶 |
学生が入力するセルは、このプレビューでは空白です。
ターミナルでは品物を1文字にする
次のコマンドは、この10回の買い物から、おにぎりとお茶が両方入ったバスケットを数えます。ターミナルでは日本語の入力が崩れることがあるので、品物を1文字にしました。
r はおにぎり、t はお茶、b はパン、m は牛乳、e はたまごです。答えは 5 です。
2つが入ったかごを数える
docker exec jupyter python3 -c 'B=["rt","rte","bm","rtb","bme","rt","bm","re","be","rt"]; print(sum(["r" in x and "t" in x for x in B]))'ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。
最小支持度より多い組だけを残す
品物の組は、数えきれないほどあります。そこで最小支持度を決め、それ以上の組だけを残します。ここでは 0.3、つまり3かご以上とします。
品物1つずつの数と、品物2つの組の数を、下の表にまとめました。
例: 数えた結果
| 品物の組 | 入っているかご | 支持度 | 残るか |
|---|---|---|---|
| おにぎり | 6 | 0.6 | 残る |
| お茶 | 5 | 0.5 | 残る |
| パン | 5 | 0.5 | 残る |
| 牛乳 | 3 | 0.3 | 残る |
| たまご | 4 | 0.4 | 残る |
| おにぎりとお茶 | 5 | 0.5 | 残る |
| パンと牛乳 | 3 | 0.3 | 残る |
| おにぎりとたまご | 2 | 0.2 | 残らない |
| パンとたまご | 2 | 0.2 | 残らない |
| ほかの組すべて | 1か0 | 0.1以下 | 残らない |
学生が入力するセルは、このプレビューでは空白です。
ある組が頻出なら、中の品物も頻出
ある組が頻出なら、その中の品物1つずつも必ず頻出です。頻出でない品物が1つでも入った組は、数えなくてよいことになります。
この考え方を使うのが、アプリオリという方法です。まず品物1つずつを数え、残ったものだけで組を作ります。
かごの組を数える
# 10回の買い物から、品物2つの組の数を数えます。
baskets = [
["おにぎり", "お茶"], ["おにぎり", "お茶", "たまご"], ["パン", "牛乳"],
["おにぎり", "お茶", "パン"], ["パン", "牛乳", "たまご"], ["おにぎり", "お茶"],
["パン", "牛乳"], ["おにぎり", "たまご"], ["パン", "たまご"], ["おにぎり", "お茶"],
]
min_count = 3
counts = {}
for basket in baskets:
for i in range(len(basket)):
for j in range(i + 1, len(basket)):
pair = basket[i] + " と " + basket[j]
if pair in counts:
counts[pair] = counts[pair] + 1
else:
counts[pair] = 1
for pair in counts:
if counts[pair] >= min_count:
print(pair, counts[pair])
# min_count を 2 に変えて、もう一度実行してください。
# 残る組はいくつ増えますか。
よくある間違い
注意
よく一緒に買われる組は、品物どうしに関係があると考えがちです。実際は、人気の品物どうしは、関係がなくても一緒に入りやすいのです。支持度は数えた結果にすぎません。
ノートブックに入力: 日をかごにする
import csv
days = []
for row in csv.DictReader(open("hires.csv")):
items = []
if row["weekday"] in ["Sat", "Sun"]:
items.append("weekend")
if row["weather"] == "rainy":
items.append("rainy")
if float(row["temp_c"]) >= 12:
items.append("warm")
if int(row["hires"]) >= 300:
items.append("busy")
days.append(items)
first = "weekend"
second = "busy"
both = 0
for items in days:
if first in items and second in items:
both = both + 1
print("両方ある日:", both)
print("支持度:", round(both / len(days), 3))
# first と second を、rainy や warm に変えてみましょう。