数据挖掘-Apriori算法的java实现

3 篇文章 0 订阅
2 篇文章 0 订阅

1. Apriori算法思想
  对于Apriori算法,我们使用支持度来作为我们判断频繁项集的标准。Apriori算法的目标是找到最大的K项频繁集。这里有两层意思,首先,我们要找到符合支持度标准的频繁集。但是这样的频繁集可能有很多。第二层意思就是我们要找到最大个数的频繁集。比如我们找到符合支持度的频繁集AB和ABE,那么我们会抛弃AB,只保留ABE,因为AB是2项频繁集,而ABE是3项频繁集。那么具体的,Apriori算法是如何做到挖掘K项频繁集的呢?

Apriori算法采用了迭代的方法,先搜索出候选1项集及对应的支持度,剪枝去掉低于支持度的1项集,得到频繁1项集。然后对剩下的频繁1项集进行连接,得到候选的频繁2项集,筛选去掉低于支持度的候选频繁2项集,得到真正的频繁二项集,以此类推,迭代下去,直到无法找到频繁k+1项集为止,对应的频繁k项集的集合即为算法的输出结果。

可见这个算法还是很简洁的,第i次的迭代过程包括扫描计算候选频繁i项集的支持度,剪枝得到真正频繁i项集和连接生成候选频繁i+1项集三步。

我们下面这个简单的例子看看:
    在这里插入图片描述
 我们的数据集D有4条记录,分别是134,235,1235和25。现在我们用Apriori算法来寻找频繁k项集,最小支持度设置为50%。首先我们生成候选频繁1项集,包括我们所有的5个数据并计算5个数据的支持度,计算完毕后我们进行剪枝,数据4由于支持度只有25%被剪掉。我们最终的频繁1项集为1235,现在我们链接生成候选频繁2项集,包括12,13,15,23,25,35共6组。此时我们的第一轮迭代结束。

进入第二轮迭代,我们扫描数据集计算候选频繁2项集的支持度,接着进行剪枝,由于12和15的支持度只有25%而被筛除,得到真正的频繁2项集,包括13,23,25,35。现在我们链接生成候选频繁3项集,123, 135和235共3组,这部分图中没有画出。通过计算候选频繁3项集的支持度,我们发现123和135的支持度均为25%,因此接着被剪枝,最终得到的真正频繁3项集为235一组。由于此时我们无法再进行数据连接,进而得到候选频繁4项集,最终的结果即为频繁3三项集235。

2. Aprior算法流程
下面我们对Aprior算法流程做一个总结。

输入:数据集合D,支持度阈值α
输出:最大的频繁k项集

1)扫描整个数据集,得到所有出现过的数据,作为候选频繁1项集。k=1,频繁0项集为空集。

2)挖掘频繁k项集

a) 扫描数据计算候选频繁k项集的支持度

b) 去除候选频繁k项集中支持度低于阈值的数据集,得到频繁k项集。如果得到的频繁k项集为空,则直接返回频繁k-1项集的集合作为算法结果,算法结束。如果得到的频繁k项集只有一项,则直接返回频繁k项集的集合作为算法结果,算法结束。

c) 基于频繁k项集,连接生成候选频繁k+1项集。

3) 令k=k+1,转入步骤2。

从算法的步骤可以看出,Aprior算法每轮迭代都要扫描数据集,因此在数据集很大,数据种类很多的时候,算法效率很低。
    
 基于基本思想,我写出了它的java代码(原创):   
3.java代码实现
首先,引入要测试的数据:(数据保存在input.txt文件中,当前目录)
1 Cardiacfailure Myocardialinfarction Other
2 Cardiacfailure
3 Cardiacfailure uremia Myocardialinfarction
4 Renalfailure Cardiacfailure diabetes uremia
5 uremia Cardiacfailure Renalfailure diabetes
6 diabetes
7 diabetes Cardiacfailure Myocardialinfarction Other
8 diabetes uremia
9 diabetes
10 Renalfailure diabetes uremia
11 diabetes
12 Cardiacfailure diabetes uremia Renalfailure
13 uremia diabetes Renalfailure Cardiacfailure
14 Renalfailure
15 Other Renalfailure
16 Renalfailure diabetes
17 Myocardialinfarction Cardiacfailure
18 uremia Renalfailure
19 Renalfailure
20 uremia diabetes Renalfailure
21 uremia Renalfailure
22 uremia
23 Cardiacfailure uremia Renalfailure diabetes Myocardialinfarction
24 Renalfailure diabetes uremia Cardiacfailure
25 Myocardialinfarction Cardiacfailure Other
26 diabetes Renalfailure uremia Cardiacfailure
27 uremia Renalfailure diabetes Cardiacfailure Myocardialinfarction
28 uremia diabetes Renalfailure Myocardialinfarction
29 diabetes uremia
30 Myocardialinfarction
31 diabetes Renalfailure uremia Cardiacfailure
32 Cardiacfailure diabetes Other
33 Renalfailure diabetes
34 uremia diabetes Renalfailure
35 Myocardialinfarction Cardiacfailure
36 uremia Renalfailure
37 Other Renalfailure Myocardialinfarction
38 Renalfailure diabetes uremia
39 Cardiacfailure Myocardialinfarction Other
40 Myocardialinfarction Other
41 uremia Renalfailure diabetes
42 Cardiacfailure diabetes uremia Renalfailure
43 Myocardialinfarction
44 diabetes uremia Renalfailure
45 Myocardialinfarction Renalfailure
46 Cardiacfailure Myocardialinfarction
47 diabetes
48 Myocardialinfarction Cardiacfailure
49 diabetes Renalfailure uremia
50 Renalfailure

