Python技术迷

mining,一个超 nice 的 Python 库!

不是所有库都值得单独写一篇。

有些库你装完,跑了两个 demo,热闹一下就过去了。mining 这类库不太一样,我第一次拿它干活,不是为了“学习数据挖掘”,是想把一堆订单明细里那些总一起出现的商品组合先扒出来,别老靠 SQL group by 硬顶。那种写法,能查出结果,但很快就写成一坨,后面想调支持度、置信度,基本就开始烦了。

我这里说的,实际上更接近 pymining 这个方向的小库:纯 Python、上手直接、适合做频繁项集和关联规则这类事情。它在 PyPI 上就是“用 Python 实现的一组数据挖掘算法”,主打轻量,不靠 C 扩展,拿来处理中小规模分析任务很顺手。 先看一个很像现场会碰到的数据。比如电商订单表里,你已经把每笔订单聚成了一个商品列表:

orders = [
    ["可乐", "薯片", "炸鸡"],
    ["可乐", "薯片"],
    ["咖啡", "三明治"],
    ["可乐", "炸鸡"],
    ["薯片", "炸鸡"],
    ["可乐", "薯片", "炸鸡", "纸巾"],
]

这种数据,最笨的办法就是两层三层循环自己数。真不是不能写,是写完 usually 不太想看第二遍。尤其你后面还要继续问:

  • 哪些组合出现得最多?
  • 买了 A 的人,有多大概率也买 B?
  • 阈值改一下,结果怎么变?

这时候 mining 这种库的价值就出来了,不在“高深”,在于省掉那堆重复脏活。

安装很直接:

pip install pymining

然后先把频繁项集跑出来:

from pymining import itemmining

relim_input = itemmining.get_relim_input(orders)
itemsets = itemmining.relim(relim_input, min_support=2)

for items, support in sorted(itemsets.items(), key=lambda x: (-x[1], len(x[0]))):
    print(items, support)

这段代码干的事很实在:把出现次数大于等于 2 的组合全捞出来。比如你很可能会看到这种结果:

('可乐',) 4
('薯片',) 4
('炸鸡',) 4
('可乐', '薯片') 3
('可乐', '炸鸡') 3
('薯片', '炸鸡') 3
('可乐', '薯片', '炸鸡') 2

这就比你直接看原始订单清楚多了。哪些是单品热,哪些是真组合,一眼就分开了。

但只到这里还不够。频繁项集只能告诉你“经常一起出现”,它不告诉你“谁带谁”。真正业务里更常问的是:用户买了可乐,顺手买薯片的概率高不高?适不适合做凑单推荐?这时就该继续往关联规则走。

我一般会自己补一层规则计算,不完全依赖库把最后一步全包掉。原因很简单:线上分析时,你迟早要加自己的过滤条件,比如屏蔽低利润商品、过滤活动赠品、排除组合装。这些东西,自己接一层代码更稳。

from itertools import combinations

defgen_rules(itemsets, min_confidence=0.6):
    rules = []
    support_map = {frozenset(k): v for k, v in itemsets.items()}

for itemset, support in support_map.items():
if len(itemset) < 2:
continue

for i in range(1, len(itemset)):
for left in combinations(itemset, i):
                left = frozenset(left)
                right = itemset - left
                left_support = support_map.get(left)
ifnot left_support:
continue

                confidence = support / left_support
if confidence >= min_confidence:
                    rules.append({
"left": tuple(sorted(left)),
"right": tuple(sorted(right)),
"support": support,
"confidence": round(confidence, 3)
                    })
return rules

rules = gen_rules(itemsets, min_confidence=0.7)
for rule in sorted(rules, key=lambda x: -x["confidence"]):
    print(rule)

跑出来你会得到类似这样的东西:

{'left': ('可乐',), 'right': ('薯片',), 'support': 3, 'confidence': 0.75}
{'left': ('薯片',), 'right': ('可乐',), 'support': 3, 'confidence': 0.75}
{'left': ('可乐',), 'right': ('炸鸡',), 'support': 3, 'confidence': 0.75}

这就开始有业务味了。你已经不是在“学算法”,你是在给推荐位、活动搭配、库存联动找依据。

我自己比较喜欢这个库的一点,是它不跟你讲太多排场,输入就是事务数据,输出就是结果。没有那种先搭一套训练框架、配半天参数、最后还得猜是不是自己喂错格式的烦躁感。它适合的就是这种场景:数据不算海量,但你想很快验证一个想法。PyPI 和项目说明里也明确写了,这类库本身就是围绕数据挖掘算法的轻量实现,不是大而全平台。([GitHub][1])

当然,这库也不是没边界。

第一,它更适合离线分析,不适合你拿去做实时高并发推荐。真到线上实时链路,还是要把结果提前算好,落库、落缓存,接口只负责查。

第二,原始数据得先洗干净。这个事很多人容易偷懒。订单里如果混着空值、测试商品、赠品编码、大小写不统一,最后跑出来的规则会很脏,脏到你怀疑算法,其实是数据先烂了。

我平时会先来一段清洗,不复杂,但很有必要:

defclean_orders(raw_orders):
    cleaned = []
for row in raw_orders:
        items = []
for item in row:
ifnot item:
continue
            item = item.strip().lower()
if item in {"测试商品", "赠品", "unknown"}:
continue
            items.append(item)

        items = sorted(set(items))
if len(items) >= 2:
            cleaned.append(items)
return cleaned

你看,这才像实际用法。不是摆个玩具例子说“库很好”。真正麻烦的,从来都不是 import,而是你导进来的那坨数据到底能不能看。

所以我对 mining 这类 Python 库的评价一直挺直接:不花哨,但很顶用。你手里正好有交易记录、行为序列、标签共现数据,想先把模式挖出来,它比你手撸统计算法省事太多;等你验证完方向,再决定要不要上更重的方案,也不迟。

有些库适合收藏。这个库更适合真拿来干活。