數(shù)據(jù)分析案例丨商品零售購(gòu)物籃分析(下)
接上文:
數(shù)據(jù)分析案例丨商品零售購(gòu)物籃分析(上)
03
數(shù)據(jù)預(yù)處理
通過(guò)對(duì)數(shù)據(jù)探索分析,發(fā)現(xiàn)數(shù)據(jù)數(shù)據(jù)完整,并不存在缺失值。建模之前需要轉(zhuǎn)變數(shù)據(jù)的格式,才能使用apriori函數(shù)進(jìn)行關(guān)聯(lián)分析。對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換,如代碼清單1所示。
import pandas as pd
inputfile='../data/GoodsOrder.csv'
data = pd.read_csv(inputfile,encoding='gbk')
# 根據(jù)id對(duì)“Goods”列合并,并使用“,”將各商品隔開(kāi)
data['Goods'] = data['Goods'].apply(lambda x:','+x)
data = data.groupby('id').sum().reset_index()
# 對(duì)合并的商品列轉(zhuǎn)換數(shù)據(jù)格式
data['Goods'] = data['Goods'].apply(lambda x :[x[1:]])
data_list = list(data['Goods'])
# 分割商品名為每個(gè)元素
data_translation = []
for i in data_list:
? ?p = i[0].split(',')
? ?data_translation.append(p)
print('數(shù)據(jù)轉(zhuǎn)換結(jié)果的前5個(gè)元素:\n', data_translation[0:5])
代碼清單1
04
模型構(gòu)建
本案例的目標(biāo)是探索商品之間的關(guān)聯(lián)關(guān)系,因此采用關(guān)聯(lián)規(guī)則算法,挖掘它們之間的關(guān)聯(lián)關(guān)系。關(guān)聯(lián)規(guī)則算法主要用于尋找數(shù)據(jù)中項(xiàng)集之間的關(guān)聯(lián)關(guān)系。它揭示了數(shù)據(jù)項(xiàng)間的未知關(guān)系,基于樣本的統(tǒng)計(jì)規(guī)律,進(jìn)行關(guān)聯(lián)規(guī)則分析。根據(jù)所分析的關(guān)聯(lián)關(guān)系,可從一個(gè)屬性的信息來(lái)推斷另一個(gè)屬性的信息。當(dāng)置信度達(dá)到某一閾值時(shí),就可以認(rèn)為規(guī)則成立。Apriori算法是常用的關(guān)聯(lián)規(guī)則算法之一,也是最為經(jīng)典的分析頻繁項(xiàng)集的算法,第一次實(shí)現(xiàn)在大數(shù)據(jù)集上可行的關(guān)聯(lián)規(guī)則提取的算法。除此之外,還有FP-Tree算法,Eclat算法和灰色關(guān)聯(lián)算法等。本案例主要使用Apriori算法進(jìn)行分析。
1.?商品購(gòu)物籃關(guān)聯(lián)規(guī)則模型構(gòu)建
本次商品購(gòu)物籃關(guān)聯(lián)規(guī)則建模的流程如圖1所示。

