关联规则算法在游戏行业中的应用
本文为学习《R语言游戏数据分析与挖掘》学习笔记。
Apriori算法应用广泛,可用于消费市场价格分析,猜测顾客的消费习惯,比如较有名的“尿布和啤酒”的故事。其核心思想是通过连接产生候选项及其支持度,然后通过剪枝生成频繁项集,这里的频繁项集是指所有支持度大于等于给定最小支持度的项集。
项集:在关联分析中,包含0个或多个项的集合被称为项集(itemset)。如果一个项集包含k个项,则称它为k-项集。例如:{新手礼包,8条钥匙,10000金币,十个滑板} 是一个4-项集。空集是指不包含任何项的项集。
现有数据集如下:
其中:player_id是指用户ID,product_name是指商品名称,qty是指购买数量。
①导入数据:
data <- read.csv("C:/Mathmodel/Ryuyan/GameR/data/第9章/玩家购物数据.csv",T,fileEncoding="utf8")
# 利用cast函数对数据进行重组
library(reshape)
data_matrix <- cast(data,player_id~product_name,value = "qty")
# 查看前三行五列数据
data_matrix[1:5,1:6]
结果如下:
> data_matrix[1:5,1:6]
player_id 0.1元大礼包 10块滑板 15000金币 15元大礼包 1条钥匙
1 107204535 NA NA NA NA NA
2 213666611 NA NA NA NA NA
3 226500629 1 NA NA NA NA
4 230329140 NA NA NA NA NA
5 264162836 NA NA NA NA NA
②可发现,未购买某种道具记为NA。应当将NA转化为0,其余的转换为1.
# 进行替换,将NA转化为0,其他数字为1
data_matrix_new <- apply(data_matrix[,-1],2,function(x) {ifelse(is.na(x),0,1)})
# 对矩阵行名称、列名称进行赋值
data_matrix_new <- matrix(data_matrix_new,nrow=dim(data_matrix_new)[1],
ncol=dim(data_matrix_new)[2],
dimnames = list(data_matrix[,1],colnames(data_matrix)[-1]))
# 查看前三行五列数据
data_matrix_new[1:5,1:6]
结果如下:
> data_matrix_new[1:5,1:6]
0.1元大礼包 10块滑板 15000金币 15元大礼包 1条钥匙 20条钥匙
107204535 0 0 0 0 0 0
213666611 0 0 0 0 0 0
226500629 1 0 0 0 0 0
230329140 0 0 0 0 0 0
264162836 0 0 0 0 0 0
③再利用as函数将矩阵转换为事务型。
library(arules)
data_class <- as(data_matrix_new,"transactions")
inspect(data_class[1:6]) # 查看前六条交易记录
summary(data_class) # 查看汇总信息
结果如下:
#这部分是将每个用户交易情况作为项集。
> inspect(data_class[1:6]) # 查看前六条交易记录
items transactionID
[1] {感恩大礼包,新手礼包} 107204535
[2] {8条钥匙} 213666611
[3] {0.1元大礼包,8条钥匙,限量版角色} 226500629
[4] {38000金币,限量版角色,新手礼包} 230329140
[5] {50条钥匙} 264162836
[6] {15000金币,70000金币,快速复活} 278620434
> summary(data_class) # 查看汇总信息
#第一部分
transactions as itemMatrix in sparse format with
6252 rows (elements/itemsets/transactions) and
26 columns (items) and a density of 0.05526847
#第二部分
most frequent items:
8条钥匙 15000金币 0.1元大礼包 限量版角色 50条钥匙 (Other)
2171 1161 796 732 634 3490
#第三部分
element (itemset/transaction) length distribution:
sizes
1 2 3 4 5 6 7 8 9
4510 1126 392 132 60 17 7 5 3
Min. 1st Qu. Median Mean 3rd Qu. Max.
1.000 1.000 1.000 1.437 2.000 9.000
#第四部分
includes extended item information - examples:
labels
1 0.1元大礼包
2 10块滑板
3 15000金币
#第五部分
includes extended transaction information - examples:
transactionID
1 107204535
2 213666611
3 226500629
summary部分解释:
第一部分: 共有6252条交易记录transaction,26个商品item,密度(density)值0.05526847(5.5%)是指非零矩阵单元的比例。
第二部分: 最频繁出现的商品item及其出现的次数。例如,8条钥匙出现了2171次,说明在6252次交易中有2171次交易包含了8条钥匙。
第三部分: 每笔交易包含的商品数目及其对应的5个分位数和均值的统计信息。例如,有4510位用户只购买了一个商品,仅有3位用户购买了9件商品。第三四分位数(3rd U.)为2,意味着75%的用户购买的商品item数不超过2个。
第四,五部分: 包含labels(item 名字)和 transactionID(玩家 ID)。
利用itemFrequency()函数计算各个项集的出现频率(支持度)。例如,可通过itemFrequency[,1:3]命令查看data_class数据中前3件道具的支持率,也可以直接给定道具名称查看支持度。
④itemFrequency函数计算各个项集的出现频率(支持度)
# itemFrequency函数计算各个项集的出现频率(支持度)
itemFrequency(data_class[,1:6]) # 查看前六件道具的支持度
itemFrequency(data_class[,c('8条钥匙','15000金币','0.1元大礼包')]) # 查看指定道具的支持度
结果如下:
> itemFrequency(data_class[,1:6]) # 查看前六件道具的支持度
0.1元大礼包 10块滑板 15000金币 15元大礼包 1条钥匙 20条钥匙
0.1273192578 0.0107165707 0.1857005758 0.0004798464 0.0118362124 0.0316698656
> itemFrequency(data_class[,c('8条钥匙','15000金币','0.1元大礼包')])
> # 查看指定道具的支持度
8条钥匙 15000金币 0.1元大礼包
0.3472489 0.1857006 0.1273193
可见,8条钥匙的出现频率(支持度)为0.3472489,在前面分析中已经知道8条钥匙出现的次数为2171,从而可以计算出8条钥匙的支持度为2171/6252=0.34724889,与用函数求出结果一致。
⑤绘制描述所包含的特定商品交易比例的柱状图。
par(mfrow=c(2,1))
# 输出支持度support大于0.05的项集的支持度频率图
itemFrequencyPlot(data_class,support=0.05,main="support大于0.05的项集支持度频率图")
# 输出支持度support最大的前20个项集的支持度频率图
itemFrequencyPlot(data_class,topN=20,main="support最大的前20个项集的支持度频率图")
par(mfrow=c(1,1))
⑥建立关联规则rules,设定最小支持度阈值为0.005,最小置信度阈值为0.1,每项集最小项目数为2,并通过summer函数查看规则的汇总信息。
# 建立关联规则rules
rules <- apriori(data_class,
parameter=list(support=0.005,confidence=0.1,target="rules",minlen=2))
summary(rules) # 查看规则汇总信息
结果如下:
> rules <- apriori(data_class,
+ parameter=list(support=0.005,confidence=0.1,target="rules",minlen=2))
Apriori
Parameter specification:
confidence minval smax arem aval originalSupport maxtime support minlen
0.1 0.1 1 none FALSE TRUE 5 0.005 2
maxlen target ext
10 rules TRUE
Algorithmic control:
filter tree heap memopt load sort verbose
0.1 TRUE TRUE FALSE TRUE 2 TRUE
Absolute minimum support count: 31
set item appearances ...[0 item(s)] done [0.00s].
set transactions ...[26 item(s), 6252 transaction(s)] done [0.00s].
sorting and recoding items ... [21 item(s)] done [0.00s].
creating transaction tree ... done [0.00s].
checking subsets of size 1 2 3 done [0.00s].
writing ... [48 rule(s)] done [0.00s].
creating S4 object ... done [0.00s].
> summary(rules) # 查看规则汇总信息
set of 48 rules
#第一部分
rule length distribution (lhs + rhs):sizes
2 3
42 6
Min. 1st Qu. Median Mean 3rd Qu. Max.
2.000 2.000 2.000 2.125 2.000 3.000
#第二部分
summary of quality measures:
support confidence coverage lift
Min. :0.005278 Min. :0.1034 Min. :0.01200 Min. : 0.3979
1st Qu.:0.007678 1st Qu.:0.1540 1st Qu.:0.03559 1st Qu.: 0.8391
Median :0.011916 Median :0.1764 Median :0.06142 Median : 1.3211
Mean :0.012939 Mean :0.2179 Mean :0.07304 Mean : 2.0827
3rd Qu.:0.016115 3rd Qu.:0.2363 3rd Qu.:0.09325 3rd Qu.: 2.2325
Max. :0.040787 Max. :0.9009 Max. :0.34725 Max. :13.1907
count
Min. : 33.0
1st Qu.: 48.0
Median : 74.5
Mean : 80.9
3rd Qu.:100.8
Max. :255.0
#第三部分
mining info:
data ntransactions support confidence
data_class 6252 0.005 0.1
第一部分:规则的长度分布(前项+后项)及其对应的5个分位数和均值的统计信息。len=2有42条规则,len=3有6条规则。
第二部分:支持度,置信度和提升度的描述统计信息。
第三部分:挖掘的相关信息。
⑦可以通过inspect函数查看关联规则,quality函数提取每条规则的支持度,置信度和提升度信息。
inspect(rules[1:6]) # 查看前六条规则
quality(rules[1:6]) # 提取前六条规则信息
# 对规则按照提升度排序,并输出提升度最大的前六条规则
inspect(sort(rules,by="lift")[1:6])
结果如下:
> inspect(rules[1:6]) # 查看前六条规则
lhs rhs support confidence coverage lift
[1] {超值大礼包} => {新手礼包} 0.015994882 0.9009009 0.01775432 13.190708
[2] {新手礼包} => {超值大礼包} 0.015994882 0.2341920 0.06829814 13.190708
[3] {3000金币} => {新手礼包} 0.007677543 0.2330097 0.03294946 3.411655
[4] {新手礼包} => {3000金币} 0.007677543 0.1124122 0.06829814 3.411655
[5] {3000金币} => {15000金币} 0.008957134 0.2718447 0.03294946 1.463887
[6] {38000金币} => {70000金币} 0.007517594 0.2061404 0.03646833 2.210617
count
[1] 100
[2] 100
[3] 48
[4] 48
[5] 56
[6] 47
> quality(rules[1:6]) # 提取前六条规则信息
support confidence coverage lift count
1 0.015994882 0.9009009 0.01775432 13.190708 100
2 0.015994882 0.2341920 0.06829814 13.190708 100
3 0.007677543 0.2330097 0.03294946 3.411655 48
4 0.007677543 0.1124122 0.06829814 3.411655 48
5 0.008957134 0.2718447 0.03294946 1.463887 56
6 0.007517594 0.2061404 0.03646833 2.210617 47
> # 对规则按照提升度排序,并输出提升度最大的前六条规则
> inspect(sort(rules,by="lift")[1:6])
lhs rhs support confidence coverage
[1] {超值大礼包} => {新手礼包} 0.015994882 0.9009009 0.01775432
[2] {新手礼包} => {超值大礼包} 0.015994882 0.2341920 0.06829814
[3] {双倍金币,限量版角色} => {解锁滑板} 0.005918106 0.3523810 0.01679463
[4] {解锁滑板,双倍金币} => {限量版角色} 0.005918106 0.4933333 0.01199616
[5] {解锁滑板,限量版角色} => {双倍金币} 0.005918106 0.3083333 0.01919386
[6] {3000金币} => {新手礼包} 0.007677543 0.2330097 0.03294946
lift count
[1] 13.190708 100
[2] 13.190708 100
[3] 5.737202 37
[4] 4.213552 37
[5] 3.524132 37
[6] 3.411655 48
可发现购买超值大礼包和新手礼包的支持度为0.0159,提升度为13.19.
由此说明APRIORI算法是不考虑物品购买先后顺序的。 如果需要考虑顺序因素,利用arulesSequences包中的cspade函数实现cSPADE算法。
⑧提取包含“超级大礼包”或“新手礼包”的规则。
# 提取规则
# 提取前项包含"超值大礼包"或"新手礼包"的规则
inspect(subset(rules,subset=lhs %in% c("超值大礼包","新手礼包")))
# 提取lhs包含"超值大礼包"或"新手礼包"的规则且lift大于1的规则
inspect(subset(rules,subset=lhs %in% c("超值大礼包","新手礼包") & lift>1))
结果如下:
> inspect(subset(rules,subset=lhs %in% c("超值大礼包","新手礼包")))
lhs rhs support confidence coverage lift
[1] {超值大礼包} => {新手礼包} 0.015994882 0.9009009 0.01775432 13.1907083
[2] {新手礼包} => {超值大礼包} 0.015994882 0.2341920 0.06829814 13.1907083
[3] {新手礼包} => {3000金币} 0.007677543 0.1124122 0.06829814 3.4116550
[4] {新手礼包} => {0.1元大礼包} 0.010396673 0.1522248 0.06829814 1.1956151
[5] {新手礼包} => {15000金币} 0.010556622 0.1545667 0.06829814 0.8323439
[6] {新手礼包} => {8条钥匙} 0.009436980 0.1381733 0.06829814 0.3979086
count
[1] 100
[2] 100
[3] 48
[4] 65
[5] 66
[6] 59
> # 提取lhs包含"超值大礼包"或"新手礼包"的规则且lift大于1的规则
> inspect(subset(rules,subset=lhs %in% c("超值大礼包","新手礼包") & lift>1))
lhs rhs support confidence coverage lift
[1] {超值大礼包} => {新手礼包} 0.015994882 0.9009009 0.01775432 13.190708
[2] {新手礼包} => {超值大礼包} 0.015994882 0.2341920 0.06829814 13.190708
[3] {新手礼包} => {3000金币} 0.007677543 0.1124122 0.06829814 3.411655
[4] {新手礼包} => {0.1元大礼包} 0.010396673 0.1522248 0.06829814 1.195615
count
[1] 100
[2] 100
[3] 48
[4] 65
⑨可视化
利用rulesViz包中的plot()函数对关联规则进行可视化。 例如,相对提升度大于2 的规则绘制关联图形(method=“graph”)。
# 对关联规则进行可视化
rules_lift <- subset(rules,subset=lift>2)
library(arulesViz)
#绘制关联图形
plot(rules_lift,method="graph",
control = list(nodeCol = grey.colors(10),
edgeCol = grey(.7), alpha = 1))
图中圆圈代表 规则的支持度(0.006~0.019),圆圈越大表示支持度越大。圆圈的颜色深浅代表 规则的提升度 (2.211~13.191),颜色从灰色到黑色表示提升度由小到大。
支持度: 一个项集或者规则在所有事物中出现的频率,确定规则可以用于给定数据集的频繁程度。σ(X):表示项集X的支持度计数项集X的支持度:s(X)=σ(X)/N;规则X → Y的支持度:s(X → Y) = σ(X∪Y) / N
置信度:
确定Y在包含X的事务中出现的频繁程度。c(X → Y) = σ(X∪Y)/σ(X)
通俗解释:简单地说,可信度就是指在出现了物品集X 的事务T 中,物品集Y 也同时出现的概率有多大。
概率描述:物品集X对物品集Y的置信度confidence(X==>Y)=P(X|Y)
实例说明:上该关联规则的可信度就回答了这样一个问题:如果一个顾客购买了10000金币,那么他也购买50个滑板的可能性有多大呢?在上述例子中,购买10000金币的顾客中有65%的人购买了50个滑板, 所以可信度是50%。
期望置信度(Expected confidence)
定义:设W 中有e %的事务支持物品集B,e %称为关联规则A→B 的期望可信度度。
通俗解释:期望可信度描述了在没有任何条件影响时,物品集B 在所有事务中出现的概率有多大。
实例说明:如果某天共有1000 个用户到购买物品,其中有250 个顾客购买了10000个金币,则上述的关联规则的期望可信度就是25 %。
概率描述:物品集A对物品集B的期望置信度为support(B)=P(B)
提升度(lift)
定义:提升度是可信度与期望可信度的比值
通俗解释:提升度反映了“物品集A的出现”对物品集B的出现概率发生了多大的变化。
实例说明:上述的关联规则的提升度=65%/25%=2.6
概率描述:物品集A对物品集B的期望置信度为lift(A==>B)=confidence(A==>B)/support(B)=p(B|A)/p(B)
提升度判断: 如果lift=1 ,说明两个事项没有任何关联 ;如果lift<1 ,说明A事件的发生与B事件是相斥 的。一般在数据挖掘中当提升度大于3 时,我们才承认挖掘出的关联规则是有价值的 。
总结:
支持度:就是概率(一项就是其出现的概率,多项就是其同时出现的概率)
置信度:条件概率(A出现后,B也出现的概率)
总之,可信度是对关联规则的准确度的衡量,支持度是对关联规则重要性的衡量。支持度说明了这条规则在所有事务中有多大的代表性,显然支持度越大,关联规则越重要。
有些关联规则可信度虽然很高,但支持度却很低,说明该关联规则实用的机会很小,因此也不重要。
将method设置为"grouped",可以绘制分组矩阵。
#绘制分组矩阵
plot(rules_lift,method = "grouped",
control = list(col = grey.colors(10)))
# 将规则导出到本地
write(rules,"rules.txt",sep="|",row.names=F)
圆圈表示支持度,圆圈越大表示支持度越大,颜色代表提升度,颜色由灰到黑色表示提升度由小到大。
上面是LHS(前项),是道具名称和规则数目;右边是RHS(后项),是道具名称。
导出数据可得到:
"rules"|"support"|"confidence"|"coverage"|"lift"|"count"
"{超值大礼包} => {新手礼包}"|0.0159948816378759|0.900900900900901|0.0177543186180422|13.1907082726755|100
"{新手礼包} => {超值大礼包}"|0.0159948816378759|0.234192037470726|0.06829814459373|13.1907082726755|100
"{3000金币} => {新手礼包}"|0.00767754318618042|0.233009708737864|0.0329494561740243|3.4116550328551|48
"{新手礼包} => {3000金币}"|0.00767754318618042|0.112412177985948|0.06829814459373|3.4116550328551|48
"{3000金币} => {15000金币}"|0.00895713371721049|0.271844660194175|0.0329494561740243|1.46388700735054|56
"{38000金币} => {70000金币}"|0.00751759436980166|0.206140350877193|0.036468330134357|2.21061659294033|47
"{38000金币} => {50条钥匙}"|0.00639795265515035|0.175438596491228|0.036468330134357|1.73003486634568|40
"{38000金币} => {15000金币}"|0.00847728726807422|0.232456140350877|0.036468330134357|1.25177931909878|53
"{38000金币} => {8条钥匙}"|0.00639795265515035|0.175438596491228|0.036468330134357|0.505224369075614|40
"{20条钥匙} => {70000金币}"|0.00527831094049904|0.166666666666667|0.0316698656429942|1.78730703259005|33
"{20条钥匙} => {50条钥匙}"|0.00831733845169546|0.262626262626263|0.0316698656429942|2.5898097696205|52
"{20条钥匙} => {15000金币}"|0.00767754318618042|0.242424242424242|0.0316698656429942|1.3054576775507|48
"{20条钥匙} => {8条钥匙}"|0.0140754958413308|0.444444444444444|0.0316698656429942|1.27990173499156|88
"{特殊滑板} => {双倍金币}"|0.00735764555342291|0.150326797385621|0.0489443378119002|1.71817758181883|46
"{特殊滑板} => {限量版角色}"|0.0127959053103007|0.261437908496732|0.0489443378119002|2.23293689060324|80
"{限量版角色} => {特殊滑板}"|0.0127959053103007|0.109289617486339|0.117082533589251|2.23293689060324|80
"{特殊滑板} => {15000金币}"|0.00767754318618042|0.156862745098039|0.0489443378119002|0.844707909003395|48
"{特殊滑板} => {8条钥匙}"|0.00975687779910429|0.199346405228758|0.0489443378119002|0.574073572312389|61
"{解锁滑板} => {双倍金币}"|0.0119961612284069|0.1953125|0.0614203454894434|2.23234689213894|75
"{双倍金币} => {解锁滑板}"|0.0119961612284069|0.137111517367459|0.0874920025591811|2.23234689213894|75