机器学习——关联规则
机器学习——关联规则
- (一)关联规则原理
- (二)关联规则代码实现
(一)关联规则原理
在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,超市也因此发现了一个规律,在购买婴儿尿布的年轻父亲们中,有30%~40%的人同时要买一些啤酒。超市随后调整了货架的摆放,把尿布和啤酒放在一起,明显增加了销售额。
若两个或多个变量的取值之间存在某种规律性,就称为关联。
关联规则是寻找在同一个事件中出现的不同项的相关性,比如在一次购买活动中所买不同商品的相关性。
编号 | 牛奶 | 果冻 | 啤酒 | 面包 | 花生酱 |
---|---|---|---|---|---|
T1 | 1 | 1 | 0 | 0 | 1 |
T2 | 0 | 1 | 0 | 1 | 0 |
T3 | 0 | 1 | 1 | 0 | 0 |
T4 | 1 | 1 | 0 | 1 | 0 |
T5 | 1 | 0 | 1 | 0 | 0 |
T6 | 0 | 1 | 1 | 0 | 0 |
T7 | 1 | 0 | 1 | 0 | 0 |
T8 | 1 | 1 | 1 | 0 | 1 |
T9 | 1 | 1 | 1 | 0 | 0 |
一个样本称为一个事物
每个事务由多个属性来确定,这里的属性称为“项”
多个项组成的集合称为“项集”
由k个项构成的集合
{牛奶}、{啤酒}都是1-项集;
{牛奶,果冻}是2-项集;
{啤酒,面包,牛奶}是3-项集
X==>Y含义:
X和Y是项集
X称为规则前项(antecedent)
Y称为规则后项(consequent)
事务仅包含其涉及到的项目,而不包含项目的具体信息。
在超级市场的关联规则挖掘问题中事务是顾客一次购物所购买的商品,但事务中并不包含这些商品的具体信息,如商品的数量、价格等。
支持度(support):一个项集或者规则在所有事务中出现的频率,σ(X):表示项集X的支持度计数
- 项集X的支持度:s(X)=σ(X)/N。
- 规则X==>Y表示物品集X对物品集Y的支持度,也就是物品集X和物品集Y同时出现的概率。
- 某天共有100个顾客到商场购买物品,其中有30个顾客同时购买了啤酒和尿布,那么上述的关联规则的支持度就是30%。
置信度(confidence):确定Y在包含X的事务中出现的频繁程度。
c ( X → Y ) = σ ( X ∪ Y ) / σ ( X ) c(X\rightarrow Y)=\sigma (X\cup Y)/\sigma (X) c(X→Y)=σ(X∪Y)/σ(X)
- p ( Y ∣ X ) = p ( X Y ) / p ( X ) p(Y|X)=p(XY)/p(X) p(Y∣X)=p(XY)/p(X)
- 置信度反应了关联规则的可信度—购买了项目集X中的商品的顾客同时也购买了Y中商品的可能性有多大
- 购买薯片的顾客中有50%的人购买了可乐,则置信度为50%。
举例:
交易ID | 购买的商品 |
---|---|
1 | A,B,C |
2 | A,C |
3 | A,D |
4 | B,E,F |
(X,Y)==>Z
- 支持度:交易中包含{X 、 Y 、 Z}的可能性。
- 置信度:包含{X 、 Y}的交易中也包含Z的条件概率
设最小支持度为50%, 最小可信度为 50%, 则可得到 :
- A==>C (50%, 66.6%)
- C==>A (50%, 100%)
若关联规则X->Y的支持度和置信度分别大于或等于用户指定的最小支持率minsupport和最小置信度minconfidence,则称关联规则X->Y为强关联规则,否则称关联规则X->Y为弱关联规则。
提升度(lift):物品集A的出现对物品集B的出现概率发生了多大的变化。
- l i f t ( A = = > B ) = c o n f i d e n c e ( A = = > B ) / s u p p o r t ( B ) = p ( B ∣ A ) / p ( B ) lift(A==>B)=confidence(A==>B)/support(B)=p(B|A)/p(B) lift(A==>B)=confidence(A==>B)/support(B)=p(B∣A)/p(B)
- 现在有1000 个消费者,有500 人购买了茶叶,其中有450人同时 购买了咖啡,另50人 没有。由于confidence(茶叶=>咖啡)=450/500=90% ,由此可能会认为喜欢喝茶的人往往喜欢喝咖啡。但如果另外没有购买茶叶的500人 ,其中同样有450人 购买了咖啡,同样是很高的置信度90% ,由此,得到不爱喝茶的也爱喝咖啡。这样看来,其实是否购买咖啡,与有没有购买茶叶并没有关联,两者是相互独立的,其提升度90%/[(450+450)/1000]=1 。
由此可见,lift正是弥补了confidence的这一缺陷,if lift=1,X与Y独立,X对Y出现的可能性没有提升作用,其值越大(lift>1),则表明X对Y的提升程度越大,也表明关联性越强。
X | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|---|---|---|
Y | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Z | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
rule | Support | Lift |
---|---|---|
X=>Y | 25% | 2.00 |
X=>Z | 37.50% | 0.86 |
Y=>Z | 12.50% | 0.57 |
Leverage 与 Conviction的作用和lift类似,都是值越大代表越关联。
Leverage: P ( A , B ) − P ( A ) P ( B ) P(A,B)-P(A)P(B) P(A,B)−P(A)P(B)
Conviction: P ( A ) P ( ! B ) / P ( A , ! B ) P(A)P(!B)/P(A,!B) P(A)P(!B)/P(A,!B)
使用mlxtend工具包得出频繁项集与规则
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
自定义一份购物数据集
data = {'ID':[1,2,3,4,5,6],'Onion':[1,0,0,1,1,1],'Potato':[1,1,0,1,1,1],'Burger':[1,1,0,0,1,1],'Milk':[0,1,1,1,0,1],'Beer':[0,0,1,0,1,0]}
df = pd.DataFrame(data)
df = df[['ID', 'Onion', 'Potato', 'Burger', 'Milk', 'Beer' ]]
df
设置支持度 (support) 来选择频繁项集。选择最小支持度为50%
apriori(df, min_support=0.5, use_colnames=True)
frequent_itemsets = apriori(df[['Onion', 'Potato', 'Burger', 'Milk', 'Beer' ]], min_support=0.50, use_colnames=True)
frequent_itemsets
返回的3种项集均是支持度>=50%
计算规则
association_rules(df, metric=‘lift’, min_threshold=1)
可以指定不同的衡量标准与最小阈值
rules = association_rules(frequent_itemsets, metric='lift', min_threshold=1)
rules
返回的是各个的指标的数值。
rules [ (rules['lift'] >1.125) & (rules['confidence']> 0.8) ]
发现:
- (洋葱和马铃薯)(汉堡和马铃薯)提升度和置信度都比较高,可以搭配着来卖。
- 如果洋葱和汉堡都在购物篮中, 顾客买马铃薯的可能性也比较高,如果他篮子里面没有,可以推荐一下.
数据需转换成one-hot编码
#创建一个购物篮数据集
retail_shopping_basket = {'ID':[1,2,3,4,5,6],'Basket':[['Beer', 'Diaper', 'Pretzels', 'Chips', 'Aspirin'],['Diaper', 'Beer', 'Chips', 'Lotion', 'Juice', 'BabyFood', 'Milk'],['Soda', 'Chips', 'Milk'],['Soup', 'Beer', 'Diaper', 'Milk', 'IceCream'],['Soda', 'Coffee', 'Milk', 'Bread'],['Beer', 'Chips']]}
retail = pd.DataFrame(retail_shopping_basket)
retail = retail[['ID', 'Basket']]
pd.options.display.max_colwidth=100
retail
数据集中都是字符串组成的,需要转换成数值编码。
retail_id = retail.drop('Basket' ,1)
retail_id
retail_Basket = retail.Basket.str.join(',')
retail_Basket
retail_Basket = retail_Basket.str.get_dummies(',')
retail_Basket
retail = retail_id.join(retail_Basket)
retail
frequent_itemsets_2 = apriori(retail.drop('ID',1), use_colnames=True)
frequent_itemsets_2
如果只考虑支持度support(X>Y), [Beer, Chips] 和 [Beer, Diaper] 都是很频繁的,哪一种组合更相关呢?
association_rules(frequent_itemsets_2, metric='lift')
显然{Diaper, Beer}更相关一些。
电影题材关联
movies = pd.read_csv('ml-latest-small/movies.csv')
movies.head(10)
数据中包括电影名字与电影类型的标签,第一步还是先转换成one-hot格式。
movies_ohe = movies.drop('genres',1).join(movies.genres.str.get_dummies())
pd.options.display.max_columns=100
movies_ohe.head()
movies_ohe.shape
(9125, 22)
数据集包括9125部电影,一共有20种不同类型。
movies_ohe.set_index(['movieId','title'],inplace=True)
movies_ohe.head()
frequent_itemsets_movies = apriori(movies_ohe,use_colnames=True, min_support=0.025) #设置最小支持度0.025
frequent_itemsets_movies
rules_movies = association_rules(frequent_itemsets_movies, metric='lift', min_threshold=1.25) #设置最小提升度1.25
rules_movies
rules_movies[(rules_movies.lift>4)].sort_values(by=['lift'], ascending=False)
Children和Animation 这俩题材是最相关的了,常识也可以分辨出来。
movies[(movies.genres.str.contains('Children')) & (~movies.genres.str.contains('Animation'))]
具体分析还得落实到数据本身,这就需要充分理解数据才可以。
(二)关联规则代码实现
使用Apriori算法来发现频繁集:
Apriori原理可以帮我们减少可能感兴趣的项集。Apriori原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。根据上图给出的例子,这意味着如果{0,1}是频繁的,那么{0}、{1}也一定是频繁的。这个原理直观上并没有什么帮助,但是如果反过来看就有用了,也就是说如果一个项集是非频繁集,那么它的所有超集也是非频繁的。
已知阴影项集{2,3}是非频繁的。利用这个知识,我们就知道项集{0,2,3} ,{1,2,3}以及{0,1,2,3}也是非频繁的。这也就是说,一旦计算出了{2,3}的支持度,知道它是非频繁的之后,就不需要再计算{0,2,3}、{1,2,3}和{0,1,2,3}的支持度,因为我们知道这些集合不会满足我们的要求。使用该原理就可以避免项集数目的指数增长,从而在合理时间内计算出频繁项集。
#构建数据集
def loadDataSet():return [[1 ,3 ,4] ,[2 ,3 ,5] ,[1 ,2 ,3 ,5] ,[2 ,5]]def createC1(dataSet): #1项集'''构建初始候选项集的列表,即所有候选项集只包含一个元素,C1是大小为1的所有候选项集的集合'''C1 = []for transaction in dataSet:for item in transaction:if not [item] in C1:C1.append([item])C1.sort() #排序return list(map(frozenset ,C1))
#扫描模块
def scanD(D ,CK ,minSupport):'''计算Ck中的项集在数据集合D(记录或者transactions)中的支持度,返回满足最小支持度的项集的集合,和所有项集支持度信息的字典。'''ssCnt = {} #字典for tid in D:# 对于每一条transactionfor can in CK:# 对于每一个候选项集can,检查是否是transaction的一部分# 即该候选can是否得到transaction的支持if can.issubset(tid): #是否为子集if not can in ssCnt:ssCnt[can] = 1else:ssCnt[can] += 1numItems = float(len(list(D)))retlist = []supportData = {}for key in ssCnt:# 每个项集的支持度support = ssCnt[key ] /numItemsif support >= minSupport:# 将满足最小支持度的项集,加入retListretlist.insert(0 ,key)# 汇总支持度数据supportData[key] = supportreturn retlist ,supportData
if __name__ == '__main__':# 导入数据集myDat = loadDataSet()# 构建第一个候选项集列表C1C1 = createC1(myDat)# 构建集合表示的数据集 DD = map(set, myDat)# 选择出支持度不小于0.5 的项集作为频繁项集L, suppData = scanD(D, C1, 0.5)print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
可以看出,只有支持度不小于 0.5 的项集被选中到 L 中作为频繁项集,根据不同的需求,我们可以设定最小支持度的值,从而得到我们想要的频繁项集。
上面的示例只是选择出来了项集中只包含一个元素的频繁项集,下面需要整合上面的代码,选择出包含 2个,3个直至个数据等于所有候选元素个数的频繁项集。
# Aprior算法
def aprioriGen( Lk, k ):'''由初始候选项集的集合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:retList.append( Lk[ i ] | Lk[ j ] ) return retListdef apriori( dataSet, minSupport = 0.5 ):# 构建初始候选项集C1C1 = createC1( dataSet )# 将dataSet集合化,以满足scanD的格式要求D = map( set, dataSet )# 构建初始的频繁项集,即所有项集只有一个元素L1, suppData = scanD( D, C1, minSupport )L = [ L1 ]# 最初的L1中的每个项集含有一个元素,新生成的# 项集应该含有2个元素,所以 k=2k = 2while ( len( L[ k - 2 ] ) > 0 ):Ck = aprioriGen( L[ k - 2 ], k )Lk, supK = scanD( D, Ck, minSupport )# 将新的项集的支持度数据加入原来的总支持度字典中suppData.update( supK )# 将符合最小支持度要求的项集加入LL.append( Lk )# 新生成的项集中的元素个数应不断增加k += 1# 返回所有满足条件的频繁项集的列表,和所有候选项集的支持度信息return L, suppData
最小支持度为 0.5 时
if __name__ == '__main__':# 导入数据集myDat = loadDataSet() # 选择频繁项集L, suppData = apriori( myDat, 0.5 )print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
最小支持度为 0.7 时:
if __name__ == '__main__':# 导入数据集myDat = loadDataSet()# 选择频繁项集L, suppData = apriori( myDat, 0.7 )print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
频繁项集相比最小支持度 0.5 时要少,符合预期。
从频繁集中挖掘关联规则
# 规则生成与评价
def calcConf( freqSet, H, supportData, brl, minConf=0.7 ):'''计算规则的可信度,返回满足最小可信度的规则。freqSet(frozenset):频繁项集H(frozenset):频繁项集中所有的元素supportData(dic):频繁项集中所有元素的支持度brl(tuple):满足可信度条件的关联规则minConf(float):最小可信度'''prunedH = []for conseq in H:conf = supportData[ freqSet ] / supportData[ freqSet - conseq ]if conf >= minConf:print freqSet - conseq, '-->', conseq, 'conf:', confbrl.append( ( freqSet - conseq, conseq, conf ) )prunedH.append( conseq )return prunedHdef rulesFromConseq( freqSet, H, supportData, brl, minConf=0.7 ):'''对频繁项集中元素超过2的项集进行合并。freqSet(frozenset):频繁项集H(frozenset):频繁项集中的所有元素,即可以出现在规则右部的元素supportData(dict):所有项集的支持度信息brl(tuple):生成的规则'''m = len( H[ 0 ] )# 查看频繁项集是否大到移除大小为 m 的子集if len( freqSet ) > m + 1:Hmp1 = aprioriGen( H, m + 1 )Hmp1 = calcConf( freqSet, Hmp1, supportData, brl, minConf )# 如果不止一条规则满足要求,进一步递归合并if len( Hmp1 ) > 1:rulesFromConseq( freqSet, Hmp1, supportData, brl, minConf )def generateRules( L, supportData, minConf=0.7 ):'''根据频繁项集和最小可信度生成规则。L(list):存储频繁项集supportData(dict):存储着所有项集(不仅仅是频繁项集)的支持度minConf(float):最小可信度'''bigRuleList = []for i in range( 1, len( L ) ):for freqSet in L[ i ]:# 对于每一个频繁项集的集合freqSetH1 = [ frozenset( [ item ] ) for item in freqSet ]# 如果频繁项集中的元素个数大于2,需要进一步合并if i > 1:rulesFromConseq( freqSet, H1, supportData, bigRuleList, minConf )else:calcConf( freqSet, H1, supportData, bigRuleList, minConf )return bigRuleList
if __name__ == '__main__':# 导入数据集myDat = loadDataSet() # 选择频繁项集L, suppData = apriori( myDat, 0.5 )rules = generateRules( L, suppData, minConf=0.7 )print 'rules:\n', rules
将可信度降为 0.5 之后:
一旦降低置信度阈值,就可以获得更多的规则。
机器学习——关联规则
机器学习——关联规则
- (一)关联规则原理
- (二)关联规则代码实现
(一)关联规则原理
在美国,一些年轻的父亲下班后经常要到超市去买婴儿尿布,超市也因此发现了一个规律,在购买婴儿尿布的年轻父亲们中,有30%~40%的人同时要买一些啤酒。超市随后调整了货架的摆放,把尿布和啤酒放在一起,明显增加了销售额。
若两个或多个变量的取值之间存在某种规律性,就称为关联。
关联规则是寻找在同一个事件中出现的不同项的相关性,比如在一次购买活动中所买不同商品的相关性。
编号 | 牛奶 | 果冻 | 啤酒 | 面包 | 花生酱 |
---|---|---|---|---|---|
T1 | 1 | 1 | 0 | 0 | 1 |
T2 | 0 | 1 | 0 | 1 | 0 |
T3 | 0 | 1 | 1 | 0 | 0 |
T4 | 1 | 1 | 0 | 1 | 0 |
T5 | 1 | 0 | 1 | 0 | 0 |
T6 | 0 | 1 | 1 | 0 | 0 |
T7 | 1 | 0 | 1 | 0 | 0 |
T8 | 1 | 1 | 1 | 0 | 1 |
T9 | 1 | 1 | 1 | 0 | 0 |
一个样本称为一个事物
每个事务由多个属性来确定,这里的属性称为“项”
多个项组成的集合称为“项集”
由k个项构成的集合
{牛奶}、{啤酒}都是1-项集;
{牛奶,果冻}是2-项集;
{啤酒,面包,牛奶}是3-项集
X==>Y含义:
X和Y是项集
X称为规则前项(antecedent)
Y称为规则后项(consequent)
事务仅包含其涉及到的项目,而不包含项目的具体信息。
在超级市场的关联规则挖掘问题中事务是顾客一次购物所购买的商品,但事务中并不包含这些商品的具体信息,如商品的数量、价格等。
支持度(support):一个项集或者规则在所有事务中出现的频率,σ(X):表示项集X的支持度计数
- 项集X的支持度:s(X)=σ(X)/N。
- 规则X==>Y表示物品集X对物品集Y的支持度,也就是物品集X和物品集Y同时出现的概率。
- 某天共有100个顾客到商场购买物品,其中有30个顾客同时购买了啤酒和尿布,那么上述的关联规则的支持度就是30%。
置信度(confidence):确定Y在包含X的事务中出现的频繁程度。
c ( X → Y ) = σ ( X ∪ Y ) / σ ( X ) c(X\rightarrow Y)=\sigma (X\cup Y)/\sigma (X) c(X→Y)=σ(X∪Y)/σ(X)
- p ( Y ∣ X ) = p ( X Y ) / p ( X ) p(Y|X)=p(XY)/p(X) p(Y∣X)=p(XY)/p(X)
- 置信度反应了关联规则的可信度—购买了项目集X中的商品的顾客同时也购买了Y中商品的可能性有多大
- 购买薯片的顾客中有50%的人购买了可乐,则置信度为50%。
举例:
交易ID | 购买的商品 |
---|---|
1 | A,B,C |
2 | A,C |
3 | A,D |
4 | B,E,F |
(X,Y)==>Z
- 支持度:交易中包含{X 、 Y 、 Z}的可能性。
- 置信度:包含{X 、 Y}的交易中也包含Z的条件概率
设最小支持度为50%, 最小可信度为 50%, 则可得到 :
- A==>C (50%, 66.6%)
- C==>A (50%, 100%)
若关联规则X->Y的支持度和置信度分别大于或等于用户指定的最小支持率minsupport和最小置信度minconfidence,则称关联规则X->Y为强关联规则,否则称关联规则X->Y为弱关联规则。
提升度(lift):物品集A的出现对物品集B的出现概率发生了多大的变化。
- l i f t ( A = = > B ) = c o n f i d e n c e ( A = = > B ) / s u p p o r t ( B ) = p ( B ∣ A ) / p ( B ) lift(A==>B)=confidence(A==>B)/support(B)=p(B|A)/p(B) lift(A==>B)=confidence(A==>B)/support(B)=p(B∣A)/p(B)
- 现在有1000 个消费者,有500 人购买了茶叶,其中有450人同时 购买了咖啡,另50人 没有。由于confidence(茶叶=>咖啡)=450/500=90% ,由此可能会认为喜欢喝茶的人往往喜欢喝咖啡。但如果另外没有购买茶叶的500人 ,其中同样有450人 购买了咖啡,同样是很高的置信度90% ,由此,得到不爱喝茶的也爱喝咖啡。这样看来,其实是否购买咖啡,与有没有购买茶叶并没有关联,两者是相互独立的,其提升度90%/[(450+450)/1000]=1 。
由此可见,lift正是弥补了confidence的这一缺陷,if lift=1,X与Y独立,X对Y出现的可能性没有提升作用,其值越大(lift>1),则表明X对Y的提升程度越大,也表明关联性越强。
X | 1 | 1 | 1 | 1 | 0 | 0 | 0 | 0 |
---|---|---|---|---|---|---|---|---|
Y | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
Z | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
rule | Support | Lift |
---|---|---|
X=>Y | 25% | 2.00 |
X=>Z | 37.50% | 0.86 |
Y=>Z | 12.50% | 0.57 |
Leverage 与 Conviction的作用和lift类似,都是值越大代表越关联。
Leverage: P ( A , B ) − P ( A ) P ( B ) P(A,B)-P(A)P(B) P(A,B)−P(A)P(B)
Conviction: P ( A ) P ( ! B ) / P ( A , ! B ) P(A)P(!B)/P(A,!B) P(A)P(!B)/P(A,!B)
使用mlxtend工具包得出频繁项集与规则
import pandas as pd
from mlxtend.frequent_patterns import apriori
from mlxtend.frequent_patterns import association_rules
自定义一份购物数据集
data = {'ID':[1,2,3,4,5,6],'Onion':[1,0,0,1,1,1],'Potato':[1,1,0,1,1,1],'Burger':[1,1,0,0,1,1],'Milk':[0,1,1,1,0,1],'Beer':[0,0,1,0,1,0]}
df = pd.DataFrame(data)
df = df[['ID', 'Onion', 'Potato', 'Burger', 'Milk', 'Beer' ]]
df
设置支持度 (support) 来选择频繁项集。选择最小支持度为50%
apriori(df, min_support=0.5, use_colnames=True)
frequent_itemsets = apriori(df[['Onion', 'Potato', 'Burger', 'Milk', 'Beer' ]], min_support=0.50, use_colnames=True)
frequent_itemsets
返回的3种项集均是支持度>=50%
计算规则
association_rules(df, metric=‘lift’, min_threshold=1)
可以指定不同的衡量标准与最小阈值
rules = association_rules(frequent_itemsets, metric='lift', min_threshold=1)
rules
返回的是各个的指标的数值。
rules [ (rules['lift'] >1.125) & (rules['confidence']> 0.8) ]
发现:
- (洋葱和马铃薯)(汉堡和马铃薯)提升度和置信度都比较高,可以搭配着来卖。
- 如果洋葱和汉堡都在购物篮中, 顾客买马铃薯的可能性也比较高,如果他篮子里面没有,可以推荐一下.
数据需转换成one-hot编码
#创建一个购物篮数据集
retail_shopping_basket = {'ID':[1,2,3,4,5,6],'Basket':[['Beer', 'Diaper', 'Pretzels', 'Chips', 'Aspirin'],['Diaper', 'Beer', 'Chips', 'Lotion', 'Juice', 'BabyFood', 'Milk'],['Soda', 'Chips', 'Milk'],['Soup', 'Beer', 'Diaper', 'Milk', 'IceCream'],['Soda', 'Coffee', 'Milk', 'Bread'],['Beer', 'Chips']]}
retail = pd.DataFrame(retail_shopping_basket)
retail = retail[['ID', 'Basket']]
pd.options.display.max_colwidth=100
retail
数据集中都是字符串组成的,需要转换成数值编码。
retail_id = retail.drop('Basket' ,1)
retail_id
retail_Basket = retail.Basket.str.join(',')
retail_Basket
retail_Basket = retail_Basket.str.get_dummies(',')
retail_Basket
retail = retail_id.join(retail_Basket)
retail
frequent_itemsets_2 = apriori(retail.drop('ID',1), use_colnames=True)
frequent_itemsets_2
如果只考虑支持度support(X>Y), [Beer, Chips] 和 [Beer, Diaper] 都是很频繁的,哪一种组合更相关呢?
association_rules(frequent_itemsets_2, metric='lift')
显然{Diaper, Beer}更相关一些。
电影题材关联
movies = pd.read_csv('ml-latest-small/movies.csv')
movies.head(10)
数据中包括电影名字与电影类型的标签,第一步还是先转换成one-hot格式。
movies_ohe = movies.drop('genres',1).join(movies.genres.str.get_dummies())
pd.options.display.max_columns=100
movies_ohe.head()
movies_ohe.shape
(9125, 22)
数据集包括9125部电影,一共有20种不同类型。
movies_ohe.set_index(['movieId','title'],inplace=True)
movies_ohe.head()
frequent_itemsets_movies = apriori(movies_ohe,use_colnames=True, min_support=0.025) #设置最小支持度0.025
frequent_itemsets_movies
rules_movies = association_rules(frequent_itemsets_movies, metric='lift', min_threshold=1.25) #设置最小提升度1.25
rules_movies
rules_movies[(rules_movies.lift>4)].sort_values(by=['lift'], ascending=False)
Children和Animation 这俩题材是最相关的了,常识也可以分辨出来。
movies[(movies.genres.str.contains('Children')) & (~movies.genres.str.contains('Animation'))]
具体分析还得落实到数据本身,这就需要充分理解数据才可以。
(二)关联规则代码实现
使用Apriori算法来发现频繁集:
Apriori原理可以帮我们减少可能感兴趣的项集。Apriori原理是说如果某个项集是频繁的,那么它的所有子集也是频繁的。根据上图给出的例子,这意味着如果{0,1}是频繁的,那么{0}、{1}也一定是频繁的。这个原理直观上并没有什么帮助,但是如果反过来看就有用了,也就是说如果一个项集是非频繁集,那么它的所有超集也是非频繁的。
已知阴影项集{2,3}是非频繁的。利用这个知识,我们就知道项集{0,2,3} ,{1,2,3}以及{0,1,2,3}也是非频繁的。这也就是说,一旦计算出了{2,3}的支持度,知道它是非频繁的之后,就不需要再计算{0,2,3}、{1,2,3}和{0,1,2,3}的支持度,因为我们知道这些集合不会满足我们的要求。使用该原理就可以避免项集数目的指数增长,从而在合理时间内计算出频繁项集。
#构建数据集
def loadDataSet():return [[1 ,3 ,4] ,[2 ,3 ,5] ,[1 ,2 ,3 ,5] ,[2 ,5]]def createC1(dataSet): #1项集'''构建初始候选项集的列表,即所有候选项集只包含一个元素,C1是大小为1的所有候选项集的集合'''C1 = []for transaction in dataSet:for item in transaction:if not [item] in C1:C1.append([item])C1.sort() #排序return list(map(frozenset ,C1))
#扫描模块
def scanD(D ,CK ,minSupport):'''计算Ck中的项集在数据集合D(记录或者transactions)中的支持度,返回满足最小支持度的项集的集合,和所有项集支持度信息的字典。'''ssCnt = {} #字典for tid in D:# 对于每一条transactionfor can in CK:# 对于每一个候选项集can,检查是否是transaction的一部分# 即该候选can是否得到transaction的支持if can.issubset(tid): #是否为子集if not can in ssCnt:ssCnt[can] = 1else:ssCnt[can] += 1numItems = float(len(list(D)))retlist = []supportData = {}for key in ssCnt:# 每个项集的支持度support = ssCnt[key ] /numItemsif support >= minSupport:# 将满足最小支持度的项集,加入retListretlist.insert(0 ,key)# 汇总支持度数据supportData[key] = supportreturn retlist ,supportData
if __name__ == '__main__':# 导入数据集myDat = loadDataSet()# 构建第一个候选项集列表C1C1 = createC1(myDat)# 构建集合表示的数据集 DD = map(set, myDat)# 选择出支持度不小于0.5 的项集作为频繁项集L, suppData = scanD(D, C1, 0.5)print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
可以看出,只有支持度不小于 0.5 的项集被选中到 L 中作为频繁项集,根据不同的需求,我们可以设定最小支持度的值,从而得到我们想要的频繁项集。
上面的示例只是选择出来了项集中只包含一个元素的频繁项集,下面需要整合上面的代码,选择出包含 2个,3个直至个数据等于所有候选元素个数的频繁项集。
# Aprior算法
def aprioriGen( Lk, k ):'''由初始候选项集的集合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:retList.append( Lk[ i ] | Lk[ j ] ) return retListdef apriori( dataSet, minSupport = 0.5 ):# 构建初始候选项集C1C1 = createC1( dataSet )# 将dataSet集合化,以满足scanD的格式要求D = map( set, dataSet )# 构建初始的频繁项集,即所有项集只有一个元素L1, suppData = scanD( D, C1, minSupport )L = [ L1 ]# 最初的L1中的每个项集含有一个元素,新生成的# 项集应该含有2个元素,所以 k=2k = 2while ( len( L[ k - 2 ] ) > 0 ):Ck = aprioriGen( L[ k - 2 ], k )Lk, supK = scanD( D, Ck, minSupport )# 将新的项集的支持度数据加入原来的总支持度字典中suppData.update( supK )# 将符合最小支持度要求的项集加入LL.append( Lk )# 新生成的项集中的元素个数应不断增加k += 1# 返回所有满足条件的频繁项集的列表,和所有候选项集的支持度信息return L, suppData
最小支持度为 0.5 时
if __name__ == '__main__':# 导入数据集myDat = loadDataSet() # 选择频繁项集L, suppData = apriori( myDat, 0.5 )print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
最小支持度为 0.7 时:
if __name__ == '__main__':# 导入数据集myDat = loadDataSet()# 选择频繁项集L, suppData = apriori( myDat, 0.7 )print u"频繁项集L:", Lprint u"所有候选项集的支持度信息:", suppData
频繁项集相比最小支持度 0.5 时要少,符合预期。
从频繁集中挖掘关联规则
# 规则生成与评价
def calcConf( freqSet, H, supportData, brl, minConf=0.7 ):'''计算规则的可信度,返回满足最小可信度的规则。freqSet(frozenset):频繁项集H(frozenset):频繁项集中所有的元素supportData(dic):频繁项集中所有元素的支持度brl(tuple):满足可信度条件的关联规则minConf(float):最小可信度'''prunedH = []for conseq in H:conf = supportData[ freqSet ] / supportData[ freqSet - conseq ]if conf >= minConf:print freqSet - conseq, '-->', conseq, 'conf:', confbrl.append( ( freqSet - conseq, conseq, conf ) )prunedH.append( conseq )return prunedHdef rulesFromConseq( freqSet, H, supportData, brl, minConf=0.7 ):'''对频繁项集中元素超过2的项集进行合并。freqSet(frozenset):频繁项集H(frozenset):频繁项集中的所有元素,即可以出现在规则右部的元素supportData(dict):所有项集的支持度信息brl(tuple):生成的规则'''m = len( H[ 0 ] )# 查看频繁项集是否大到移除大小为 m 的子集if len( freqSet ) > m + 1:Hmp1 = aprioriGen( H, m + 1 )Hmp1 = calcConf( freqSet, Hmp1, supportData, brl, minConf )# 如果不止一条规则满足要求,进一步递归合并if len( Hmp1 ) > 1:rulesFromConseq( freqSet, Hmp1, supportData, brl, minConf )def generateRules( L, supportData, minConf=0.7 ):'''根据频繁项集和最小可信度生成规则。L(list):存储频繁项集supportData(dict):存储着所有项集(不仅仅是频繁项集)的支持度minConf(float):最小可信度'''bigRuleList = []for i in range( 1, len( L ) ):for freqSet in L[ i ]:# 对于每一个频繁项集的集合freqSetH1 = [ frozenset( [ item ] ) for item in freqSet ]# 如果频繁项集中的元素个数大于2,需要进一步合并if i > 1:rulesFromConseq( freqSet, H1, supportData, bigRuleList, minConf )else:calcConf( freqSet, H1, supportData, bigRuleList, minConf )return bigRuleList
if __name__ == '__main__':# 导入数据集myDat = loadDataSet() # 选择频繁项集L, suppData = apriori( myDat, 0.5 )rules = generateRules( L, suppData, minConf=0.7 )print 'rules:\n', rules
将可信度降为 0.5 之后:
一旦降低置信度阈值,就可以获得更多的规则。