圖1 商品購(gòu)物籃關(guān)聯(lián)規(guī)則模型建模流程圖
由圖1可知,模型主要由輸入、算法處理、輸出3個(gè)部分組成。輸入部分包括:建模樣本數(shù)據(jù)的輸入;建模參數(shù)的輸入。算法處理部分是采用Apriori關(guān)聯(lián)規(guī)則算法進(jìn)行處理。輸出部分為采用Apriori關(guān)聯(lián)規(guī)則算法進(jìn)行處理后的結(jié)果。
模型具體實(shí)現(xiàn)步驟為:首先設(shè)置建模參數(shù)最小支持度、最小置信度,輸入建模樣本數(shù)據(jù);然后采用Apriori關(guān)聯(lián)規(guī)則算法對(duì)建模的樣本數(shù)據(jù)進(jìn)行分析,以模型參數(shù)設(shè)置的最小支持度、最小置信度以及分析目標(biāo)作為條件,如果所有的規(guī)則都不滿足條件,則需要重新調(diào)整模型參數(shù),否則輸出關(guān)聯(lián)規(guī)則結(jié)果。
目前,如何設(shè)置最小支持度與最小置信度,并沒(méi)有統(tǒng)一的標(biāo)準(zhǔn)。大部分都是根據(jù)業(yè)務(wù)經(jīng)驗(yàn)設(shè)置初始值,然后經(jīng)過(guò)多次調(diào)整,獲取與業(yè)務(wù)相符的關(guān)聯(lián)規(guī)則結(jié)果。本案例經(jīng)過(guò)多次調(diào)整并結(jié)合實(shí)際業(yè)務(wù)分析,選取模型的輸入?yún)?shù)為:最小支持度0.02、最小置信度0.35。其關(guān)聯(lián)規(guī)則代碼如代碼清單2所示。
from numpy import *
def loadDataSet():
? ?return [['a', 'c', 'e'], ['b', 'd'], ['b', 'c'], ['a', 'b', 'c', 'd'], ['a', 'b'], ['b', 'c'], ['a', 'b'],
? ? ? ? ? ?['a', 'b', 'c', 'e'], ['a', 'b', 'c'], ['a', 'c', 'e']]
def createC1(dataSet):
? ?C1 = []
? ?for transaction in dataSet:
? ? ? ?for item in transaction:
? ? ? ? ? ?if not [item] in C1:
? ? ? ? ? ? ? ?C1.append([item])
? ?C1.sort()
? ?# 映射為frozenset唯一性的,可使用其構(gòu)造字典
? ?return list(map(frozenset, C1)) ? ?
# 從候選K項(xiàng)集到頻繁K項(xiàng)集(支持度計(jì)算)
def scanD(D, Ck, minSupport):
? ?ssCnt = {}
? ?for tid in D: ? # 遍歷數(shù)據(jù)集
? ? ? ?for can in Ck: ?# 遍歷候選項(xiàng)
? ? ? ? ? ?if can.issubset(tid): ?# 判斷候選項(xiàng)中是否含數(shù)據(jù)集的各項(xiàng)
? ? ? ? ? ? ? ?if not can in ssCnt:
? ? ? ? ? ? ? ? ? ?ssCnt[can] = 1 ?# 不含設(shè)為1
? ? ? ? ? ? ? ?else:
? ? ? ? ? ? ? ? ? ?ssCnt[can] += 1 ?# 有則計(jì)數(shù)加1
? ?numItems = float(len(D)) ?# 數(shù)據(jù)集大小
? ?retList = [] ?# L1初始化
? ?supportData = {} ?# 記錄候選項(xiàng)中各個(gè)數(shù)據(jù)的支持度
? ?for key in ssCnt:
? ? ? ?support = ssCnt[key] / numItems ?# 計(jì)算支持度
? ? ? ?if support >= minSupport:
? ? ? ? ? ?retList.insert(0, key) ?# 滿足條件加入L1中
? ? ? ? ? ?supportData[key] = support ?
? ?return retList, supportData
def calSupport(D, Ck, min_support):
? ?dict_sup = {}
? ?for i in D:
? ? ? ?for j in Ck:
? ? ? ? ? ?if j.issubset(i):
? ? ? ? ? ? ? ?if not j in dict_sup:
? ? ? ? ? ? ? ? ? ?dict_sup[j] = 1
? ? ? ? ? ? ? ?else:
? ? ? ? ? ? ? ? ? ?dict_sup[j] += 1
? ?sumCount = float(len(D))
? ?supportData = {}
? ?relist = []
? ?for i in dict_sup:
? ? ? ?temp_sup = dict_sup[i] / sumCount
? ? ? ?if temp_sup >= min_support:
? ? ? ? ? ?relist.append(i)
# 此處可設(shè)置返回全部的支持度數(shù)據(jù)(或者頻繁項(xiàng)集的支持度數(shù)據(jù))
? ? ? ? ? ?supportData[i] = temp_sup
? ?return relist, supportData
# 改進(jìn)剪枝算法
def aprioriGen(Lk, k):
? ?retList = []
? ?lenLk = len(Lk)
? ?for i in range(lenLk):
? ? ? ?for j in range(i + 1, lenLk): ?# 兩兩組合遍歷
? ? ? ? ? ?L1 = list(Lk[i])[:k - 2]
? ? ? ? ? ?L2 = list(Lk[j])[:k - 2]
? ? ? ? ? ?L1.sort()
? ? ? ? ? ?L2.sort()
? ? ? ? ? ?if L1 == L2: ?# 前k-1項(xiàng)相等,則可相乘,這樣可防止重復(fù)項(xiàng)出現(xiàn)
? ? ? ? ? ? ? ?# 進(jìn)行剪枝(a1為k項(xiàng)集中的一個(gè)元素,b為它的所有k-1項(xiàng)子集)
? ? ? ? ? ? ? ?a = Lk[i] | Lk[j] ?# a為frozenset()集合
? ? ? ? ? ? ? ?a1 = list(a)
? ? ? ? ? ? ? ?b = []
? ? ? ? ? ? ? ?# 遍歷取出每一個(gè)元素,轉(zhuǎn)換為set,依次從a1中剔除該元素,并加入到b中
? ? ? ? ? ? ? ?for q in range(len(a1)):
? ? ? ? ? ? ? ? ? ?t = [a1[q]]
? ? ? ? ? ? ? ? ? ?tt = frozenset(set(a1) - set(t))
? ? ? ? ? ? ? ? ? ?b.append(tt)
? ? ? ? ? ? ? ?t = 0
? ? ? ? ? ? ? ?for w in b:
? ? ? ? ? ? ? ? ? ?# 當(dāng)b(即所有k-1項(xiàng)子集)都是Lk(頻繁的)的子集,則保留,否則刪除
? ? ? ? ? ? ? ? ? ?if w in Lk:
? ? ? ? ? ? ? ? ? ? ? ?t += 1
? ? ? ? ? ? ? ?if t == len(b):
? ? ? ? ? ? ? ? ? ?retList.append(b[0] | b[1])
? ?return retList
def apriori(dataSet, minSupport=0.2):
# 前3條語(yǔ)句是對(duì)計(jì)算查找單個(gè)元素中的頻繁項(xiàng)集
? ?C1 = createC1(dataSet)
? ?D = list(map(set, dataSet)) ?# 使用list()轉(zhuǎn)換為列表
? ?L1, supportData = calSupport(D, C1, minSupport)
? ?L = [L1] ?# 加列表框,使得1項(xiàng)集為一個(gè)單獨(dú)元素
? ?k = 2
? ?while (len(L[k - 2]) > 0): ?# 是否還有候選集
? ? ? ?Ck = aprioriGen(L[k - 2], k)
? ? ? ?Lk, supK = scanD(D, Ck, minSupport) ?# scan DB to get Lk
? ? ? ?supportData.update(supK) ?# 把supk的鍵值對(duì)添加到supportData里
? ? ? ?L.append(Lk) ?# L最后一個(gè)值為空集
? ? ? ?k += 1
? ?del L[-1] ?# 刪除最后一個(gè)空集
? ?return L, supportData ?# L為頻繁項(xiàng)集,為一個(gè)列表,1,2,3項(xiàng)集分別為一個(gè)元素
# 生成集合的所有子集
def getSubset(fromList, toList):
? ?for i in range(len(fromList)):
? ? ? ?t = [fromList[i]]
? ? ? ?tt = frozenset(set(fromList) - set(t))
? ? ? ?if not tt in toList:
? ? ? ? ? ?toList.append(tt)
? ? ? ? ? ?tt = list(tt)
? ? ? ? ? ?if len(tt) > 1:
? ? ? ? ? ? ? ?getSubset(tt, toList)
def calcConf(freqSet, H, supportData, ruleList, minConf=0.7):
? ?for conseq in H: ?#遍歷H中的所有項(xiàng)集并計(jì)算它們的可信度值
? ? ? ?conf = supportData[freqSet] / supportData[freqSet - conseq] ?# 可信度計(jì)算,結(jié)合支持度數(shù)據(jù)
? ? ? ?# 提升度lift計(jì)算lift = p(a & b) / p(a)*p(b)
? ? ? ?lift = supportData[freqSet] / (supportData[conseq] * supportData[freqSet - conseq])
? ? ? ?if conf >= minConf and lift > 1:
? ? ? ? ? ?print(freqSet - conseq, '-->', conseq, '支持度', round(supportData[freqSet], 6), '置信度:', round(conf, 6),
? ? ? ? ? ? ? ? ?'lift值為:', round(lift, 6))
? ? ? ? ? ?ruleList.append((freqSet - conseq, conseq, conf))
# 生成規(guī)則
def gen_rule(L, supportData, minConf0.7):
? ?bigRuleList = []
? ?for i in range(1, len(L)): ?# 從二項(xiàng)集開(kāi)始計(jì)算
? ? ? ?for freqSet in L[i]: ?# freqSet為所有的k項(xiàng)集
? ? ? ? ? ?# 求該三項(xiàng)集的所有非空子集,1項(xiàng)集,2項(xiàng)集,直到k-1項(xiàng)集,用H1表示,為list類型,里面為frozenset類型,
? ? ? ? ? ?H1 = list(freqSet)
? ? ? ? ? ?all_subset = []
? ? ? ? ? ?getSubset(H1, all_subset) ?# 生成所有的子集
? ? ? ? ? ?calcConf(freqSet, all_subset, supportData, bigRuleList, minConf)
? ?return bigRuleList
if __name__ == '__main__':
? ?dataSet = data_translation
? ?L, supportData = apriori(dataSet, minSupport0.02)
? ?rule = gen_rule(L, supportData, minConf0.35)
代碼清單2???構(gòu)建關(guān)聯(lián)規(guī)則模型
運(yùn)行代碼清單2得到的結(jié)果如下。
frozenset({'水果/蔬菜汁'}) --> frozenset({'全脂牛奶'}) 支持度 0.02664 置信度:0.368495 lift值為:1.44216
frozenset({'人造黃油'}) --> frozenset({'全脂牛奶'}) 支持度 0.024199 置信度:0.413194 lift值為:1.617098
... ? ? ... ? ? ?... ? ? ?...
frozenset({'根莖類蔬菜', '其他蔬菜'}) --> frozenset({'全脂牛奶'}) 支持度 0.023183 置信度:0.48927 lift值為:1.914833
2.模型分析
根據(jù)代碼清單2運(yùn)行結(jié)果,我們得出了26個(gè)關(guān)聯(lián)規(guī)則。根據(jù)規(guī)則結(jié)果,可整理出購(gòu)物籃關(guān)聯(lián)規(guī)則模型結(jié)果,如表1所示。

