资讯动态

Python关联规则挖掘:Apriori处方药材配伍实战

发布时间:2026/10/27 4:23:02 来源:尧图企业网站定制
1. 从一堆处方明细说起项目整体思路拆解手上拿到的是某连锁药房后台导出的处方明细表两列最关键order_id处方单号和herb_name药材名。一张处方少则八九味多则二十几味几万条记录堆在 Excel 里靠肉眼看是看不出规律的。业务方的原始诉求很朴素——哪些药材总是成对成组地出现、顾客拿了甲药是不是大概率还会拿乙药。这类问题在数据挖掘里的标准解法就是关联规则挖掘而 Python 生态里最经典、最容易上手落地的算法就是Apriori。它通过逐层搜索的方式找出数据集中满足最小支持度的频繁项集再从频繁项集里推导出形如甲出现则乙也出现的关联规则整个过程完全由支持度、置信度、提升度这几个指标量化不依赖任何先验的业务判断非常适合用来做第一轮探索。这篇内容我想完整走一遍从原始明细表怎么变成算法能吃的矩阵、阈值到底怎么定、代码怎么写、结果怎么读、跑不动了怎么优化以及那些只有真跑过一遍才会踩到的坑。适合两类人看——一类是手上正好有处方、订单、购物篮这类一单多品结构数据想快速出结论的另一类是想把关联规则这套方法真正用到业务里而不是停在调包跑个 demo 的。代码全部基于pandasmlxtend不涉及深度学习框架普通笔记本 16G 内存足够跑十万级记录。需要提前说清楚一个边界关联规则挖出来的是统计共现规律不是医学结论。某两味药经常出现在同一张处方里可能因为配伍习惯、可能因为某类证型的固定组合、也可能只是某位坐诊医师的个人风格甚至可能只是某段时间某味药缺货导致的替代。任何涉及用药的判断都必须交给有资质的中医师我们做的是把数据里的模式呈现在台面上仅此而已。这个定位想清楚了后面解读结果时才不会跑偏也不会拿着一条提升度 5 的规则就去下结论。1.1 为什么选 Apriori而不是聚类或协同过滤同样一批处方数据能用的方法不少把每张处方当成向量做 K-Means 聚类、用药材共现矩阵做谱聚类、或者直接上协同过滤做推荐。我最初也评估过这几条路最后还是落到 Apriori原因有三个。第一是可解释性。聚类出来的簇你得回头去看每个簇里都是什么药然后再自己总结一句这个簇大概是什么类型的组合中间隔了一层翻译。关联规则直接输出甘草 → 茯苓这种可读的形式配上支持度置信度业务方能自己看懂不需要我在旁边解释半天。第二是对稀疏数据的适应性。药材维度假设有八百味一张处方只用十几味这是一个极度稀疏的 0-1 矩阵。聚类方法在这种高维稀疏场景下距离度量很容易失效欧氏距离几乎全是 1效果往往不如预期。Apriori 是基于集合的频繁模式搜索天然适配一单多品这种结构。第三是门槛和工程成本。mlxtend一个库搞定没有模型训练、没有超参数调优、没有 GPU 需求跑完直接出表格。对于一个先看看有没有规律的探索性需求投入产出比明显更高。当然它也有明确的短板我在实际使用中体会很深一是项数一多组合爆炸如果放任算法去找 5 项以上的组合候选集数量是天文数字内存直接顶不住二是只关心是否出现不关心出现多少某味药用了 6 克和用了 30 克在 Apriori 眼里是一回事这个信息损失是必须接受的三是对高频万金油药材极度敏感像甘草、陈皮这类几乎出现在每张方子里的药会污染大量规则后面必须做专门处理。这三点在后面的章节里都会展开讲应对办法。1.2 整体链路与技术栈选型整条链路我拆成五步每一步都有明确的输入输出出错时容易定位环节输入输出关键工具数据读取与清洗Excel / CSV 明细干净的 (order_id, herb_name) 两列pandas别名归一原始药材名标准药材名自定义字典 replace事务化分组后的药材列表每单一个 listgroupby apply独热编码list 列表0/1 矩阵TransactionEncoder频繁项集与规则0/1 矩阵规则表mlxtend技术栈就是pandasmlxtendopenpyxl读 xlsxmatplotlib可选出图。mlxtend版本建议 0.22 以上因为 0.23 版本对association_rules的参数做了调整多了一个num_itemsets必填参数很多人照抄旧教程会直接报错这个坑后面单独说。我特意没有引入数据库因为多数人的原始数据就是 Excel。如果数据量到了百万级明细建议先在数据库里做一次GROUP_CONCAT把一单多行压成一单一行导出的数据体积能小一个数量级后续读入内存也轻松很多。这个小优化我在一个八万单的项目里做过Excel 从 400MB 降到 20MB读取时间从两分多钟降到几秒。2. 把三个指标翻译成人话支持度、置信度、提升度很多人卡在 Apriori 上不是代码不会写而是挖出一堆规则之后不知道怎么判断哪条有用。根子在于对这三个指标的理解停留在了公式层面。我用药房柜台的场景重新讲一遍应该会好懂很多。假设总共有8000 张处方。药材 A 出现在 800 张里药材 B 出现在 1000 张里A 和 B 同时出现在 400 张里。支持度Support回答的是这个组合有多常见。AB 同时出现的支持度 400 / 8000 5%。这个数字的意义是随便抽一张处方里面有 A 也有 B 的概率是 5%。它衡量的是普遍性支持度太低说明这个组合是偶发可能只是巧合样本量一小统计噪音就盖过信号了。置信度Confidence回答的是看到 A 之后B 出现的概率有多大。A → B 的置信度 400 / 800 50%。注意方向性B → A 的置信度 400 / 1000 40%两者不相等。置信度衡量的是可靠性但它是单向的这是初学者最容易忽略的一点。提升度Lift回答的是这个关联比随机情况强多少。B 的整体支持度是 1000 / 8000 12.5%如果 A 和 B 完全独立那么 A 出现时 B 出现的概率应该也是 12.5%。实际是 50%所以提升度 50% / 12.5% 4。含义是A 出现时 B 出现的可能性是随机情况的 4 倍。提升度衡量的是关联强度大于 1 是正相关等于 1 是独立小于 1 是负相关互斥。2.1 三个指标各自的陷阱单看任何一个指标都会得出错误结论我在实际项目里三个坑都踩过。只看支持度的坑支持度高只能说明常见不能说明有关联。甘草在几乎每张方子里都有支持度可能高达 60%但甘草 → 任何药的置信度都接近该药本身的支持度提升度接近 1等于废话。所以支持度必须和提升度一起看。只看置信度的坑置信度会被高频项绑架。如果 B 本身就是个万金油那 A → B 的置信度天然就高因为不管 A 出不出现B 都经常出现。这种情况必须用提升度来校正。我一般要求置信度和提升度双达标比如置信度 0.5 且提升度 1.2。只看提升度的坑提升度极高但支持度极低的规则多数是噪音。比如某两味冷门药材只在一张处方里同时出现过一次支持度 0.012%提升度可能算出来是几百这种规则毫无意义就是两个稀有项的偶然碰撞。所以支持度要设一个下限兜底。我的经验阈值组合是支持度下限看样本量置信度 0.4~0.6提升度 1.2同时加上前项和后项各自的支持度都不能是 Top 5 高频项这个业务过滤。最后这条是从业者才会想到的因为纯数学指标不会告诉你甘草太常见了含甘草的规则基本不用看。2.2 最小支持度到底该设多少这是所有参数里最需要算的一个不是拍脑袋定的。有个简单的换算最小支持度 × 处方总数 该组合至少要出现的次数。如果总共有 8000 张处方最小支持度设 0.001那么一个组合至少出现 8 次就能进入频繁项集。8 次在统计上太脆弱了任何一次数据录入错误都能改变结论。反过来设 0.05 意味着至少要 400 次共现那么三项、四项的组合几乎全部被过滤掉结果只剩下一堆两味药的常见搭配。我一般按下面的经验值起步然后根据结果数量做微调处方总量建议 min_support含义最少出现次数适合场景 10000.0550 次样本少只找最强的两味组合1000 ~ 50000.0220~100 次两味、三味组合都能出一些5000 ~ 500000.0150~500 次主力区间两到四项都有 500000.005 起250 次以上需要配合分层挖掘还有个更细的做法叫分层挖掘先用较高的支持度比如 0.02挖两项集把结果稳定下来再降到 0.008 挖三项及以上同时把max_len卡在 4。这样既能保证短组合的可靠性又能捞到一些长组合的线索。这个策略在我处理六万张处方的项目里用过比一次性设低支持度跑全量要快得多内存也省。注意支持度阈值不要跨数据集直接套用。两万张处方的最佳阈值放到八百张处方上会直接挖不出东西因为组合的出现次数不够。换数据集必须重新算。2.3 从频繁项集到规则的推导逻辑Apriori 的原理部分很多文章会画一堆集合图其实核心就一句话如果一个项集是频繁的那它的所有子集也一定是频繁的反之如果一个项集不频繁那它的所有超集都不频繁。这条向下封闭性质是整个算法能剪枝省时间的关键也是为什么它要一层一层往上搜先找 1 项集再 2 项集以此类推。从频繁项集到关联规则做法是枚举每个频繁项集的非空真子集。比如频繁项集 {A, B, C}可以生成 A→BC、B→AC、C→AB、AB→C、AC→B、BC→A 六条候选规则然后逐条算置信度低于阈值就丢掉。所以规则数量是项集数量的函数项集越多规则越多这也是为什么max_len要卡住——五项的频繁项集能生成 30 条候选规则六项是 62 条增长很快。mlxtend的association_rules已经把这层枚举做好了我们只管传参和筛选就行不需要手写。但知道它在内部做了什么后面遇到规则数量异常多或者内存爆了的时候才知道该从哪个方向去卡。3. 数据准备从处方明细到 0/1 矩阵这一步的工作量占了整个项目的七成但往往被写得最少。我说句实话Apriori 本身调包只要三行代码真正决定结果质量的是数据清洗做得够不够细。3.1 别名归一同一味药有五个名字这是最影响结果的一步也是不做就必然出错的环节。同一个药材在系统里可能有多个写法带炮制方式的炙甘草和生甘草、带产地的川贝母和浙贝母严格说是两味药但杭白芍和白芍很可能指的是一回事、带规格的、还有单纯的错别字和空格。如果炙甘草和生甘草这两味药不合并算法会把它们当成两种不同的药A 和 B 的共现次数被劈成两半支持度直接砍办很多本该出来的规则就沉下去了。这个坑我在第一次跑的时候完全没意识到结果出来一看甘草的排名特别靠后回头查原始数据才发现光甘草就有五种写法。我建了一个别名字典用字典做批量替换代码很简单但效果立竿见影import re import pandas as pd # 别名映射表建议单独维护一个 Excel 或 py 文件方便业务方补充 herb_alias { 炙甘草: 甘草, 生甘草: 甘草, 甘草片: 甘草, 杭白芍: 白芍, 炒白芍: 白芍, 川牛膝: 牛膝, 怀牛膝: 牛膝, 淮山药: 山药, 怀山药: 山药, 云苓: 茯苓, 白茯苓: 茯苓, 广陈皮: 陈皮, 新会陈皮: 陈皮, } df pd.read_excel(处方明细.xlsx, sheet_namedetail) df df[[order_id, herb_name]].dropna() # 基础清洗去空格、全角转半角、去掉括号里的炮制说明 def clean_name(s: str) - str: s str(s).strip() s s.replace( , ).replace( , ) s re.sub(r[(].*?[)], , s) # 去掉括号注释 return s df[herb_name] df[herb_name].map(clean_name) df[herb_name] df[herb_name].replace(herb_alias)括号那行要特别注意很多系统的药材名会写成当归(酒炒)、黄芪(炙)这种形式把括号内容去掉之后能合并掉一大批。但反过来也要小心如果括号里写的是产地或规格当归(甘肃)和当归(云南)被合并是对的万一括号里是不同药材的区分信息就有误合并的风险。我一般的处理是先把所有带括号的名字单独拉出来人工扫一遍高频的几十个确认没问题再批量处理。提示别名字典的维护一定要让业务方参与。我一开始按自己的常识写映射结果把两种确实不同的药材合并了被药房的老师傅指出来后面改成我出初稿业务方签字确认的流程才没再出错。3.2 从明细表到 One-Hot 矩阵清洗完之后要把一单多行的结构转成一单一列表再转成算法要的 0/1 矩阵。这三步的中间产物建议都存一份出问题了好回溯。# 第一步按单号聚合每单变成药材列表 transactions ( df.groupby(order_id)[herb_name] .apply(lambda x: sorted(set(x))) # set 去重防止同一味药重复录入 .tolist() ) print(处方总数:, len(transactions)) print(第一张处方:, transactions[0]) # 第二步转 0/1 矩阵 from mlxtend.preprocessing import TransactionEncoder te TransactionEncoder() te_array te.fit(transactions).transform(transactions) onehot pd.DataFrame(te_array, columnste.columns_) print(矩阵形状:, onehot.shape) # (处方数, 药材数)set(x)这个去重很重要。有些系统会把同一味药按不同剂量拆成两行或者同一张方子在数据库里有主药和辅药两条记录不去重的话这一单里甘草出现两次虽然对布尔矩阵没影响但会让药材出现频次统计失真后面定阈值时会误判。矩阵形状一般是几千行 × 几百列内存占用很小。如果药材维度超过两千TransactionEncoder生成的object类型矩阵会开始吃内存这时候要手动转成bool或int8onehot onehot.astype(bool) # 内存直接降到 1/4 甚至更低这一步虽然只有一行但在大项目里能把内存从 3G 压到 700M 左右属于必做优化后面性能那一节还会提到。3.3 脏数据与处理策略速查我整理了一份实际遇到的脏数据清单基本覆盖了药房系统导出的常见问题脏数据类型具体表现处理方式不处理的后果空格与全角甘 草、甘草 strip 全角转半角 正则去空白同一味药被拆成多列括号注释当归(酒炒)正则去掉括号内容同一味药多个变体炮制差异炙甘草/生甘草按业务确认后合并支持度被劈开单方处方只含 1~2 味药过滤掉如 len 3撑大分母压低所有支持度重复行同一单同一药出现两次set()去重频次统计失真空值 / 占位符-、无、NaNdropna 黑名单过滤出现无意义的药材单味超大处方一张单子 40 味视情况保留但要标记拉高整体共现基线最后一行要展开说一下。有些处方是膏方或者大复方动辄三四十味药这种单子在数据里会拉高整体的共现基线让原本正常的规则提升度显得没那么突出。我一般的做法不是删掉而是加一列herb_count标记出来分析时可以做分群对比——大复方和小方剂可能对应完全不同的配伍规律混在一起挖有时候会互相抵消。4. 完整代码实现从频繁项集到可用规则前面铺垫完这一段直接上能跑的代码每一步都说明在干什么。4.1 挖频繁项集mlxtend提供了两个实现apriori和fpgrowth。两者的输出格式完全一样区别在于算法策略——Apriori 是逐层生成候选集再验证FP-Growth 是先把数据集压缩成 FP 树再挖后者在数据量大、低频项多的情况下通常快一个数量级而且不需要反复扫描数据集。既然结果等价我现在的默认选择是fpgrowth只有教学演示才用apriori。from mlxtend.frequent_patterns import fpgrowth, apriori # 先做一次低频药材过滤把出现率低于 0.3% 的冷门项直接砍掉 min_item_support 0.003 item_rate onehot.mean(axis0) keep_cols item_rate[item_rate min_item_support].index onehot_filtered onehot[keep_cols] print(f过滤前 {onehot.shape[1]} 味过滤后 {onehot_filtered.shape[1]} 味) # 挖频繁项集 frequent_items fpgrowth( onehot_filtered, min_support0.01, # 最小支持度 use_colnamesTrue, # 输出用列名而不是列索引 max_len4, # 最多找 4 味药的组合防止爆炸 verbose0 ) frequent_items[length] frequent_items[itemsets].apply(len) frequent_items frequent_items.sort_values(support, ascendingFalse) frequent_items.to_csv(频繁项集.csv, indexFalse, encodingutf-8-sig)max_len这个参数强烈建议设不设的话算法有可能一直往上找组合数指数级增长。我见过有人在八百味药的数据集上不设max_len跑到 5 项集的时候内存直接打满。实际业务里超过四味药的组合已经很难解释也更难落地卡在 3 或 4 是合理的选择。use_colnamesTrue也别忘了不然输出的itemsets里是列索引数字你还得回头去查第 137 列对应哪味药麻烦且容易出错。4.2 生成并筛选关联规则这一步是重点参数设对了结果才有用。注意mlxtend0.23 版本之后association_rules多了一个num_itemsets参数不传会报警告甚至报错网上大量旧教程没提这一点。from mlxtend.frequent_patterns import association_rules rules association_rules( frequent_items, metricconfidence, min_threshold0.4, num_itemsetslen(frequent_items) # 0.23 版本需要 ) # 多重筛选置信度 提升度 支持度三重卡 top_items [甘草, 陈皮] # 业务确认的万金油含它们的规则单独看 def has_top_item(s): return bool(s set(top_items)) rules rules[ (rules[confidence] 0.4) (rules[lift] 1.2) (rules[support] 0.008) ] # 把 frozenset 转成可读字符串 def fmt(s): return .join(sorted(s)) rules[前项] rules[antecedents].apply(fmt) rules[后项] rules[consequents].apply(fmt) rules[前项长度] rules[antecedents].apply(len) # 标记是否含万金油项方便分开看 rules[含高频项] rules[antecedents].apply(has_top_item) | \ rules[consequents].apply(has_top_item) rules rules.sort_values([lift, support], ascendingFalse)frozenset这个类型要先处理掉因为 pandas 导出 CSV 时对它没法正常序列化直接to_csv会变成一串frozenset({甘草})的 Python 对象字符串后续没法用。先转成普通的连接的字符串导出之后 Excel 里能直接看、能筛选、能排序交给业务方的时候省很多沟通成本。筛选条件我一般会做两套输出一套是剔除万金油项的干净规则用来找真正有信息量的新增搭配另一套是包含万金油项的规则这类虽然提升度不高但支持度大对库存备货反而更有参考价值——甘草配什么都常见那备货就得按最保守的量来。同一个数据两种用途不要用一套筛选逻辑走到底。4.3 结果导出与基础可视化导出这块有个小细节中文 Excel 打开 CSV 乱码是因为编码问题用utf-8-sig就行了这个很多人都踩过。out_cols [前项, 后项, support, confidence, lift, 前项长度, 含高频项] rules[out_cols].to_csv(关联规则_全量.csv, indexFalse, encodingutf-8-sig) # 干净版不含万金油项按提升度排序取前 100 clean rules[~rules[含高频项]].head(100) clean[out_cols].to_csv(关联规则_重点.csv, indexFalse, encodingutf-8-sig) # 简单的提升度分布图一眼看出整体质量 import matplotlib.pyplot as plt plt.rcParams[font.sans-serif] [SimHei] plt.rcParams[axes.unicode_minus] False fig, ax plt.subplots(figsize(8, 5)) ax.hist(rules[lift], bins50, color#4C72B0, edgecolorwhite) ax.axvline(1.2, colorred, linestyle--, labellift1.2 参考线) ax.set_xlabel(提升度 lift) ax.set_ylabel(规则数量) ax.legend() plt.tight_layout() plt.savefig(lift_dist.png, dpi150)看这张直方图比看表格更快判断整体情况。如果大部分规则的提升度都集中在 1.0~1.2 这个窄区间说明数据里的共现模式很弱基本是随机组合不要指望能挖出什么惊艳结论这时候应该先怀疑数据质量或者支持度设得太低。如果长尾一直到 3 甚至 5那说明确实有强关联模式存在值得往下深挖。5. 结果解读哪些规则能信哪些是幻觉代码跑完表格导出来了真正的难点才开始。一张几千行的规则表扔给业务方没人看得完。我用下来比较有效的方法是三层过滤 人工复核。5.1 三类必须警惕的伪规则第一类高频项绑架型。前项或后项本身支持度就很高比如党参 → 茯苓两味药各自的支持度都是 20%那它们的共现概率天然就高置信度算出来可能 0.45看着不错但提升度只有 1.1基本等于独立。这类规则要一律压低优先级。第二类稀有项巧合型。两味冷门药材在数据里各出现十几次恰好有几次撞在一起支持度算出来 0.1%提升度飙到 8。这种规则看着诱人但样本量太小只要再增加一批数据就散了。我的做法是给每条规则加一个共现次数列support × 处方总数低于 20 次的一律不看。第三类方向错误型。置信度是有方向的A → B 和 B → A 差别可能极大。有个实际例子某两味药的 A → B 置信度 0.62看着很强但反过来 B → A 只有 0.18。原因很直白——B 是个大品种出现场景很泛而 A 只在一类特定方子里出现一旦 A 出现基本必然带 B。如果只看单向很容易得出B 带来 A的错误结论去指导陈列或者推荐方向搞反了效果就完全相反。筛选时我习惯把两个方向都列出来对照着看。5.2 规则怎么真正落到业务上同一批规则在不同岗位手里能发挥完全不同的作用这是我在项目里体会比较深的一点。配方与组方参考三项以上的高提升度规则可以整理成常用组合参考清单。这里必须强调这份清单的作用是提供线索让专业人员复核不是自动生成处方。有些组合在数据里高频可能是因为某段时期的特定证型集中或者某位医师的固定用法离开那个语境就不成立了。库存与备货这个用途反而被低估了。支持度高、提升度一般的两味组合对备货最有价值——因为它们经常一起出现那就可以考虑同批次采购、同区域摆放降低缺货率。我做过一个简单测算把支持度 Top 20 的两项组合里的药材做一次库存关联分析能发现十几组总是一起断货的品种对调整补货策略后缺货率有可见下降。货位与陈列药房实际抓药是有动线的经常一起出现的药材如果摆得远抓一副药要来回走。把高支持度的组合尽量安排在同一货架区域能明显提升抓药效率。这个优化听起来朴素但对日均几百方的药房来说节省的时间很可观。推荐与搭配如果是零售场景顾客拿了甲药可以提示常一起购买的还有乙。但这里要特别谨慎涉及药材的推荐必须由专业人员把关合规性不能简单按算法结果推。5.3 跑不动的时候怎么优化数据量上万单之后几个地方会成为瓶颈我按见效快慢排个序第一先砍维度再进算法。低频药材出现率 0.3%对结果贡献极小却会显著增加候选集数量。先做一次列过滤通常能砍掉一半以上的列速度提升立竿见影。第二用 FP-Growth 替换 Apriori。输出完全一致速度快几倍到十几倍这个是最省事的替换。第三降低数据类型精度。TransactionEncoder默认输出object或int64转成bool后内存能降到四分之一。矩阵一大内存换页就是主要瓶颈这一步收益很高。第四分层挖掘。不要一次设很低的阈值跑全量。先高阈值挖短项集拿到稳定结果再降阈值挖长项集max_len卡在 4。分两次跑总时间往往比一次跑全量更短而且中间结果可以分别验证。第五限制规则数量。筛选条件越早加越好不要先把所有规则生成出来再筛。association_rules直接传metriclift和min_threshold让它在生成阶段就过滤掉大部分内存占用能差一个量级。6. 常见问题与排查实录这一段是我踩坑记录里挑出来的基本覆盖了新手到中级阶段会遇到的大部分问题。6.1 报错与异常速查表现象原因解决TypeError: association_rules() missing 1 required positional argument: num_itemsetsmlxtend 0.23 新增必填参数传入num_itemsetslen(frequent_items)ValueError: Columns must be same length as key传进去的矩阵含非 0/1 值onehot.astype(bool)频繁项集只有 1 项集没有 2 项集支持度阈值过高按处方总数换算降阈值结果为空 DataFrame筛选条件太严提升度、置信度同时卡太狠逐条放宽先只卡支持度看基础盘内存撑爆 / 进程被杀max_len未设或设太大卡max_len3~4先过滤低频列导出的 CSV 在 Excel 里中文乱码编码问题encodingutf-8-sig同一味药出现两个近似列别名未归一建别名字典 正则去括号规则条数上万无法阅读高频项污染 阈值太低剔除万金油项 提高支持度下限6.2 结果看起来没意义的几个真实原因很多人跑完发现规则全是甘草 → 陈皮这种觉得算法没用。其实问题往往不在算法在数据或参数。原因一样本量太小。只有三百张处方的时候支持度设 0.01 就是 3 次共现统计噪音完全盖过信号出来的规则自然像随机抽的。这种情况建议先积累数据或者把支持度设到 0.05 以上只看最强的两条项组合别贪多。原因二没有剔除高频项。前面反复说过万金油药材会占据大量规则额度。加一列是否含高频项标记把这类规则单独抽出来剩下的才是真正值得看的。原因三时间跨度混在一起。如果把三年的处方混成一坨季节性规律会被平均掉。比如某几味药只在冬季方子里高频共现全年数据一平均支持度就掉到阈值以下了。我现在的做法是按季度或按半年切片分别挖一遍对比不同时间窗口的差异经常能发现单一全局分析看不到的模式。原因四数据本身没有共现结构。这个要接受现实。有些业务场景下药材组合本来就是随机的硬挖一定是噪音。判断方法很直接——看提升度的分布如果绝大多数规则集中在 1.0~1.15说明数据里就不存在强关联这时候应该回头质疑这个分析目标是否本身就不成立而不是继续调参。6.3 几个只有真跑过才会知道的细节frozenset的坑。association_rules输出的antecedents和consequents是frozenset类型直接to_csv会变成对象字符串在 Excel 里既不能筛选也不能排序。必须先用 .join(sorted(x))转成普通字符串。我第一次交报告没做这一步业务方打开表格一脸茫然。排序键的选择。默认按support排序看的是多常见按lift排序看的是多强。给业务方的版本我一般按lift排因为支持度高的那批他们凭经验本来就知道给库存岗的版本按support排因为他们关心的是量。阈值不要一次定死。我现在的流程是先跑三组阈值比如支持度 0.02 / 0.01 / 0.005把三组结果放在一起对比。如果规则在三组里都稳定出现那这条规则的可信度就比较高只在最低阈值那组出现的多半是噪音。这个交叉验证的思路比单跑一次靠谱得多。中文字体。matplotlib 画图不设font.sans-serif的话所有中文会变成方块。这个坑几乎人人踩一次加上SimHei就行Mac 上换成PingFang SC。结果要留版本。每次调参跑出来的规则表都要带日期和参数存档比如rules_20250101_sup001_lift12.csv。不然后面业务方问上次那个结果怎么和现在不一样你根本说不清是哪次改了什么。7. 我个人在几个项目里沉淀下来的用法最后分享几个不太写在文档里的实际做法都是踩过坑之后总结的。第一件事是先跑一遍单味药频次榜再开始挖规则。这一步花不了几分钟但能立刻识别出哪些是万金油、哪些是稀有项后面设阈值和做过滤全靠这份榜。我一般会把频次榜直接发给业务方确认一遍这几个是不是确实什么方子都有得到确认之后再动手能省掉大量后期解释。第二件事是规则数量控制在 100 条以内再交付。几千条规则的表格没人看等于没做。我的做法是按提升度排序取前 100再人工过一遍把明显是数据问题的比如某味药在某段时间录入系统出错导致的异常高频剔掉剩下的配上几行说明一页纸讲清楚。交付物的价值不在于全在于能被人用起来。第三件事是把分析结果和实际业务动作做一次闭环验证。比如根据高频组合调整了货位一个月后回头看抓药时长有没有变化比如根据规则清单给业务方看问他们这些组合你们平时是不是也这么用如果对不上那大概率是数据有问题而不是他们经验有问题。这一步很多人会跳过但它是判断分析到底有没有价值的唯一办法。还有一个算不上技巧但很重要的认知Apriori 挖出来的东西是过去发生了什么不是应该发生什么。它能告诉你某两味药在历史数据里经常一起出现但不能告诉你为什么更不能告诉你这样配对不对。真正的价值在于把数据里的模式摊开让有经验的人去对照、去验证、去发现原来是这样或者这里不对劲。把它当成一面镜子比当成一个答案用处大得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