好,数据有了,现在就用算法实现!

//主类
package Apriori;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main 
{

	public static int minSupCount;//最小支持度
	public static ArrayList<String> dataItem;//一维数组,记录原始数据的每一行
	
	public static void main(String[] args) throws IOException 
	{
		// TODO Auto-generated method stub
		Scanner scan=new Scanner(System.in);
		System.out.print("请输入最小支持度(整数&按Enter结束):");
		minSupCount=scan.nextInt();
		
		//创建包含数组的list,即可看成是二维数组
		//与普通的二位数组不同的是,它可以动态改变大小
		ArrayList<List<String>> list=new ArrayList<List<String>>();//源数据保存在这里
	    
		File file=new File("input.txt");//文件保存在当前目录
		BufferedReader input=new BufferedReader(new FileReader(file));
		
		String string=null;
		String []temp;

		if(file.isFile())
		{
			while((string=input.readLine())!=null)
			{
				temp=string.split(" ");//分割疾病
				
				dataItem=new ArrayList<String>();//用到再创建
				for(int i=0;i<temp.length;i++)
				{
					if(temp[i].length()>2) //分割的前面的数字编号去掉
						dataItem.add(temp[i]);
				}
				list.add(dataItem);
				//System.out.println(dataItem);
			}
		}						
		input.close();//关闭文件
		ArrayList <List <String>> item = new ArrayList<List <String>>();//初始化第1项集,并把其改为List类型
		ArrayList <String> minItem1 = new ArrayList<String>();
		ArrayList <String> minItem2 = new ArrayList<String>();
		ArrayList <String> minItem3 = new ArrayList<String>();
		ArrayList <String> minItem4 = new ArrayList<String>();
		ArrayList <String> minItem5 = new ArrayList<String>();
		ArrayList <String> minItem6 = new ArrayList<String>();
		minItem1.add("Cardiacfailure");//初始化第1项集。
		minItem2.add("Myocardialinfarction");
		minItem3.add("uremia");
		minItem4.add("diabetes");
		minItem5.add("Renalfailure");
		minItem6.add("Other");
		
		item.add(minItem1);
		item.add(minItem2);
		item.add(minItem3);
		item.add(minItem4);
		item.add(minItem5);
		item.add(minItem6);
		
		
		ArrayList<List<String>> test = new ArrayList<List <String>>();
		ArrayList<String> oneItem=new ArrayList<String>();//初始化第1项集。
		oneItem=getOneItem.get();//得到1项集。
			
		//啊啊啊啊啊啊啊啊啊啊
		
		int count=0;
		while(true)		
		{		 
		     //System.out.println(test);
			 if(count==0)
				 countKItem.caculate(list, item, minSupCount);//第一项集	
			 else 
				 countKItem.caculate(list, test, minSupCount);
		    
		     if(count==0)
			     test=addKItem.changeKTo(item, oneItem);	//第一项集	
			 else 
				 test=addKItem.changeKTo(test, oneItem);
		     if(test.size()==0) break;
		     count++;
		     System.out.println();
		}
		System.out.println("完美结束Apriori算法!");
		//countKItem.caculate(list, item, minSupCount);
		
	

		//System.out.print(list);
		//打印输出看效果
//		for(int i=0;i<list.size();i++)
//		{
//			for(int j=0;j<list.get(i).size();j++)
//				System.out.print(list.get(i).get(j)+" ");
//			System.out.println();	
//		}
	
		
	}

}

