昨天讲解了关联规则挖掘的原理。关联规则挖掘在生活中有很多使用场景,不仅是商品的捆绑销售,甚至在挑选演员决策上,你也能通过关联规则挖掘看出来某个导演选择演员的倾向。今天我来带你用 Apriori 算法做一个项目实战。
你需要掌握的是以下几点:
- 熟悉上节课讲到的几个重要概念:支持度、置信度和提升度;
- 熟悉与掌握 Apriori 工具包的使用;
- 在实际问题中,灵活运用。包括数据集的准备等。
如何使用 Apriori
Apriori 虽然是十大算法之一,不过在 sklearn 工具包中并没有它,也没有 FP-Growth 算法。这里教你个方法,来选择 Python 中可以使用的工具包,你可以通过https://pypi.org/ 搜索工具包。
这个网站提供的工具包都是 Python 语言的,你能找到 8 个 Python 语言的 Apriori 工具包,具体选择哪个呢?建议你使用第二个工具包,即 efficient-apriori。后面我会讲到为什么推荐这个工具包。
首先你需要通过 pip install efficient-apriori 安装这个工具包。然后看下如何使用它,核心的代码就是这一行:
1
| itemsets, rules = apriori(data, min_support, min_confidence)
|
其中 data 是我们要提供的数据集,它是一个 list 数组类型。min_support 参数为最小支持度,在 efficient-apriori 工具包中用 0 到 1 的数值代表百分比,比如 0.5 代表最小支持度为 50%。min_confidence 是最小置信度,数值也代表百分比,比如 1 代表 100%。
一般来说最小支持度常见的取值有0.5,0.1, 0.05。最小置信度常见的取值有1.0, 0.9, 0.8。可以通过尝试一些取值,然后观察关联结果的方式来调整最小值尺度和最小置信度的取值。
关于支持度、置信度和提升度,我们再来简单回忆下。
支持度指的是某个商品组合出现的次数与总次数之间的比例。支持度越高,代表这个组合出现的概率越大。
置信度是一个条件概念,就是在 A 发生的情况下,B 发生的概率是多少。
提升度代表的是“商品 A 的出现,对商品 B 的出现概率提升了多少”。
接下来我们用这个工具包,跑一下上节课中讲到的超市购物的例子。下面是客户购买的商品列表:
具体实现的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12
| from efficient_apriori import apriori
data = [('牛奶','面包','尿布'), ('可乐','面包', '尿布', '啤酒'), ('牛奶','尿布', '啤酒', '鸡蛋'), ('面包', '牛奶', '尿布', '啤酒'), ('面包', '牛奶', '尿布', '可乐')]
itemsets, rules = apriori(data, min_support=0.5, min_confidence=1) print(itemsets) print(rules)
|
结果:
1 2 3 4
| {1: {('啤酒',): 3, ('尿布',): 5, ('牛奶',): 4, ('面包',): 4}, 2: {('啤酒', '尿布'): 3, ('尿布', '牛奶'): 4, ('尿布', '面包'): 4, ('牛奶', '面包'): 3}, 3: {('尿布', '牛奶', '面包'): 3}}
[{啤酒} -> {尿布}, {牛奶} -> {尿布}, {面包} -> {尿布}, {牛奶, 面包} -> {尿布}]
|
你能从代码中看出来,data 是个 List 数组类型,其中每个值都可以是一个集合。实际上你也可以把 data 数组中的每个值设置为 List 数组类型,比如:
1 2 3 4 5 6
| data = [['牛奶','面包','尿布'], ['可乐','面包', '尿布', '啤酒'], ['牛奶','尿布', '啤酒', '鸡蛋'], ['面包', '牛奶', '尿布', '啤酒'], ['面包', '牛奶', '尿布', '可乐']]
|
两者的运行结果是一样的,efficient-apriori 工具包把每一条数据集里的项式都放到了一个集合中进行运算,并没有考虑它们之间的先后顺序。因为实际情况下,同一个购物篮中的物品也不需要考虑购买的先后顺序。而其他的 Apriori 算法可能会因为考虑了先后顺序,出现计算频繁项集结果不对的情况。所以这里采用的是 efficient-apriori 这个工具包。
**
挖掘-导演是如何选择演员
在实际工作中,数据集是需要自己来准备的,比如今天我们要挖掘导演是如何选择演员的数据情况,但是并没有公开的数据集可以直接使用。因此我们需要使用之前讲到的 Python 爬虫进行数据采集。不同导演选择演员的规则是不同的,因此我们需要先指定导演。数据源我们选用豆瓣电影。先来梳理下采集的工作流程。首先我们先在https://movie.douban.com搜索框中输入导演姓名,比如“宁浩”。
页面会呈现出来导演之前的所有电影,然后对页面进行观察,你能观察到以下几个现象:
- 页面默认是 15 条数据反馈,第一页会返回 16 条。因为第一条数据实际上这个导演的概览,你可以理解为是一条广告的插入,下面才是真正的返回结果。
- 每条数据的最后一行是电影的演出人员的信息,第一个人员是导演,其余为演员姓名。姓名之间用“/”分割。有了这些观察之后,我们就可以编写抓取程序了。
在代码讲解中你能看出这两点观察的作用。抓取程序的目的是为了生成宁浩导演(你也可以抓取其他导演)的数据集,结果会保存在 csv 文件中。完整的抓取代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
from efficient_apriori import apriori from lxml import etree import time from selenium import webdriver import csv driver = webdriver.Chrome()
director = u'宁浩'
file_name = './' + director + '.csv' base_url = 'https://movie.douban.com/subject_search?search_text='+director+'&cat=1002&start=' out = open(file_name,'w', newline='', encoding='utf-8-sig') csv_write = csv.writer(out, dialect='excel') flags=[]
def download(request_url): driver.get(request_url) time.sleep(1) html = driver.find_element_by_xpath("//*").get_attribute("outerHTML") html = etree.HTML(html) movie_lists = html.xpath("/html/body/div[@id='wrapper']/div[@id='root']/div[1]//div[@class='item-root']/div[@class='detail']/div[@class='title']/a[@class='title-text']") name_lists = html.xpath("/html/body/div[@id='wrapper']/div[@id='root']/div[1]//div[@class='item-root']/div[@class='detail']/div[@class='meta abstract_2']") num = len(movie_lists) if num > 15: movie_lists = movie_lists[1:] name_lists = name_lists[1:] for (movie, name_list) in zip(movie_lists, name_lists): if name_list.text is None: continue print(name_list.text) names = name_list.text.split('/') if names[0].strip() == director and movie.text not in flags: names[0] = movie.text flags.append(movie.text) csv_write.writerow(names) print('OK') print(num) if num >= 14: return True else: return False
start = 0 while start<10000: request_url = base_url + str(start) flag = download(request_url) if flag: start = start + 15 else: break out.close() print('finished')
|
爬取的代码在这里就不赘述了,其中有一点就是这里用到了selenium模拟打开窗口爬取。
下面是爬取下来的数据:
我们用获取到的少量宁浩数据,来做一次关联规则分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
from efficient_apriori import apriori import csv director = u'宁浩' file_name = './'+director+'.csv' lists = csv.reader(open(file_name, 'r', encoding='utf-8-sig'))
data = [] for names in lists: name_new = [] for name in names: name_new.append(name.strip()) data.append(name_new[1:])
itemsets, rules = apriori(data, min_support=0.5, min_confidence=1) print(itemsets) print(rules)
|
代码中使用的 apriori 方法和开头中用 Apriori 获取购物篮规律的方法类似,比如代码中都设定了最小支持度和最小置信系数,这样我们可以找到支持度大于 50%,置信系数为 1 的频繁项集和关联规则。这是最后的运行结果:
1 2 3
| {1: {('徐峥',): 5, ('黄渤',): 6}, 2: {('徐峥', '黄渤'): 5}}
[{徐峥} -> {黄渤}]
|
你能看出来,宁浩导演喜欢用徐峥和黄渤,并且有徐峥的情况下,一般都会用黄渤。你也可以用上面的代码来挖掘下其他导演选择演员的规律。
总结
Apriori 算法的核心就是理解频繁项集和关联规则。
在算法运算的过程中,还要重点掌握对支持度、置信度和提升度的理解。
在工具使用上,你可以使用 efficient-apriori 这个工具包,它会把每一条数据中的项(item)放到一个集合(篮子)里来处理,不考虑项(item)之间的先后顺序。
在实际运用中你还需要灵活处理,比如导演如何选择演员这个案例,虽然工具的使用会很方便,但重要的还是数据挖掘前的准备过程,也就是获取某个导演的电影数据集。