实验描述:
对指定数据集进行关联规则挖掘,选择适当的挖掘算法,编写程序实现,提交程序和结果报告。
数据集: retail.txt ,根据数据集中的数据利用合适的挖掘算法得到频繁项集,并计算置信度,求出满足置信度的所有的关联规则
retail.txt中每个数字表示一种商品的ID,一个{}内的表示一次交易
实验环境和编程语言:
本实验使用的编程语言为:Java
编程环境为:Intellij idea
实现频繁项集的挖掘算法为Apriori算法
用于挖掘的样本个数为:1000个(retail.txt的前1000条数据)
样本示例:
{ 38,39,47,48}
表示一个顾客购买了ID为38、39、47、48的四种商品。
算法分析:
Apriori算法是一种最有影响的挖掘布尔关联规则频繁项集的算法Apriori使用一种称作逐层搜索的迭代方法,“K-1项集”用于搜索“K项集”。
首先,找出频繁“1项集”的集合,该集合记作L1。L1用于找频繁“2项集”的集合L2,而L2用于找L3。如此下去,直到不能找到“K项集”。找每个Lk都需要一次数据库扫描。
核心思想是:连接步和剪枝步。连接步是自连接,原则是保证前k-2项相同,并按照字典顺序连接。剪枝步,是使任一频繁项集的所有非空子集也必须是频繁的。反之,如果某个候选的非空子集不是频繁的,那么该候选肯定不是频繁的,从而可以将其从CK中删除。
简单的讲,利用Apriori算法挖掘关联规则步骤如下:
1、发现频繁项集,过程为(1)扫描(2)计数(3)比较(4)产生频繁项集(5)连接、剪枝,产生候选项集 重复步骤(1)~(5)直到不能发现更大的频集,示例如图1-1所示。
2、产生关联规则,过程为:根据前面提到的置信度的定义,关联规则的产生如下:
(1)对于每个频繁项集L,产生L的所有非空子集;
(2)对于L的每个非空子集S,如果
P(L)/P(S)≧min_conf
则输出关联规则“{ S } =>>{L-S}”
注:L-S表示在项集L中除去S子集的项集
实验结果分析:
根据程序运行的结果,利用retail.txt的前1000条数据进行关联规则挖掘,在最小支持度为4%的时候(即支持度计数大于40时)其得到的频繁项集如图1-2所示,总共发现了9个一项集、10个二项集、4个三项集、1个四项集。
对频繁项集进行置信度计算,在最小置信度为70%的时候,挖掘出8项关联规则,其结果如图1-3所示。
思考与改进:
1. 本次实验使用Apriori算法对数据集进行关联规则的挖掘,虽然算法实现起来相对简单,但是由于其在计算支持度的时候需要每次都要扫描整个数据集,所以其效率十分低下,同时也造成了很多不必要的重复计算,因此本次实验只能选取retail.txt总共80000多条数据中的前1000条进行关联规则挖掘,如果使用完整的数据集则连一项集都需要相当长的时间才能统计出来。因此在面对大数据量的时候,Apriori算法并不是最好的选择。对于大数据集,使用Fpgrowth算法可能效率更高,但由于其实现更加复杂,在这里就不做过多赘述。
2. 为了实现简单,本次实验中实现的是最简单的Apriori算法,其在每次的计算中是有很多无用的计算,所以其实我们可以利用一些技术来提高Apriori算法的执行效率例如使用基于散列的技术、事务压缩等方法,来提高计数的效率同时减少不必要的计数,从而实现算法效率的提高。
3. 同时在本次实验中发现一个现象,如果加大数据集,例如使用retail.txt中的前2000项数据进行挖掘,在相同的支持度和置信度下,频繁项集和关联规则甚至会减少。经过分析发现,由于本次实验是利用百分比来作为支持度的阈值,当总数据集增大时,相当于支持度计数的阈值也成倍的增长,满足支持度计数的项集反而会减少,由此可见根据不同的数据集规模,选择合适的支持度百分比对于能否得到有效的关联规则至关重要。
编程实现:
本实验的工程项目和数据集可访问以下网址下载:
http://download.csdn.net/detail/qq_24369113/9712408
https://github.com/muziyongshixin/Association-rule-mining-with-Apriori
函数设计与分析:
1. public staticList<List<String>> getRecord(String url)
//加载数据文件并进行预处理
2. public static void Apriori()
//实现Apriori算法的迭代
3. public static voidAssociationRulesMining()
//根据频繁项集进行关联规则的挖掘
4. public static double isAssociationRules(List<String> s1,List<String>s2,List<String> tem)
//判断s1和tem-s1是否为一个关联规则
5. public static intgetCount(List<String> in)
//得到输入频繁项集in的支持度计数
6. public static List<String>gets2set(List<String> tem, List<String> s1)
//得到集合{tem-s1},即为s2
7. public staticList<List<String>> getSubSet(List<String> set)
//得到一个集合是所有的非空真子集
8. private staticList<List<String>> getNextCandidate(List<List<String>>FrequentItemset)
//有当前频繁项集自连接求下一次候选集
9. private static booleanisnotHave(HashSet<String> hsSet, List<List<String>>nextCandidateItemset)
//判断新生成的候选集是不是在已经在候选集集合中
10. private staticList<List<String>>getSupprotedItemset(List<List<String>> CandidateItemset)
//对候选集进行支持度计数
11. private static intcountFrequent1(List<String> list)
//进行支持度计数
12. private staticList<List<String>> findFirstCandidate()
//找到一项集的候选集
源码实现:
/**
* Created by muziyongshixin on 2016/12/6.
*
*
* 本工程包含两个数据文件
* fulldata为老师给的原始数据文件,由于数据量过大程序跑不出来结果,没有选用进行测试
* top1000data是从fulldata中摘取的前1000条数据,本程序运行的结果是基于这前1000条数据进行的频繁项集挖掘和关联度分析
*
*/
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.*;
/**
* Apriori算法实现 最大模式挖掘,涉及到支持度,但没有置信度计算
*
* AssociationRulesMining()函数实现置信度计算和关联规则挖掘
*/
public class AprioriMyself {
public static int times=0;//迭代次数
private static double MIN_SUPPROT = 0.02;//最小支持度百分比
private static double MIN_CONFIDENCE=0.6;//最小置信度
private static boolean endTag = false;//循环状态,迭代标识
static List<List<String>> record = new ArrayList<List<String>>();//数据集
static List<List<String>> frequentItemset=new ArrayList<>();//存储所有的频繁项集
static List<Mymap> map = new ArrayList();//存放频繁项集和对应的支持度技术
public static void main(String args[]){
System.out.println("请输入最小支持度(如0.05)和最小置信度(如0.6)");
Scanner in=new Scanner(System.in);
MIN_SUPPROT=in.nextDouble();
MIN_CONFIDENCE=in.nextDouble();
/*************读取数据集**************/
record = getRecord("top1000data");
//控制台输出记录
System.out.println("读取数据集record成功===================================");