```java
//第二个类
package Apriori;

import java.util.ArrayList;
import java.util.List;

public class getOneItem 
{
	//得到数据的一项集
	public static ArrayList<String> get() 
	{
        ArrayList<String> list=new ArrayList<String>();//初始化第1项集。
        list.add("Cardiacfailure");
		list.add("Myocardialinfarction");
		list.add("uremia");
		list.add("diabetes");
		list.add("Renalfailure");
		list.add("Other");
		return list;
	}

}


//第三个类
package Apriori;

import java.util.ArrayList;
import java.util.List;

public class countKItem 
{
    //data数组为原数组,list数组为k项集,support为最小支持度。
	//这个类主要是筛选符合置信度的k项集。
	static ArrayList<Integer> cMachine;//最终的频率计数器
	public static ArrayList<List<String>> caculate(ArrayList<List<String>> data,ArrayList<List<String>> list,int support)
	{
		ArrayList<List<String>> datalist=new ArrayList<List<String>>();//记录k项集符合>=最小置信度的项集
		ArrayList<Integer> countMachine=new ArrayList<Integer>();
		cMachine=new ArrayList<Integer>();
		for(int i=0;i<list.size();i++)
		{
			int sum=0;		
			for(int raw=0;raw<data.size();raw++)//数据集第0行开始验证
			{
				int count=0;
				for(int j=0;j<list.get(i).size();j++)//k项集的时候,计算k+1项集
			    {
				    int n=liveUP(list.get(i).get(j),raw,data);
				    	if(n==1)				    	
				    		count+=n;   
			    }
				if(count == list.get(i).size())
				    sum++;
			}
			if(sum>=support)
			{
				countMachine.add(sum);
				datalist.add(list.get(i));
			}
			
			
		}
		
        ArrayList<List<String>> List=new ArrayList<List<String>>();//记录k项集符合>=最小置信度的项集	
		List=checkRight(datalist,countMachine);
		
		if(List.size()==0) //直至符合置信度的项集为null
		{
			return List;
		}
		
		//下面打印输出k项集。
		System.out.printf("第 %d 级频数项集为:\n",list.get(0).size());
		System.out.println("       项集               "+"        频率   ");
		for(int i=0;i<List.size();i++)
		{
			for(int j=0;j<List.get(i).size();j++)
			{
				System.out.printf("%s   ",List.get(i).get(j));
			}
			
			System.out.print(cMachine.get(i));
			System.out.println();
		}
		
		return List;
	}
	public static ArrayList <List<String>> checkRight(ArrayList <List<String>> list,ArrayList<Integer> count)//验证数据项在数据集中是否重复:如a b 与b a 是重复的项集。
	{
		ArrayList <List<String>> temp=new ArrayList<List<String>>();
		for(int i=0;i<list.size();i++)
		{
			
			for(int j=i+1;j<list.size();j++)
			{
				int sum=0;
				if(count.get(i)==count.get(j)) //支持度相等才检验。
				{
					
					for(int x=0;x<list.get(i).size();x++)
					{
						for(int y=0;y<list.get(j).size();y++)
						{
							if(list.get(i).get(x)==list.get(j).get(y))
							{
								sum++;
								break;
							}								
						}
					}			
					if(sum==list.get(i).size())
					    count.set(j, -1);//标为-1则表示要删除的。	
				}	
			}			
		}
		
//		System.out.println(count);
		for(int i=0;i<list.size();i++)
		{
			
			if(count.get(i)!=-1) 
			{
				temp.add(list.get(i));
				cMachine.add(count.get(i));
			}
				
			
			else continue;
		}
		//System.out.println(temp);
		return temp;
				
	}
	
	public static int liveUP(String str,int raw,ArrayList<List<String>> data)//验证单个元素在数据集data第raw行中是否存在。
	{
	
		for(int i=0;i<data.get(raw).size();i++)
		{
			if(str.equals(data.get(raw).get(i)))
				return 1;
		}
		return 0;
	}
	
}


```java
//第四个类
package Apriori;

import java.util.ArrayList;
import java.util.List;

public class addKItem
{
	//list为K项集,support为最小置信度,返回的dataList为K+1项集。

	public static ArrayList<String>temp;
	static ArrayList<List<String>> dataList;
	public static ArrayList<List<String>> changeKTo(ArrayList<List<String>> list,ArrayList<String> oneItem)
	{
		
	
		 dataList = new ArrayList<List<String>>();
		
		ArrayList<Integer> count=new ArrayList<Integer>();//计算k+1项集的支持度
		for(int i=0;i<list.size();i++)
		{
			temp=new ArrayList<String>();
			for(int j=0;j<list.get(i).size();j++)//把k项集的第i行元素复制过来。
				temp.add(list.get(i).get(j));
			//System.out.println(temp);
			
			for(int x=0;x<oneItem.size();x++)//K+1项集生成。
			{
				int flag=0;
				flag=check(oneItem.get(x),temp);
				//System.out.println(flag);
				ArrayList<String> temp1 =new ArrayList<String>();
				if(flag==1)
				{
					temp.add(oneItem.get(x));
					for(int y=0;y<temp.size();y++)
						temp1.add(temp.get(y));
					dataList.add(temp1);//不能直接add(temp),引用同一对象会覆盖。
					//System.out.println(temp1);					
					temp.remove(temp.size()-1);
				}
			}
				
		}
		
		//System.out.println(dataList);
		
		return dataList;
	}
	public static int check(String string, ArrayList<String> item)//元素不重复加入
	{
		
		for(int i=0;i<item.size();i++)
		{
			if(string.equals(item.get(i)))
				return 0;
		}
		return 1;
		
	}

}

运行结果截图:
在这里插入图片描述

代码很浅显,哈哈哈,都是一码一码写出来的,可能还有待优化。
前面的第1、2 转载自 https://www.cnblogs.com/pinard/p/6293298.html

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乐邂逅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值