聯(lián)規(guī)則分析實(shí)戰(zhàn):從Apriori到FP-Growth的完整指南)
1. 從啤酒與尿布說(shuō)起關(guān)聯(lián)規(guī)則到底在解決什么問(wèn)題很多人第一次聽(tīng)到關(guān)聯(lián)規(guī)則分析這個(gè)詞腦子里浮現(xiàn)的可能是超市購(gòu)物籃里啤酒和尿布擺在一起的經(jīng)典故事。這個(gè)故事流傳太廣以至于不少人以為關(guān)聯(lián)規(guī)則就是用來(lái)做商品推薦的。這個(gè)理解不算錯(cuò)但太窄了。關(guān)聯(lián)規(guī)則分析的本質(zhì)是在一堆事件集合里找出哪些事件傾向于一起出現(xiàn)并且用可量化的指標(biāo)去衡量這種一起出現(xiàn)到底有多強(qiáng)、有多可信。我做了這么多年數(shù)據(jù)相關(guān)的工作接觸過(guò)的關(guān)聯(lián)規(guī)則場(chǎng)景遠(yuǎn)不止零售。比如運(yùn)維日志分析里某幾個(gè)報(bào)錯(cuò)總是前后腳出現(xiàn)這背后可能指向同一個(gè)根因比如內(nèi)容平臺(tái)上看了某類(lèi)視頻的用戶往往接著會(huì)看另一類(lèi)這可以用來(lái)做冷啟動(dòng)推薦再比如制造業(yè)的設(shè)備傳感器告警某些告警組合幾乎必然導(dǎo)致停機(jī)這就是典型的關(guān)聯(lián)模式。所以別把關(guān)聯(lián)規(guī)則局限在購(gòu)物籃三個(gè)字上它是一套通用的共現(xiàn)模式挖掘方法論。那它到底解決什么問(wèn)題一句話概括從大量事務(wù)數(shù)據(jù)中自動(dòng)發(fā)現(xiàn)如果出現(xiàn)了A那么很可能也會(huì)出現(xiàn)B這類(lèi)規(guī)則并且給出支持度、置信度、提升度等指標(biāo)讓你判斷這條規(guī)則值不值得信、值不值得用。它解決的是人工拍腦袋找組合效率太低的問(wèn)題。你不可能靠肉眼從十萬(wàn)條訂單里看出哪些商品組合有規(guī)律但算法可以。這篇文章我打算按一個(gè)完整的實(shí)操鏈路來(lái)講先講清楚幾個(gè)核心指標(biāo)到底怎么算、為什么這么算再講最經(jīng)典的Apriori算法和它為什么慢、FP-Growth怎么救場(chǎng)然后給一套能直接跑的代碼接著重點(diǎn)講參數(shù)怎么調(diào)、結(jié)果怎么篩——這部分是絕大多數(shù)教程不講但實(shí)際最要命的最后聊聊我踩過(guò)的坑和幾個(gè)容易翻車(chē)的地方。適合有一定Python基礎(chǔ)、想把這套東西真正用到業(yè)務(wù)里的人純小白也能看懂因?yàn)槲視?huì)盡量用生活化的例子把公式講透。2. 三個(gè)核心指標(biāo)支持度、置信度、提升度到底在衡量什么2.1 支持度這個(gè)組合到底常不常見(jiàn)支持度Support回答的是一個(gè)頻率問(wèn)題在所有事務(wù)里同時(shí)包含A和B的事務(wù)占了多大比例。公式很樸素Support(A→B) 同時(shí)包含A和B的事務(wù)數(shù) / 總事務(wù)數(shù)舉個(gè)例子假設(shè)一個(gè)便利店一天有1000筆訂單其中面包牛奶同時(shí)出現(xiàn)的有80筆那這個(gè)組合的支持度就是80/1000 8%。它衡量的是這個(gè)組合的普遍性。支持度太低說(shuō)明這個(gè)組合太罕見(jiàn)哪怕置信度很高也可能只是偶然沒(méi)有推廣價(jià)值。這里有個(gè)新手特別容易混淆的點(diǎn)支持度既可以指單個(gè)項(xiàng)集的支持度也可以指整條規(guī)則的支持度。比如面包這個(gè)單項(xiàng)的支持度可能是30%面包牛奶這個(gè)二項(xiàng)集的支持度是8%。在Apriori算法里我們通常先設(shè)定一個(gè)最小支持度閾值min_support把那些出現(xiàn)頻率太低的項(xiàng)集直接砍掉因?yàn)橐粋€(gè)低頻項(xiàng)集不可能衍生出高頻的規(guī)則。這個(gè)砍枝思想是Apriori能跑起來(lái)的關(guān)鍵后面會(huì)細(xì)講。提示最小支持度閾值的設(shè)定沒(méi)有萬(wàn)能公式。數(shù)據(jù)集越大閾值應(yīng)該越低。我一般先用0.01到0.05之間試看篩出來(lái)的規(guī)則數(shù)量再調(diào)整。如果規(guī)則多到幾千條說(shuō)明閾值太低如果一條都沒(méi)有說(shuō)明太高。2.2 置信度這條規(guī)則有多可信置信度Confidence回答的是可靠性問(wèn)題在出現(xiàn)了A的事務(wù)里有多大比例也出現(xiàn)了B。公式是Confidence(A→B) Support(A∪B) / Support(A)還是剛才的例子如果面包單獨(dú)出現(xiàn)的支持度是30%300筆面包牛奶的支持度是8%80筆那置信度就是8%/30% ≈ 26.7%。意思是買(mǎi)了面包的人里有大約26.7%也買(mǎi)了牛奶。置信度聽(tīng)起來(lái)很直觀但它有個(gè)著名的陷阱如果B本身就是一個(gè)超級(jí)常見(jiàn)的商品比如礦泉水單獨(dú)支持度就有60%那不管A是什么Confidence(A→B)都會(huì)很高因?yàn)榉帜感?、分子被B的高頻撐起來(lái)了。這時(shí)候規(guī)則看起來(lái)很可信其實(shí)毫無(wú)意義——買(mǎi)任何東西的人本來(lái)就會(huì)買(mǎi)礦泉水。這就是為什么光看置信度會(huì)翻車(chē)必須引入第三個(gè)指標(biāo)。2.3 提升度剔除本來(lái)就會(huì)買(mǎi)的干擾提升度Lift就是來(lái)解決上面那個(gè)陷阱的。它的公式是Lift(A→B) Confidence(A→B) / Support(B) Support(A∪B) / (Support(A) × Support(B))提升度的含義是在知道A發(fā)生的前提下B發(fā)生的概率相對(duì)于B本來(lái)發(fā)生的概率提升了多少倍。Lift 1A的出現(xiàn)確實(shí)提升了B出現(xiàn)的概率兩者正相關(guān)規(guī)則有價(jià)值。Lift 1A和B相互獨(dú)立A對(duì)B沒(méi)有任何影響規(guī)則沒(méi)意義。Lift 1A的出現(xiàn)反而抑制了B負(fù)相關(guān)?;氐降V泉水那個(gè)例子假設(shè)Confidence(面包→礦泉水) 55%而礦泉水本身的支持度是60%那Lift 55%/60% ≈ 0.92小于1。這說(shuō)明買(mǎi)面包的人買(mǎi)礦泉水的概率其實(shí)比普通人還略低一點(diǎn)這條規(guī)則完全是置信度制造的假象。所以我在實(shí)際項(xiàng)目里篩規(guī)則第一道硬門(mén)檻永遠(yuǎn)是Lift 1通常要求大于1.2甚至1.5才認(rèn)為有實(shí)際價(jià)值。下面這張表把三個(gè)指標(biāo)放在一起對(duì)比方便你建立整體認(rèn)知指標(biāo)衡量什么公式判斷標(biāo)準(zhǔn)常見(jiàn)誤區(qū)支持度組合的普遍性P(A∩B)越高越常見(jiàn)設(shè)太高會(huì)漏掉長(zhǎng)尾規(guī)則置信度規(guī)則可靠性P(A∩B)/P(A)越高越可信被高頻項(xiàng)污染提升度相關(guān)性強(qiáng)度置信度/P(B)1才有正相關(guān)忽略它只看置信度會(huì)翻車(chē)2.4 為什么必須三個(gè)指標(biāo)一起看單獨(dú)看任何一個(gè)指標(biāo)都會(huì)出問(wèn)題。只看支持度你會(huì)得到一堆礦泉水大米這種誰(shuí)都會(huì)買(mǎi)的組合只看置信度你會(huì)被高頻項(xiàng)帶偏只看提升度可能選出一個(gè)支持度極低、純屬偶然的規(guī)則。所以正確的做法是先用最小支持度砍掉低頻噪聲再用最小置信度保證可靠性最后用提升度1做價(jià)值過(guò)濾。這三層篩子缺一不可這也是我后面講參數(shù)調(diào)優(yōu)時(shí)的核心邏輯。3. Apriori算法那個(gè)砍枝思想為什么這么關(guān)鍵3.1 先理解頻繁項(xiàng)集這個(gè)概念在講算法之前得先建立一個(gè)概念頻繁項(xiàng)集Frequent Itemset。所謂項(xiàng)集就是若干個(gè)項(xiàng)的集合比如{面包, 牛奶}是一個(gè)二項(xiàng)集{面包, 牛奶, 雞蛋}是一個(gè)三項(xiàng)集。如果一個(gè)項(xiàng)集的支持度大于等于我們?cè)O(shè)定的最小支持度它就是頻繁項(xiàng)集。關(guān)聯(lián)規(guī)則挖掘其實(shí)分兩步走第一步找出所有頻繁項(xiàng)集第二步從頻繁項(xiàng)集里生成滿足最小置信度的規(guī)則。第二步相對(duì)簡(jiǎn)單真正難的是第一步因?yàn)轫?xiàng)的組合數(shù)量會(huì)爆炸。假設(shè)有100種商品理論上可能的項(xiàng)集數(shù)量是2的100次方這個(gè)數(shù)字大到宇宙毀滅都算不完。Apriori的貢獻(xiàn)就是用砍枝把這個(gè)搜索空間大幅壓縮。3.2 Apriori原理一個(gè)項(xiàng)集頻繁它的子集一定也頻繁Apriori的核心是一條聽(tīng)起來(lái)很樸素的定理如果一個(gè)項(xiàng)集是頻繁的那么它的所有子集也一定是頻繁的。反過(guò)來(lái)如果一個(gè)項(xiàng)集是非頻繁的那么它的所有超集也一定是非頻繁的。這條定理為什么成立因?yàn)橐粋€(gè)項(xiàng)集的支持度永遠(yuǎn)不可能超過(guò)它任何一個(gè)子集的支持度。你想同時(shí)包含{面包, 牛奶, 雞蛋}的訂單肯定也同時(shí)包含{面包, 牛奶}所以前者的數(shù)量一定小于等于后者。既然{面包, 牛奶}都不夠頻繁那加上雞蛋只會(huì)更少更不可能頻繁。這條定理的威力在于它讓我們可以逐層剪枝。先掃描一遍數(shù)據(jù)找出所有頻繁的單項(xiàng)集然后由頻繁單項(xiàng)集兩兩組合生成候選二項(xiàng)集再掃描數(shù)據(jù)驗(yàn)證哪些二項(xiàng)集真的頻繁接著由頻繁二項(xiàng)集生成候選三項(xiàng)集……每一層都把非頻繁的項(xiàng)集連同它的所有超集一起扔掉搜索空間就被指數(shù)級(jí)地壓縮了。3.3 手推一遍Apriori的執(zhí)行過(guò)程光講原理太抽象我用一個(gè)極簡(jiǎn)的例子帶你走一遍。假設(shè)有5筆交易T1: 面包, 牛奶 T2: 面包, 雞蛋 T3: 面包, 牛奶, 雞蛋 T4: 牛奶, 雞蛋 T5: 面包, 牛奶設(shè)最小支持度計(jì)數(shù)為2即至少出現(xiàn)2次。第一步統(tǒng)計(jì)單項(xiàng)面包出現(xiàn)4次牛奶出現(xiàn)4次雞蛋出現(xiàn)3次全部≥2都是頻繁單項(xiàng)集。第二步生成候選二項(xiàng)集并計(jì)數(shù){面包,牛奶}出現(xiàn)3次{面包,雞蛋}出現(xiàn)2次{牛奶,雞蛋}出現(xiàn)3次全部≥2都是頻繁二項(xiàng)集。第三步生成候選三項(xiàng)集{面包,牛奶,雞蛋}出現(xiàn)1次小于2被剪掉。最終頻繁項(xiàng)集就是三個(gè)單項(xiàng)集加三個(gè)二項(xiàng)集。整個(gè)過(guò)程只掃描了3遍數(shù)據(jù)。如果不用剪枝光二項(xiàng)集就有C(3,2)3個(gè)候選三項(xiàng)集1個(gè)雖然這個(gè)例子小看不出差距但當(dāng)商品有上千種時(shí)剪枝能省下的計(jì)算量是天文數(shù)字。3.4 Apriori的致命短板反復(fù)掃描數(shù)據(jù)Apriori最大的問(wèn)題是它每生成一層候選集就要完整掃描一遍數(shù)據(jù)庫(kù)來(lái)計(jì)數(shù)。如果最長(zhǎng)的頻繁項(xiàng)集有k項(xiàng)那就要掃描k遍。對(duì)于動(dòng)輒幾百萬(wàn)行、幾十個(gè)字段的數(shù)據(jù)集每掃一遍都是實(shí)打?qū)嵉腎O開(kāi)銷(xiāo)而且候選集在中間層可能會(huì)膨脹得非常大。我早年在一個(gè)訂單數(shù)據(jù)集上跑過(guò)Apriori數(shù)據(jù)量大概50萬(wàn)行商品種類(lèi)3000多最小支持度設(shè)0.005結(jié)果跑了將近20分鐘才出結(jié)果中間內(nèi)存還一度飆到幾個(gè)G。那次之后我就開(kāi)始認(rèn)真研究FP-Growth因?yàn)樗軓母旧辖鉀Q反復(fù)掃描這個(gè)問(wèn)題。4. FP-Growth把數(shù)據(jù)壓進(jìn)一棵樹(shù)只掃兩遍4.1 FP-Tree的核心思路FP-GrowthFrequent Pattern Growth的思路和Apriori完全不同。它不生成候選集而是把整個(gè)數(shù)據(jù)集壓縮成一棵叫FP-Tree的前綴樹(shù)結(jié)構(gòu)然后在這棵樹(shù)上遞歸地挖掘頻繁項(xiàng)集。整個(gè)算法只需要掃描兩遍數(shù)據(jù)第一遍統(tǒng)計(jì)每個(gè)項(xiàng)的頻次第二遍把每條事務(wù)按頻次排序后插入樹(shù)中。這棵樹(shù)為什么能壓縮數(shù)據(jù)因?yàn)橄嗤熬Y的事務(wù)會(huì)共享路徑。比如面包,牛奶,雞蛋和面包,牛奶,啤酒這兩條事務(wù)在樹(shù)里前兩個(gè)節(jié)點(diǎn)是共用的只在第三個(gè)節(jié)點(diǎn)分叉。數(shù)據(jù)集里重復(fù)模式越多壓縮效果越好。我見(jiàn)過(guò)一些實(shí)際數(shù)據(jù)壓縮后內(nèi)存占用只有原始數(shù)據(jù)的幾十分之一。4.2 為什么它比Apriori快這么多關(guān)鍵差異在于Apriori是廣度優(yōu)先、逐層生成候選、反復(fù)掃描FP-Growth是深度優(yōu)先、在樹(shù)上遞歸、不生成候選。前者在候選集膨脹時(shí)性能斷崖式下跌后者因?yàn)閿?shù)據(jù)已經(jīng)壓進(jìn)內(nèi)存里的樹(shù)挖掘過(guò)程基本是純內(nèi)存操作沒(méi)有反復(fù)的磁盤(pán)IO。不過(guò)FP-Growth也不是沒(méi)有代價(jià)。它需要把整棵樹(shù)放進(jìn)內(nèi)存如果數(shù)據(jù)量大到內(nèi)存裝不下就得做分區(qū)處理實(shí)現(xiàn)起來(lái)更復(fù)雜。所以選型上我的經(jīng)驗(yàn)是數(shù)據(jù)能裝進(jìn)內(nèi)存、追求速度用FP-Growth數(shù)據(jù)太大或者只需要跑一次、對(duì)速度不敏感Apriori也能湊合?,F(xiàn)在主流的庫(kù)比如mlxtend兩種都支持切換成本很低。4.3 兩種算法的對(duì)比與選型建議維度AprioriFP-Growth掃描次數(shù)每層一次共k次固定2次候選集需要生成可能爆炸不生成內(nèi)存占用較低較高需裝下整棵樹(shù)速度慢隨數(shù)據(jù)量急劇下降快通??煲粋€(gè)數(shù)量級(jí)實(shí)現(xiàn)復(fù)雜度簡(jiǎn)單較復(fù)雜適用場(chǎng)景小數(shù)據(jù)、教學(xué)、一次性任務(wù)中等數(shù)據(jù)、需要反復(fù)挖掘我的實(shí)際建議很直接只要數(shù)據(jù)量超過(guò)幾萬(wàn)行直接上FP-Growth別在Apriori上浪費(fèi)時(shí)間。除非你是為了理解算法原理做教學(xué)演示否則沒(méi)有理由選Apriori。5. 一套能直接跑的完整代碼5.1 環(huán)境準(zhǔn)備與依賴(lài)安裝我用的是Python生態(tài)里最順手的mlxtend庫(kù)它同時(shí)封裝了Apriori和FP-Growth接口統(tǒng)一省得自己造輪子。安裝就一行pip install mlxtend pandas如果你還想做可視化可以再裝個(gè)networkx和matplotlib用來(lái)畫(huà)關(guān)聯(lián)規(guī)則網(wǎng)絡(luò)圖后面會(huì)提到。5.2 數(shù)據(jù)準(zhǔn)備從原始記錄到事務(wù)列表關(guān)聯(lián)規(guī)則對(duì)數(shù)據(jù)格式有要求每一行是一筆事務(wù)每個(gè)事務(wù)是一個(gè)項(xiàng)的列表。原始數(shù)據(jù)往往是訂單號(hào)-商品這種長(zhǎng)表需要先做透視。假設(shè)你有一份CSV字段是order_id和productimport pandas as pd # 讀取原始長(zhǎng)表 df pd.read_csv(orders.csv) # 透視成每行一個(gè)訂單每列一個(gè)商品的0-1矩陣 basket df.groupby(order_id)[product].apply(list).tolist() # 或者用更規(guī)范的獨(dú)熱編碼方式 basket_encoded df.pivot_table( indexorder_id, columnsproduct, aggfunclambda x: 1, fill_value0 )這里有個(gè)細(xì)節(jié)要注意透視后的矩陣如果商品種類(lèi)很多會(huì)非常稀疏大部分是0內(nèi)存占用可能很大。如果商品超過(guò)幾千種建議先用支持度過(guò)濾掉低頻商品再做編碼。5.3 用FP-Growth挖掘頻繁項(xiàng)集from mlxtend.frequent_patterns import fpgrowth # 挖掘頻繁項(xiàng)集min_support0.01表示至少1%的訂單包含該項(xiàng)集 frequent_itemsets fpgrowth( basket_encoded, min_support0.01, use_colnamesTrue, max_len3 # 限制項(xiàng)集最大長(zhǎng)度避免組合爆炸 ) # 按支持度降序看前20個(gè) print(frequent_itemsets.sort_values(support, ascendingFalse).head(20))max_len這個(gè)參數(shù)特別重要。如果不限制算法可能會(huì)挖出十幾個(gè)項(xiàng)的超長(zhǎng)項(xiàng)集這些項(xiàng)集支持度極低、解釋性極差還拖慢速度。我一般限制在2到4之間看業(yè)務(wù)需要。5.4 生成規(guī)則并做第一輪篩選from mlxtend.frequent_patterns import association_rules # 生成規(guī)則min_threshold先設(shè)低一點(diǎn)后面再篩 rules association_rules( frequent_itemsets, metricconfidence, min_threshold0.3 ) # 第一輪篩選提升度大于1.2且支持度不能太低 rules rules[ (rules[lift] 1.2) (rules[support] 0.01) ] # 按提升度排序看結(jié)果 print(rules.sort_values(lift, ascendingFalse)[ [antecedents, consequents, support, confidence, lift] ].head(20))跑完這一步你就能拿到一張規(guī)則表每條規(guī)則都帶著支持度、置信度、提升度三個(gè)指標(biāo)。但拿到結(jié)果只是開(kāi)始真正決定成敗的是下一步——怎么從成百上千條規(guī)則里挑出真正有用的。6. 參數(shù)調(diào)優(yōu)與結(jié)果篩選這一步?jīng)Q定項(xiàng)目成敗6.1 最小支持度怎么定從數(shù)據(jù)規(guī)模倒推最小支持度是影響結(jié)果數(shù)量最敏感的旋鈕。設(shè)得太高長(zhǎng)尾的有價(jià)值規(guī)則全被砍掉設(shè)得太低規(guī)則多到?jīng)]法看。我的經(jīng)驗(yàn)做法是先估算你希望一條規(guī)則至少覆蓋多少筆事務(wù)。比如你希望一條規(guī)則至少覆蓋50筆訂單總訂單是1萬(wàn)筆那min_support就設(shè)0.005。這個(gè)從業(yè)務(wù)意義倒推閾值的思路比盲目試數(shù)字靠譜得多。另外支持度閾值和數(shù)據(jù)集大小是反比關(guān)系。1萬(wàn)行數(shù)據(jù)設(shè)0.01可能剛好100萬(wàn)行數(shù)據(jù)設(shè)0.01就會(huì)篩出海量規(guī)則這時(shí)候應(yīng)該降到0.001甚至更低。我一般會(huì)先跑一個(gè)支持度分布看看數(shù)據(jù)里項(xiàng)集的頻次分布長(zhǎng)什么樣再?zèng)Q定閾值。6.2 置信度和提升度的組合篩選策略前面說(shuō)過(guò)置信度會(huì)被高頻項(xiàng)污染所以我的篩選順序永遠(yuǎn)是先卡提升度再卡置信度。具體來(lái)說(shuō)提升度 1.2保證正相關(guān)這是硬門(mén)檻。置信度 0.5保證規(guī)則足夠可靠。支持度 業(yè)務(wù)最小覆蓋量保證規(guī)則有足夠的樣本支撐。這三個(gè)條件同時(shí)滿足的規(guī)則通常數(shù)量會(huì)從幾千條降到幾十條剩下的基本都是能拿給業(yè)務(wù)方看的。如果還是太多就把提升度門(mén)檻提到1.5或者把置信度提到0.6。6.3 怎么判斷一條規(guī)則有沒(méi)有業(yè)務(wù)價(jià)值指標(biāo)達(dá)標(biāo)不代表有業(yè)務(wù)價(jià)值。我判斷一條規(guī)則值不值得用會(huì)問(wèn)三個(gè)問(wèn)題第一這條規(guī)則符不符合常識(shí)如果挖出買(mǎi)牙膏的人買(mǎi)牙刷提升度再高也是廢話因?yàn)檫@是常識(shí)不需要算法告訴你。真正有價(jià)值的是那些反直覺(jué)的規(guī)則比如某個(gè)冷門(mén)配件和某個(gè)主產(chǎn)品的強(qiáng)關(guān)聯(lián)。第二這條規(guī)則能不能指導(dǎo)行動(dòng)如果一條規(guī)則指向的組合你沒(méi)法做任何運(yùn)營(yíng)動(dòng)作比如沒(méi)法捆綁銷(xiāo)售、沒(méi)法做推薦那它再漂亮也只是個(gè)數(shù)字。第三這條規(guī)則的樣本量夠不夠支持度0.001意味著只有幾十筆訂單支撐這種規(guī)則很可能是噪聲換個(gè)時(shí)間段就消失了。我一般要求規(guī)則至少覆蓋幾百筆事務(wù)才敢用。6.4 一個(gè)真實(shí)的調(diào)參踩坑記錄有次我?guī)鸵粋€(gè)內(nèi)容團(tuán)隊(duì)做視頻關(guān)聯(lián)分析一開(kāi)始min_support設(shè)了0.02結(jié)果一條規(guī)則都沒(méi)挖出來(lái)。我以為是數(shù)據(jù)問(wèn)題查了半天才發(fā)現(xiàn)是閾值太高——他們的視頻種類(lèi)有上萬(wàn)種單個(gè)視頻的觀看占比本來(lái)就低0.02意味著一個(gè)視頻要被2%的用戶看過(guò)這幾乎不可能。后來(lái)把閾值降到0.001規(guī)則一下就出來(lái)了。這個(gè)坑的教訓(xùn)是支持度閾值必須和數(shù)據(jù)的項(xiàng)基數(shù)匹配。項(xiàng)的種類(lèi)越多單項(xiàng)的占比就越低閾值就必須越低。零售場(chǎng)景商品幾千種閾值0.01還行視頻、文章這種內(nèi)容場(chǎng)景動(dòng)輒幾萬(wàn)幾十萬(wàn)項(xiàng)閾值得降到0.001甚至更低。這個(gè)規(guī)律我后來(lái)總結(jié)成一句話項(xiàng)越多閾值越低沒(méi)有例外。7. 那些教程不講的坑我踩過(guò)的幾個(gè)真實(shí)問(wèn)題7.1 數(shù)據(jù)里的偽關(guān)聯(lián)時(shí)間因素被忽略關(guān)聯(lián)規(guī)則只關(guān)心一起出現(xiàn)不關(guān)心先后順序也不關(guān)心時(shí)間。這會(huì)導(dǎo)致一類(lèi)隱蔽的偽關(guān)聯(lián)。比如某個(gè)促銷(xiāo)活動(dòng)期間A和B都被大量購(gòu)買(mǎi)算法會(huì)認(rèn)為A和B強(qiáng)關(guān)聯(lián)但實(shí)際上它們只是因?yàn)榇黉N(xiāo)才一起出現(xiàn)活動(dòng)一結(jié)束關(guān)聯(lián)就消失了。解決辦法是做時(shí)間切片分析把數(shù)據(jù)按周或按月切分分別挖掘只保留那些在多個(gè)時(shí)間段都穩(wěn)定出現(xiàn)的規(guī)則。穩(wěn)定出現(xiàn)的才是真關(guān)聯(lián)只在某個(gè)時(shí)間段出現(xiàn)的很可能是事件驅(qū)動(dòng)的偽關(guān)聯(lián)。7.2 高頻項(xiàng)的淹沒(méi)效應(yīng)前面提過(guò)高頻項(xiàng)會(huì)污染置信度這里再展開(kāi)說(shuō)一個(gè)更隱蔽的問(wèn)題高頻項(xiàng)不僅污染置信度還會(huì)淹沒(méi)真正有價(jià)值的規(guī)則。因?yàn)楦哳l項(xiàng)參與的規(guī)則數(shù)量極多排序時(shí)很容易把真正有價(jià)值的低頻規(guī)則擠到后面。我的處理辦法是在生成規(guī)則前先把那些支持度超過(guò)某個(gè)上限比如50%的超級(jí)高頻項(xiàng)單獨(dú)拎出來(lái)要么剔除要么單獨(dú)分析。這些項(xiàng)本身太普遍參與任何規(guī)則都會(huì)拉高置信度、拉低信息量。7.3 規(guī)則數(shù)量爆炸時(shí)怎么收斂當(dāng)數(shù)據(jù)量大、閾值又設(shè)得偏低時(shí)規(guī)則數(shù)量可能上萬(wàn)條人工根本看不過(guò)來(lái)。這時(shí)候有幾個(gè)收斂手段限制項(xiàng)集長(zhǎng)度max_len只挖2項(xiàng)和3項(xiàng)規(guī)則放棄長(zhǎng)規(guī)則。提高提升度門(mén)檻比如從1.2提到2.0只留強(qiáng)關(guān)聯(lián)。按前項(xiàng)分組每個(gè)前項(xiàng)只保留提升度最高的幾條規(guī)則。做規(guī)則聚類(lèi)把相似的規(guī)則歸并成一組看組級(jí)別的模式。我通常組合使用前三個(gè)手段基本能把規(guī)則收斂到可人工審閱的規(guī)模。7.4 結(jié)果的可解釋性別讓業(yè)務(wù)方看不懂技術(shù)人容易犯的一個(gè)錯(cuò)是把frozenset({面包, 牛奶})這種原始輸出直接甩給業(yè)務(wù)方。業(yè)務(wù)方看不懂frozenset也不知道提升度是什么。我的做法是輸出一張人話表格前項(xiàng)、后項(xiàng)、支持度百分比、置信度百分比、提升度再配一句自然語(yǔ)言描述比如購(gòu)買(mǎi)了面包的顧客中有26.7%也購(gòu)買(mǎi)了牛奶購(gòu)買(mǎi)概率是普通顧客的1.5倍。這樣業(yè)務(wù)方一眼就能判斷這條規(guī)則有沒(méi)有用。8. 從規(guī)則到行動(dòng)關(guān)聯(lián)規(guī)則怎么落地8.1 商品捆綁與貨架陳列最經(jīng)典的落地就是捆綁銷(xiāo)售和貨架陳列。把提升度高的商品組合放在一起或者打包成套餐。但這里有個(gè)反直覺(jué)的點(diǎn)不是所有高提升度組合都適合捆綁。如果兩個(gè)商品本來(lái)就是互補(bǔ)品比如牙膏和牙刷捆綁效果有限因?yàn)轭櫩捅緛?lái)就會(huì)一起買(mǎi)。真正適合捆綁的是那些提升度高但顧客沒(méi)意識(shí)到的組合用捆綁去提醒他們。8.2 推薦系統(tǒng)的召回層關(guān)聯(lián)規(guī)則在推薦系統(tǒng)里通常用在召回層而不是排序?qū)?。因?yàn)橐?guī)則是硬匹配缺乏個(gè)性化。做法是根據(jù)用戶當(dāng)前購(gòu)物車(chē)或?yàn)g覽歷史匹配前項(xiàng)包含這些商品的規(guī)則把后項(xiàng)商品作為候選召回再交給排序模型精排。這樣既利用了關(guān)聯(lián)規(guī)則的強(qiáng)解釋性又彌補(bǔ)了它不夠個(gè)性化的短板。8.3 異常檢測(cè)與根因分析這個(gè)用法比較小眾但很實(shí)用。在運(yùn)維或制造場(chǎng)景把告警組合當(dāng)作事務(wù)來(lái)挖關(guān)聯(lián)規(guī)則如果某幾個(gè)告警總是同時(shí)出現(xiàn)很可能指向同一個(gè)根因。提升度特別高的告警組合往往就是需要優(yōu)先排查的對(duì)象。我用這個(gè)方法幫團(tuán)隊(duì)定位過(guò)幾次偶發(fā)故障比一個(gè)個(gè)日志翻效率高多了。8.4 落地時(shí)的效果驗(yàn)證規(guī)則上線后一定要做A/B測(cè)試驗(yàn)證。因?yàn)殛P(guān)聯(lián)規(guī)則是從歷史數(shù)據(jù)挖出來(lái)的歷史規(guī)律不一定代表未來(lái)有效。我見(jiàn)過(guò)挖出來(lái)的規(guī)則在測(cè)試集上指標(biāo)很漂亮上線后轉(zhuǎn)化率卻沒(méi)變化的情況——原因是那些關(guān)聯(lián)本來(lái)就是顧客的固有行為你推不推他都會(huì)買(mǎi)。所以驗(yàn)證時(shí)要看增量而不是看總量。9. 寫(xiě)在最后的一點(diǎn)個(gè)人體會(huì)關(guān)聯(lián)規(guī)則分析這套東西算法本身其實(shí)不復(fù)雜Apriori和FP-Growth的原理一兩個(gè)小時(shí)就能搞明白代碼用mlxtend幾行就能跑通。真正拉開(kāi)差距的是參數(shù)怎么調(diào)、結(jié)果怎么篩、規(guī)則怎么解釋、落地怎么驗(yàn)證——這些沒(méi)有標(biāo)準(zhǔn)答案全靠一次次踩坑積累。我自己最大的體會(huì)是別迷信算法挖出來(lái)的結(jié)果要用業(yè)務(wù)常識(shí)去交叉驗(yàn)證。算法能發(fā)現(xiàn)模式但判斷模式有沒(méi)有價(jià)值還得靠人。那些反直覺(jué)又穩(wěn)定、又能指導(dǎo)行動(dòng)的規(guī)則才是真正值得投入的。至于那些買(mǎi)牙膏的人買(mǎi)牙刷式的規(guī)則讓算法自己留著就好別浪費(fèi)業(yè)務(wù)方的時(shí)間。如果你剛開(kāi)始做這塊我的建議是先拿一份小數(shù)據(jù)集把整個(gè)流程跑通重點(diǎn)體會(huì)支持度、置信度、提升度三個(gè)指標(biāo)隨參數(shù)變化的感覺(jué)。等你能憑經(jīng)驗(yàn)預(yù)判閾值調(diào)到多少會(huì)出多少規(guī)則的時(shí)候這套東西就算真正上手了。