表6-1、6-2 Apriori算法过程示例:假定支持度阈值为60%,相当于最小支持度计数为3。
1-项集:即只包含一个项的项集
- 初始:每个项都被看作候选1-项集。对它们的支持度计数,候选项集{可乐}和{鸡蛋}被丢弃,因其出现的事务少于3个。
- 下次迭代:仅使用频繁1-项集产生候选2-项集。本例中,只有4个频繁1-项集,因此产生C42=6个候选2-项集——计算它们的支持度值,发现其中2个,即{啤酒,面包}和{啤酒,牛奶}是非频繁的,其余4个频繁。
- 使用4个频繁的候选2-项集产生候选3-项集,此时,不使用基于支持度的剪枝,而是根据先验原理,只保留其子集都频繁的候选3-项集:{面包,尿布,牛奶}。
候选k项集——该操作的复杂度为O(k)
(2条消息) Java实现Apriori算法进行关联规则挖掘_木子的博客-CSDN博客_apriori javahttps://blog.csdn.net/qq_24369113/article/details/53645474
//编译java文件→class文件
javac -encoding UTF-8 -Xlint:unchecked AprioriMyself.java
//运行class文件
java AprioriMyself
(1条消息) I/O流之进步认识、InputStream以及FileInputStream_一点一滴-CSDN博客https://blog.csdn.net/qq_34944851/article/details/52069162
//File类: 用于描述一个文件或者文件夹,通过File对象,可以读取文件或文件夹的属性数据。如果我们需要读取文件的内容数据,那么需要使用IO流技术
//IO流:解决设备与设备之间的数据传输问题:内存—>硬盘 硬盘—>内存
import java.io.BufferedReader;//从字符输入流中读取文本,缓冲各个字符,从而提供字符,数组和行的高效读取
import java.io.File;//Java中的包就相当于windows系统中的文件夹,当前程序要使用Java文件夹下的io文件夹下的File类,由于不在同一个文件夹下的文件相互不可见,所以需要声明引入
import java.io.FileInputStream;//读取文件数据的输入字节流
import java.io.InputStreamReader;//InputStreamReader是字节流与字符流之间的桥梁,能将字节流输出为字符流,并为字节流指定字符集,输出一个个的字符
import java.util.*;//实用工具类库java.util包。在这个包中,Java提供了一些实用的方法和数据结构
public class AprioriMyself { //AprioriMyself类, public static表示公共的静态方法,static静态变量(被所有对象共享)
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> record = new ArrayList>();//数据集
static List> frequentItemset=new ArrayList<>();//存储所有的频繁项集
static List map = new ArrayList();//存放频繁项集和对应的支持度技术
public static void main(String args[]){ //解析:https://blog.csdn.net/qq_38807792/article/details/81010469
/**public:java程序的入口,java程序通过java虚拟机JVM调用,属于外部调用,所以需要使用public修饰,否则虚拟机无法调用。
static:没有static的变量或函数,如果想被调用的话,是要先新建一个对象才可以。而main函数作为程序的入口,需要在其它函数实例化之前就启动,这也就是为什么要加一个static。main函数好比一个门,要探索其它函数要先从门进入程序。static提供了这样一个特性,无需建立对象,就可以启动。
void:使用void的原因是当main方法出现返回值时JVM无法进行上抛,如果有返回值难道抛给操作系统么?
String args[]:args是数组的名字,并不是固定的,它是声明了一个可从控制台接受的数据的类型为String数组
*
*/
System.out.println("请输入最小支持度(如0.05)和最小置信度(如0.6)");//输出字符串
Scanner in=new Scanner(System.in);//获取控制台的输入
MIN_SUPPROT=in.nextDouble();//读取一个double类型的变量
MIN_CONFIDENCE=in.nextDouble();
/*************读取数据集**************/
record = getRecord("C:\\Users\\YWP\\eclipse-workspace\\apriori2\\src\\apriori2\\top1000data");
//控制台输出记录
System.out.println("读取数据集record成功===================================");
ShowData(record);
Apriori();//调用Apriori算法获得频繁项集
System.out.println("频繁模式挖掘完毕。\n\n\n\n\n进行关联度挖掘,最小支持度为:"+MIN_SUPPROT+" 最小置信度为:"+MIN_CONFIDENCE);
AssociationRulesMining();//挖掘关联规则
}
public static List> getRecord(String url) {
List> record = new ArrayList>();
try {
String encoding = "UTF-8"; // 字符编码(可解决中文乱码问题 )
File file = new File(url);//读取文件,url为路径
if (file.isFile() && file.exists()) {
InputStreamReader read = new InputStreamReader(
new FileInputStream(file), encoding);
BufferedReader bufferedReader = new BufferedReader(read);
String lineTXT = null;
while ((lineTXT = bufferedReader.readLine()) != null) {//读一行文件
String[] lineString = lineTXT.split(",");
List lineList = new ArrayList();
for (int i = 0; i < lineString.length; i++) {
lineList.add(lineString[i]);
}
record.add(lineList);
}
read.close();
} else {
System.out.println("找不到指定的文件!");
}
} catch (Exception e) {
System.out.println("读取文件内容操作出错");
e.printStackTrace();
}
return record;
}
public static void Apriori() /**实现apriori算法**/
{
//************获取候选1项集**************
System.out.println("第一次扫描后的1级 备选集CandidateItemset");
List> CandidateItemset = findFirstCandidate();
ShowData(CandidateItemset);
//************获取频繁1项集***************
System.out.println("第一次扫描后的1级 频繁集FrequentItemset");
List> FrequentItemset = getSupprotedItemset(CandidateItemset);
AddToFrequenceItem(FrequentItemset);//添加到所有的频繁项集中
//控制台输出1项频繁集
ShowData(FrequentItemset);
//*****************************迭代过程**********************************
times=2;
while(endTag!=true){
System.out.println("*******************************第"+times+"次扫描后备选集");
//**********连接操作****获取候选times项集**************
List> nextCandidateItemset = getNextCandidate(FrequentItemset);
//输出所有的候选项集
ShowData(nextCandidateItemset);
/**************计数操作***由候选k项集选择出频繁k项集****************/
System.out.println("*******************************第"+times+"次扫描后频繁集");
List> nextFrequentItemset = getSupprotedItemset(nextCandidateItemset);
AddToFrequenceItem(nextFrequentItemset);//添加到所有的频繁项集中
//输出所有的频繁项集
ShowData(nextFrequentItemset);
//*********如果循环结束,输出最大模式**************
if(endTag == true){
System.out.println("\n\n\nApriori算法--->最大频繁集==================================");
ShowData(FrequentItemset);
}
//****************下一次循环初值********************
FrequentItemset = nextFrequentItemset;
times++;//迭代次数加一
}
}
public static void AssociationRulesMining()//关联规则挖掘
{
for(int i=0;i tem=frequentItemset.get(i);
if(tem.size()>1) {
List temclone=new ArrayList<>(tem);
List> AllSubset = getSubSet(temclone);//得到频繁项集tem的所有子集
for (int j = 0; j < AllSubset.size(); j++) {
List s1 = AllSubset.get(j);
List s2 = gets2set(tem, s1);
double conf = isAssociationRules(s1, s2, tem);
if (conf > 0)
System.out.println("置信度为:" + conf);
}
}
}
}
public static double isAssociationRules(List s1,List s2,List tem)//判断是否为关联规则
{
double confidence=0;
int counts1;
int countTem;
if(s1.size()!=0&&s1!=null&&tem.size()!=0&&tem!=null)
{
counts1= getCount(s1);
countTem=getCount(tem);
confidence=countTem*1.0/counts1;
if(confidence>=MIN_CONFIDENCE)
{
System.out.print("关联规则:"+ s1.toString()+"=>>"+s2.toString()+" ");
return confidence;
}
else
return 0;
}
else
return 0;
}
public static int getCount(List in)//根据频繁项集得到 其支持度计数
{
int rt=0;
for(int i=0;i
public static List gets2set(List tem, List s1)//计算tem减去s1后的集合即为s2
{
List result=new ArrayList<>();
for(int i=0;i
public static List> getSubSet(List set){
List> result = new ArrayList<>(); //用来存放子集的集合,如{{},{1},{2},{1,2}}
int length = set.size();
int num = length==0 ? 0 : 1<<(length); //2的n次方,若集合set为空,num为0;若集合set有4个元素,那么num为16.
//从0到2^n-1([00...00]到[11...11])
for(int i = 1; i < num-1; i++){
List subSet = new ArrayList<>();
int index = i;
for(int j = 0; j < length; j++){
if((index & 1) == 1){ //每次判断index最低位是否为1,为1则把集合set的第j个元素放到子集中
subSet.add(set.get(j));
}
index >>= 1; //右移一位
}
result.add(subSet); //把子集存储起来
}
return result;
}
public static boolean AddToFrequenceItem(List> fre)
{
for(int i=0;i
public static void ShowData(List> CandidateItemset)//显示出candidateitem中的所有的项集
{
for(int i=0;i list = new ArrayList(CandidateItemset.get(i));
for(int j=0;j
private static List> getNextCandidate(List> FrequentItemset) {
List> nextCandidateItemset = new ArrayList>();
for (int i=0; i hsSet = new HashSet();
HashSet hsSettemp = new HashSet();
for (int k=0; k< FrequentItemset.get(i).size(); k++)//获得频繁集第i行
hsSet.add(FrequentItemset.get(i).get(k));
int hsLength_before = hsSet.size();//添加前长度
hsSettemp=(HashSet) hsSet.clone();
for(int h=i+1; hi)连接 每次添加且添加一个元素组成 新的频繁项集的某一行,
hsSet=(HashSet) hsSettemp.clone();//!!!做连接的hasSet保持不变
for(int j=0; j< FrequentItemset.get(h).size();j++)
hsSet.add(FrequentItemset.get(h).get(j));
int hsLength_after = hsSet.size();
if(hsLength_before+1 == hsLength_after && isnotHave(hsSet,nextCandidateItemset)){
//如果不相等,表示添加了1个新的元素 同时判断其不是候选集中已经存在的一项
Iterator itr = hsSet.iterator();
List tempList = new ArrayList();
while(itr.hasNext()){
String Item = (String) itr.next();
tempList.add(Item);
}
nextCandidateItemset.add(tempList);
}
}
}
return nextCandidateItemset;
}
private static boolean isnotHave(HashSet hsSet, List> nextCandidateItemset) {//判断hsset是不是candidateitemset中的一项
List tempList = new ArrayList();
Iterator itr = hsSet.iterator();
while(itr.hasNext()){//将hsset转换为List
String Item = (String) itr.next();
tempList.add(Item);
}
for(int i=0; i
private static List> getSupprotedItemset(List> CandidateItemset) { //对所有的商品进行支持度计数
// TODO Auto-generated method stub
boolean end = true;
List> supportedItemset = new ArrayList>();
for (int i = 0; i < CandidateItemset.size(); i++){
int count = countFrequent1(CandidateItemset.get(i));//统计记录数
if (count >= MIN_SUPPROT * (record.size()-1)){
supportedItemset.add(CandidateItemset.get(i));
map.add(new Mymap(CandidateItemset.get(i),count));//存储当前频繁项集以及它的支持度计数
end = false;
}
}
endTag = end;//存在频繁项集则不会结束
if(endTag==true)
System.out.println("*****************无满足支持度的"+times+"项集,结束连接");
return supportedItemset;
}
private static int countFrequent1(List list) {//遍历所有数据集record,对单个候选集进行支持度计数
int count =0;
for(int i=0;i
private static List> findFirstCandidate() {
// TODO Auto-generated method stub
List> tableList = new ArrayList>();
HashSet hs = new HashSet();//新建一个hash表,存放所有的不同的一维数据
for (int i = 1; i itr = hs.iterator();
while(itr.hasNext()){
List tempList = new ArrayList();
String Item = (String) itr.next();
tempList.add(Item); //将每一种商品存放到一个List中
tableList.add(tempList);//所有的list存放到一个大的list中
}
return tableList;//返回所有的商品
}
}
class Mymap{//自定义的map类,一个对象存放一个频繁项集以及其支持度计数
public List li=new LinkedList<>();
public int count;
public Mymap(List l,int c)//构造函数 新建一个对象
{
li=l;
count=c;
}
public int getcount()//返回得到当前频繁项集的支持度计数
{
return count;
}
public boolean isListEqual(List in)//判断传入的频繁项集是否和本频繁项集相同
{
if(in.size()!=li.size())//先判断大小是否相同
return false;
else {
for(int i=0;i
读取数据集record成功===================================
第一次扫描后的1级 备选集CandidateItemset
第一次扫描后的1级 频繁集FrequentItemset
*******************************第2次扫描后备选集
*******************************第2次扫描后频繁集
*******************************第3次扫描后备选集
*******************************第3次扫描后频繁集
*******************************第4次扫描后备选集
*******************************第4次扫描后频繁集
*****************无满足支持度的4项集,结束连接
Apriori算法--->最大频繁集==================================
38 41 39
48 38 39
48 41 39
频繁模式挖掘完毕。
进行关联度挖掘,最小支持度百分比为:0.05 最小置信度为:0.6
关联规则:[38]=>>[39] 置信度为:0.6239669421487604
关联规则:[170]=>>[38] 置信度为:0.9821428571428571
关联规则:[41]=>>[39] 置信度为:0.7958333333333333
关联规则:[48]=>>[39] 置信度为:0.7370786516853932
关联规则:[38, 41]=>>[39] 置信度为:0.788235294117647
关联规则:[48, 38]=>>[39] 置信度为:0.7387387387387387
关联规则:[48, 41]=>>[39] 置信度为:0.835820895522388