购物篮分析算法与实践

1. 购物篮分析

购物篮分析(Market Basket Analysis)是数据挖掘十大经典算法之一关联规则挖掘的应用场景,目的是从大规模订单数据集中寻找商品之间的关联, 线下零售商可藉由此分析改变货架上的商品排列或是设计吸引客户的组合促销套餐等,线上电商则当然就是做商品推荐啦, 最著名的案例是沃尔玛那个啤酒和尿片的传说,虽然我极度怀疑其真实性。

image.png

要从订单中找到啤酒和尿片这样强相关的商品似乎超级简单,不就是一个哈希表吗,key是商品集,value是同时出现的次数, 对交易订单逐行遍历更新这个哈希表就是了,但这样会有两个问题:

  1. 订单中商品可能会很多,订单的条数也可能几百万,按结对组合来统计的话计算量有点大吧? 以几何级数递增的计算量很可能会是一个组合爆炸的搜索空间。
  2. 如果A商品和B商品在10000个订单中同时出现了2000次,而C商品和D商品在订单中同时出现了1000次,到底两个商品关联性更强呢? 如果A商品在订单中出现了8000次同时B商品出现了3000次才产生了2000次的交集,而C商品和在订单中出现了1500次同时D商品出现了1200次就产生了1000次的交集呢?

所以还是要先系统化的复习一下统计学的几个概念,然后再了解相关算法,在此之前我先准备了一份迷你的mock data, 一则说明起来更直观,更重要的是可以节省大量的代码调试与结果验证时间,等算法跑通了再无缝切换到真实数据集上。

2. 迷你数据集

模拟十条订单数据,每个订单中的商品从1个到4个不等。


模拟订单

从模拟数据可以生成直观的关联矩阵,颜色越深则出现频率越高


关联矩阵

3. 统计学概念

Support(支持度) - 某商品(或组合)在所有订单中出现的概率
Support(A) = (Transactions containing (A))/(Total Transactions)
Support(卫浴)=P(卫浴)=4/10=0.4
Support(卫浴->地毯)=P(卫浴∩地毯) =2/10=0.2

Confidence(置信度) - 在所有包含A的订单中出现B商品的概率
Confidence(A->B) = (Transactions containing both (A and B))/(Transactions containing A) = Support(A∩B)/Suport(A)
Confidence(卫浴->地毯)=Support(卫浴->地毯)/Support(卫浴)=P(地毯|卫浴)=0.5

Lift(提升度) - 销售A商品对B商品带来的提升率
Lift(A->B) = Confidence(A->B)/Support (B)=P(B|A)/P(B)
Lift(卫浴->地毯)=0.5/0.4=1.25

我自己感觉支持度大于0.05, 置信度大于0.25的商品关联算是比较有价值的。

4. 挖掘算法

4.1 Apriori

Apriori是先验算法,假设子集S出现了k次,那么任何包含S的其它子集只会出现小于或等于k次. 反之如果S不满足最小的支持度阈值,则任何包含S的子集也不会满足,因此包含S的子集就可以忽略计算了。这样可以避免子集数目的指数增长,从而在合理时间内完成计算。所以这个算法会先生成一元子集(只有一个商品的候选集)的列表,把不满足支持度阈值的记录排除,然后用剩下的一元子集组合成二元子集,继续用支持度阈值卡一道,接下来组合成三元子集,and so on. 这就是个剪枝算法,例如下面的图例中如果发现子集[AB]不满足最小支持度阈值就可以一刀把所有包含[AB]的子集全部干掉。


image.png

代码解读:
加载数据后从dataframe转化成list
循环处理去除所有的nan(因为pandas将excel表格中为空的cell记录成nan了)
调用apriori函数设置四个最小阈值得到一串rule
为了看得清楚一些最后再写一段代码将rule遍历一次以更好的可读形式打印出来


source code

当最小support设为0.3的时候得到两个组合 (餐厨->卫浴)和(地毯->香薰)
console

Apriori的瓶颈是对数据集扫描过多,从一元子集到多元子集生成每一层候选集都要扫描一次,如果支持度阈值不够高则每一层的递进都可能是指数增长,如果订单中商品比较多还会生成庞大的数据集,所以接下来再看看2000年提出的一个改进算法FP-Growth, 多数情况下性能比Apriori高上一两个数量级。

4.2 FP-Growth

FP-Growth是深度优先算法,只需要遍历数据集两次,时间复杂度大大降低。

算法分为两个步骤: 种树和挖树

种树

第一次扫描首先统计单个元素的出现频次做降序排列并抛弃不达支持度门槛的元素(假设support threshold=2则f被干掉),然后按照频次高低对原有数据表中的每一个子集进行排序,最后开始构建FP Tree。构建树的时候逐行读取每一个子集,检查子集中的路径前缀是否在树中存在,是则将前缀节点的计数加1并挂靠在现有路径上进行延展(TID=3),否则创建一个全新的分支(TID=2)。相同元素的节点之间用虚线相连。

image.png

挖树

挖树的时候是从下往上(bottom-up), 从叶子节点往根部开始挖,因为每个订单子集都能在FP-Tree找到映射的路径,所以这是一种divide and conquer的策略,将问题分解成多个小的子集最终再把结果合并起来,算法可以分布式平行处理。

挖树分为两个子过程
a. 根据订单子集表将FP-Tree拆解成多颗小树苗
b. 从下到上递归遍历每一颗小树苗

例如我们要找到以e结尾的频繁子集,首先拆解出下图左上角那个小树苗,在这个小树苗里e对应的三个前缀路径为{(a,c,d), (a,d), (b,c)},这个大的任务可以拆解成三个小任务:
找到ae结尾的频繁子集
找到ce结尾的频繁子集
找到de结尾的频繁子集
be结尾的不用管,因为它被支持度阈值过滤了。

image.png

下面再次跑下迷你数据集,要求频繁子集至少出现3次且置信度至少为0.7, 同样抓出来了卫浴->餐厨与地毯->香薰
source code
console

5. 实战数据

现在可以切换真实数据源了,直接连接数据库读取百万级别订单数据。因为数据量大处理时间稍长,如果要改变算法的条件门槛多次尝试的话最好把处理好的列表数据用pickle dump出来,多次执行只要反序列化加载即可。订单数据中零食出现频次过高,和很多品类都有连带,所以我把订单中的零食也直接过滤了。当设置出现频次高于300且置信度不小于0.2的时候得到以下结果:

实战数据

如果有人有兴趣挑战百万级别订单数据挖掘的话可以去看看Kaggle两年前的一个购物篮分析挑战竞赛, 从这个链接可以下载到三百万订单的真实数据。
Kaggle Competition

如果要把分析做的更精细应该还可以考虑结合门店聚类,通过门店各品类销售占比做一个聚类分析就能看出三个特别比较明显的分类
一类门店的客群应该是顾家型已婚妇女
第二类喜欢买服装,但是是低单价的比较单薄的服装为主
第三类也喜欢买服装,且在大衣/羽绒/外套上的贡献突出

针对店群来关联订单数据,然后再做购物篮分析,应该还可以发现更多有趣的规则吧。
品类占比门店聚类

References:
Association Rule Mining via Apriori Algorithm in Python
Apriori vs FP-Growth for frequent item set mining
Frequent Itemset Generation Using FP-Growth
Frequent Pattern FP-Growth Algorithm
关联规则挖掘基础

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345