关联分析通过寻找最能够解释数据变量之间关系的规则,来找出大量多元数据集中有用的关联规则,他是从大量数据中发现多种数据之间关系的一种方法。其典型案例是“啤酒和尿布”的捆绑销售,即买了尿布的用户还会同时买啤酒。
项集: 若干个项的集合;
频繁项集: 支持度大于等于最小支持度的项集;
支持度(support): 某个商品或商品组合出现的次数与总次数之间的比例;
置信度(confidence): 购买了商品A,购买商品B的概率,即置信度(A→B);
提升度(lift): 商品A的出现对商品B的出现概率提升程度,提升度(A→B)=置信度(A→B)/支持度(B),提升度大于1表明应用关联规则比不应用能产生更好的结果,等于1 表明应用关联规则与不应用产生相同的结果,而小于1时,关联规则有负相关的作用;
杠杆率(leverage): 表示当先导项(A)与后继项(B)独立分布时,先导项与后继项一起出现的次数比预期多多少;
确信度(conviction): 表示X出现而Y不出现的概率,也就是规则预测错误的概率;
常用关联算法包括Apriori、FP-Growth、PrefixSpan、SPADE、AprioriAll、AprioriSome等。
(1)“正相关”组合推荐
关联规则中的正相关规则可应用于捆绑销售、库存管理、商品促销设计、页面推荐设计等等,例如网站页面浏览关联分析通过找到用户在不同页面之间的频繁访问关系,以分析用户特定的页面浏览模式,这种频繁模式可用于不同页面之间的分流和引流关系;也可以用来做不同页面的浏览推荐,有利于提高用户网站体验和转化率;
(2)“负相关”优化组合策略
当一个关联规则中支持度和置信度很高时,说明这个规则是频繁的,但当这个规则的提升度很低时,那么说明规则中的前后项是相互排斥的,规则中的前后项通常不会一起发生,比如将白砂糖与葡糖糖放一起,用户购买了其中一种一般就不会买另一种。这个规则说明我们不能将此规则中的前后项通过组合、打包或关联策略展示给用户,它可以作为组合打包的控制条件来优化组合策略;
目的:
通过对淘宝用户购买的商品进行关联分析,发掘用户需求之间的联系,通过将具有强相关规则的商品打包组合推荐给客户来提升销量,改善用户体验;
1 导入库
numpy、pandas为数据读取和基本处理库,使用time库进行数据的筛选,利用mlxtend包里面的Apriori算法进行数据关联分析,并与fpgrowth算法进行比较;
#导入库
import numpy as np
import pandas as pd
import time
from mlxtend.frequent_patterns import fpgrowth,association_rules,apriori
2 数据读取及筛选
使用pandas循环分块读取文件的内容,并对数据进行处理,通过上篇统计分析可得出12月2号3号的点击量、成交量具有明显的上升,推测为临近双12商家进行促销推广等活动,用户购买的商品无法很好体现出用户的真实需求,不具有很强的泛化能力,故选择前7天具有购买行为的数据进行关联分析;
#读取数据
reader=pd.read_csv(r'F:\Dataanalysis\UserBehavior\userbehavior.csv',iterator=True)
chunksize=100000
loop=True
chunks=[]
while loop:
try:
chunk=reader.get_chunk(chunksize)
chunks.append(chunk)
except:
loop=False
print("iteror is over!")
df=pd.concat(chunks,ignore_index=True)
#对列进行命名
columns=['user_id','item_id','category_id','behavior','timestamp']
df.columns=columns
#以这三列为主键进行去重
df.drop_duplicates(['user_id','item_id','timestamp'],inplace=True)
def gettimestamp(timestr):
formatstr='%Y-%m-%d %H:%M:%S'
timeobj=time.strptime(timestr,formatstr)
timestamp=time.mktime(timeobj)
return int(timestamp)
starttime=gettimestamp('2017-11-25 00:00:00')
endtime=gettimestamp('2017-12-01 23:59:59')
data=df[(df.behavior=='buy')&(df.timestamp>=starttime)&(df.timestamp<=endtime)] #筛选时间以及有购买行为的记录
data=data[['user_id','category_id','behavior']]
3 数据处理
①商品有将近400万的数量,DataFrame数据结构无法保存如此大量数据并对具体的商品进行关联分析,采取分步的方法,先对商品类目进行关联分析再根据商品类目进行具体商品分析,使用groupby方法得出每个用户购买的商品类目;
②一个用户在7天内所购买的所有商品类目算一个订单,设支持度为0.001对项目集进行初步筛选,category_sel为商品类目出现次数大于573次的商品类;
③以商品类ID为链接键,使用merge方法将data_result与category_sel连接;
⑤data_merge[‘behavior’]=1,将每个商品种类的值设置为1,因为mlxtend库里的算法对处理的数据格式有要求,必须为宽表的格式,所谓宽表,就是把所有的商品都放在列上,每一条购买记录,如果买了该商品,相应的地方就是1,否则就是0,如下图输出所示。
⑥data_merge[‘category_id’]=data_merge[‘category_id’].map(str) ,将商品类ID由整数类型转化为字符串类型,否则在关联分析时会报错 ValueError: Due to current limitations in Pandas, if the sparse format has integer column names,names, please make sure they either start with 0
or cast them as string column names
⑦使用拆堆unstack的方法,将数据转化为宽表形式,也可以使用mlxtend库中的TransactionEncoder()进行数据的处理;
⑧如果一个数组(包括多维数组)中的大部分元素为0,或者为同一个值的数组时,可以使用稀疏数组来保存该数组,节约空间提高计算效率。本例使用pd.SparseDtype()将数据转化为稀疏数据结构
print('订单数量:',len(data_result['user_id'].unique())) #一个用户算一个订单,输出订单数量573905
category_counts=data_result['category_id'].value_counts()
category_sel=category_counts[category_counts>573] #假设支持度为0.001则商品出现次数应大于573=0.001*573905
print('商品类的数量:',len(category_sel)) #出现次数大于573的商品有432类
data_merge=pd.merge(data_result,category_sel,left_on='category_id',right_index=True)
data_merge['behavior']=1
data_merge['category_id']=data_merge['category_id'].map(str) #将category_id_x列转化为字符串类型
data_merge=data_merge[['user_id','category_id','behavior']]
final_data=data_merge.set_index(['user_id','category_id']).unstack(level=1).fillna(0)['behavior']
final_data_sparse=final_data.astype(pd.SparseDtype('bool'))
print('final_data占用字节:',final_data.memory_usage().sum())
print('final_data_sparse占用字节:',final_data_sparse.memory_usage().sum())
print(final_data_sparse)
输出如下:
订单数量: 573905
商品类的数量: 432
final_data占用字节: 1671037064
final_data_sparse占用字节: 8570803
4 关联分析
①使用魔术命令%%time对代码执行时间进行测试;
②使用fpgrowth算法生成频繁项集frequent_itemset,其中参数min_support为集合支持度(即先导项与后继项的并集出现的次数与总次数的比例),use_colnames=True使用DataFrame中的列名作为项集的名字而不是使用DataFrame的列索引。fpgrowth为apriori的改进算法,相对于apriori创建了FP树来存储频繁项集,创建前对不满足最小支持度的项进行删除,减小存储空间,在整个过程只遍历数据集2次,大大的提升了计算效率;
③使用association_rules方法以置信度confidence的阈值0.1生成关联规则rules;
④将关联规则以支持度lift倒序排列;
经过测试使用final_data进行关联分析平均需要6.3s,而使用final_data_sparse稀疏矩阵结构进行关联分析平均需要3.1s,明显提高了计算效率。当使用apriori算法进行分析时报错MemoryError: Unable to allocate 20.0 GiB for an array with shape (231076, 93096) and data type bool,可见当处理的数据量很大时apriori算法需要花费大量内存来进行计算
%%time
frequent_itemset=fpgrowth(final_data_sparse,min_support=0.001,use_colnames=True) #生成频繁项集
rules=association_rules(frequent_itemset,metric='confidence',min_threshold=0.1) #生成关联规则
rules.sort_values('lift',ascending=False,inplace=True)
print(rules)
5 结果处理
将各个项集出现的次数进行统计,并将其与频繁规则合并,如下图所示
base=len(final_data)
rules_counts=rules[['antecedent support','consequent support','support']]*base
rules_counts.rename(columns={'antecedent support':'antecedent count','consequent support':'consequent count','support':'union count'},inplace=True)
final=pd.concat((rules,rules_counts),axis=1).reset_index(drop=True)
print('总订单数:',base)
print(final)
输出:
总订单数:482401
6 结果分析
从上述结果中可以得出,满足最小支持度0.01和最小置信度0.1的关联规则共有11个,其提升度均大于1,表明应用关联规则比不应用关联规则更能提升用户购买的概率,运营部门可根据分析结果结合实际将具有高支持度、高提升度的商品种类进行组合打包推荐,提升用户购买概率,增加销售量,同时提升用户体验减少用户的搜索查找。
7 淘宝用户购买具体商品关联分析
选择提升度排名前六的商品种类(2640118,4339722,2578647,3738615,381850,1320293,149192,4159072,2885642)进行具体的商品关联分析,其完整代码如下:
import numpy as np
import pandas as pd
import time
from mlxtend.frequent_patterns import fpgrowth,association_rules,apriori
#读取数据
reader=pd.read_csv(r'F:\Dataanalysis\UserBehavior\userbehavior.csv',iterator=True)
chunksize=100000
loop=True
chunks=[]
while loop:
try:
chunk=reader.get_chunk(chunksize)
chunks.append(chunk)
except:
loop=False
print("iteror is over!")
df=pd.concat(chunks,ignore_index=True)
#对列进行命名
columns=['user_id','item_id','category_id','behavior','timestamp']
df.columns=columns
#以这三列为主键进行去重
df.drop_duplicates(['user_id','item_id','timestamp'],inplace=True)
def gettimestamp(timestr):
formatstr='%Y-%m-%d %H:%M:%S'
timeobj=time.strptime(timestr,formatstr)
timestamp=time.mktime(timeobj)
return int(timestamp)
starttime=gettimestamp('2017-11-25 00:00:00')
endtime=gettimestamp('2017-12-01 23:59:59')
data=df[(df.behavior=='buy')&(df.timestamp>=starttime)&(df.timestamp<=endtime)] #筛选时间以及有购买行为的记录
data_sel=data[data['category_id'].isin([2640118,4339722,2578647,3738615,381850,1320293,149192,4159072,2885642])] #筛选出需要分析的商品种类
#数据处理
data_sel=data_sel[['user_id','item_id','behavior']]
data_result=data_sel.groupby(['user_id','item_id'])['behavior'].count().reset_index()
data_result.behavior=1
data_result['item_id']=data_result['item_id'].map(str)
print('订单数量:',len(data_result['user_id'].unique()))
item_count=data_result['item_id'].value_counts()
item_sel=item_count[item_count>69]
data_merge=pd.merge(data_result,item_sel,left_on='item_id',right_index=True)
final_data=data_merge.pivot('user_id','item_id','behavior').fillna(0)
final_data_sparse=final_data.astype(pd.SparseDtype('bool'))
print('final_data占用字节:',final_data.memory_usage().sum())
print('final_data_sparse占用字节:',final_data_sparse.memory_usage().sum())
print(final_data_sparse)
#关联分析
%%time
frequent_itemset=fpgrowth(final_data_sparse,min_support=0.001,use_colnames=True) #生成频繁项集
rules=association_rules(frequent_itemset,metric='confidence',min_threshold=0.001) #挖掘关联规则
rules.sort_values('lift',ascending=False,inplace=True)
base=len(final_data)
rules_counts=rules[['antecedent support','consequent support','support']]*base
rules_counts.rename(columns={'antecedent support':'antecedent count','consequent support':'consequent count','support':'union count'},inplace=True)
final=pd.concat((rules,rules_counts),axis=1)
print(base)
print(final)
其结果如下:
从图中可得,相比于其他关联项集,商品931971和4551433具有较高的支持度和提升度,可以深入分析其原因,并结合实际将此两件商品进行打包组合或推荐,来提高 用户购买概率。