表1??購(gòu)物籃關(guān)聯(lián)規(guī)則模型結(jié)果
根據(jù)表1中的輸出結(jié)果,對(duì)其中4條進(jìn)行解釋分析如下。
(1)?{'其他蔬菜',?'酸奶'}=>{'全脂牛奶'}支持度為2.23%,置信度最大為51,29%。說(shuō)明同時(shí)購(gòu)買(mǎi)酸奶,其他蔬菜和全脂牛奶這3種商品的概率達(dá)51,29%,而這種情況發(fā)生的可能性為2.23%。
(2)?{'其他蔬菜'}=>{'全脂牛奶'}支持度最大為7.48%,置信度為38.68%。說(shuō)明同時(shí)購(gòu)買(mǎi)其他蔬菜和全脂牛奶這2種商品的概率達(dá)38.68%,而這種情況發(fā)生的可能性為7.48%。
(3)?{'根莖類蔬菜'}=>{'全脂牛奶'}支持度為4.89%,置信度為44.87%。說(shuō)明同時(shí)購(gòu)買(mǎi)根莖類蔬菜和全脂牛奶這三種商品的概率達(dá)44.87%,而這種情況發(fā)生的可能性為4.89%。
(4)?{'根莖類蔬菜'}=>{'其他蔬菜'}支持度為4.74%,置信度為43.47%。說(shuō)明同時(shí)根莖類蔬菜和其他蔬菜這2種商品的概率達(dá)43.47%,而這種情況發(fā)生的可能性為4.74%。
綜合表1以及輸出結(jié)果分析,顧客購(gòu)買(mǎi)酸奶和其他蔬菜的時(shí)候會(huì)同時(shí)購(gòu)買(mǎi)全脂牛奶,其置信度最大達(dá)到51,29%。其他蔬菜、根莖類蔬菜和全脂牛奶同時(shí)購(gòu)買(mǎi)的概率較高。
對(duì)于模型結(jié)果,從購(gòu)物者角度進(jìn)行分析:現(xiàn)代生活中,大多數(shù)購(gòu)物者為家庭煮婦,購(gòu)買(mǎi)的商品大部分是食品,隨著生活質(zhì)量和健康意識(shí)的增加,其他蔬菜、根莖類蔬菜和全脂牛奶均為現(xiàn)代家庭每日飲食所需品,因此,其他蔬菜、根莖類蔬菜和全脂牛奶同時(shí)購(gòu)買(mǎi)的概率較高符合現(xiàn)代人們的生活健康意識(shí)。
2.模型應(yīng)用
模型結(jié)果表明顧客購(gòu)買(mǎi)商品的時(shí)候會(huì)同時(shí)購(gòu)買(mǎi)全脂牛奶。因此,商場(chǎng)應(yīng)該根據(jù)實(shí)際情況將全脂牛奶放在顧客購(gòu)買(mǎi)商品的必經(jīng)之路,或者商場(chǎng)顯眼位置,方便顧客拿取。其他蔬菜、根莖類蔬菜、酸奶油、豬肉、黃油、本地蛋類和多種水果同時(shí)購(gòu)買(mǎi)的概率較高,可以考慮捆綁銷售,或者適當(dāng)調(diào)整商場(chǎng)布置,將這些商品的距離盡量拉近,提升購(gòu)物體驗(yàn)。?
? ?更多數(shù)據(jù)分析案例可持續(xù)關(guān)注~關(guān)在線課程可到大數(shù)據(jù)培訓(xùn)平臺(tái)-泰迪云課堂咨詢了解更多~