算法描述
(1)扫描全部数据,产生候选1-项集的集合C1;
(2)根据最小支持度,由候选1-项集的集合C1产生频繁1-项集的集合L1;
(3)对k>1,重复执行步骤(4)、(5)、(6);
(4)由Lk执行连接和剪枝操作,产生候选(k+l)-项集的集合Ck+1;
(5)根据最小支持度,由候选(k+l)-项集的集合Ck+1,产生频繁(k+1)-项集的集合Lk+1;
(6)若L≠Φ,则k=k+1,跳往步骤(4);否则,跳往步骤(7);
(7)根据最小置信度,由频繁项集产生强关联规则,结束。
代码
public class Apriori2
{private final static int SUPPORT = 8; // 支持度阈值private final static double CONFIDENCE = 0.6; // 置信度阈值private final static String ITEM_SPLIT = " "; // 项之间的分隔符private final static String CON = "->"; // 项之间的分隔符/*** 算法主程序* @param dataList* @return Map<String, Integer>*/public Map<String, Integer> apriori(ArrayList<String> dataList){Map<String, Integer> stepFrequentSetMap = new HashMap<>(findFrequentOneSets(dataList));//找出候选// 1-项集//频繁项集Map<String, Integer> frequentSetMap = new HashMap<String, Integer>(stepFrequentSetMap);while(stepFrequentSetMap.size() > 0)//上一步的频繁项集不为空{Map<String, Integer> candidateSetMap = aprioriGen(stepFrequentSetMap);//生成候选集Set<String> candidateKeySet = candidateSetMap.keySet();//扫描D,进行计数,计算候选集的支持度计数for(String data:dataList){for(String candidate:candidateKeySet){boolean flag = true;String[] strings = candidate.split(ITEM_SPLIT);for(String string:strings){if(!data.contains(string + ITEM_SPLIT))//找不出候选项集中的元素,退出{flag = false;break;}}if(flag)candidateSetMap.put(candidate, candidateSetMap.get(candidate)+1);//支持度加一}}//从候选集中找到符合支持度的频繁项集stepFrequentSetMap.clear();for(String candidate:candidateKeySet){Integer count = candidateSetMap.get(candidate);if(count>=SUPPORT)stepFrequentSetMap.put(candidate, count);}// 合并所有频繁集frequentSetMap.putAll(stepFrequentSetMap);}return frequentSetMap;}/*** 找出候选K-项集* @param dataList* @return Map<String, Integer>*/private Map<String, Integer> findFrequentOneSets(ArrayList<String> dataList){Map<String, Integer> resultSetMap = new HashMap<>();for(String data:dataList){String[] strings = data.split(ITEM_SPLIT);for(String string:strings){string += ITEM_SPLIT;if(resultSetMap.get(string)==null){resultSetMap.put(string, 1);}else {resultSetMap.put(string, resultSetMap.get(string)+1);}}}return resultSetMap;}/*** 根据上一步的频繁项集的集合选出候选集* @param setMap* @return*/private Map<String, Integer> aprioriGen(Map<String, Integer> setMap){Map<String, Integer> candidateSetMap = new HashMap<>();Set<String> candidateSet = setMap.keySet();for(String s1:candidateSet){String[] strings1 = s1.split(ITEM_SPLIT);String s1String = "";for(String temp:strings1)s1String += temp+ITEM_SPLIT;for(String s2:candidateSet){String[] strings2 = s2.split(ITEM_SPLIT);boolean flag = true;for(int i=0;i<strings1.length-1;i++){if(strings1[i].compareTo(strings2[i])!=0)//存在不同元素,不能连接{flag = false;break;}}if(flag && strings1[strings1.length-1].compareTo(strings2[strings1.length-1])<0){//连接步:产生候选String c = s1String+strings2[strings2.length-1]+ITEM_SPLIT;if(hasInfrequentSubset(c, setMap)){//剪枝步:删除非频繁的候选}else {candidateSetMap.put(c, 0);}}}}return candidateSetMap;}/*** 使用先验知识,判断候选集是否是频繁项集* @param candidateSet* @param setMap* @return boolean*/private boolean hasInfrequentSubset(String candidateSet, Map<String, Integer> setMap){String[] strings = candidateSet.split(ITEM_SPLIT);//候选集//找出候选集所有的子集,并判断每个子集是否属于频繁子集for(int i=0;i<strings.length;i++){String subString = "";for(int j=0;j<strings.length;j++)//遍历所有子集{if(j!=i){subString += strings[j]+ITEM_SPLIT;}}if(setMap.get(subString)==null)return true;}return false;}/*** 由频繁项集产生关联规则* @param frequentSetMap* @return*/public Map<String, Double> getRelationRules(Map<String, Integer> frequentSetMap){Map<String, Double> relationsMap = new HashMap<>();Set<String> keySet = frequentSetMap.keySet();for(String key:keySet)//遍历所有频繁项集{List<String> keySubset = subset(key);//频繁项的所有子集for(String keySubsetItem:keySubset)//遍历所有子集{//子集keySubsetItem也是频繁项Integer count = frequentSetMap.get(keySubsetItem);if(count!=null)//计算置信度{Double confidence = (1.0*frequentSetMap.get(key))/(1.0*frequentSetMap.get(keySubsetItem));if(confidence>CONFIDENCE)relationsMap.put(keySubsetItem+CON+expect(key, keySubsetItem), confidence);}}}return relationsMap;}/*** 求一个集合所有的非空真子集** @param sourceSet* @return* 为了以后可以用在其他地方,这里我们不是用递归的方法** 参考:http://blog.163.com/xiaohui_1123@126/blog/static/3980524020109784356915/* 思路:假设集合S(A,B,C,D),其大小为4,拥有2的4次方个子集,即0-15,二进制表示为0000,0001,...,1111。* 对应的子集为空集,{D},...,{A,B,C,D}。*/private List<String> subset(String sourceSet){List<String> result = new ArrayList<>();String[] strings = sourceSet.split(ITEM_SPLIT);//非空真子集for(int i=1;i<(int)(Math.pow(2, strings.length))-1;i++){String item = "";String flag = "";int ii=i;do{flag += ""+ii%2;ii = ii/2;} while (ii>0);for(int j=flag.length()-1;j>=0;j--){if(flag.charAt(j)=='1'){item = strings[j]+ITEM_SPLIT+item;}}result.add(item);}return result;}/*** 集合运算,A/B* @param A* @param B* @return*/private String expect(String stringA,String stringB){String result = "";String[] stringAs = stringA.split(ITEM_SPLIT);String[] stringBs = stringB.split(ITEM_SPLIT);for(int i=0;i<stringAs.length;i++){boolean flag = true;for(int j=0;j<stringBs.length;j++){if(stringAs[i].compareTo(stringBs[j])==0){flag = false;break;}}if(flag)result += stringAs[i]+ITEM_SPLIT;}return result;}public static void readTxt(String fileName){try { // 防止文件建立或读取失败,用catch捕捉错误并打印,也可以throw/* 读入TXT文件 */File filename = new File(fileName); // 要读取以上路径的input。txt文件InputStreamReader reader = new InputStreamReader(new FileInputStream(filename)); // 建立一个输入流对象readerBufferedReader br = new BufferedReader(reader); // 建立一个对象,它把文件内容转成计算机能读懂的语言String line = "";line = br.readLine();while (line != null) {dataList.add(line);line = br.readLine();}} catch (Exception e) {e.printStackTrace();}}public static ArrayList<String> dataList = new ArrayList<>();public static void main(String[] args){readTxt("test.txt");System.out.println("=数据集合==========");for(String string:dataList){System.out.println(string);}Apriori2 apriori2 = new Apriori2();System.out.println("=频繁项集==========");Map<String, Integer> frequentSetMap = apriori2.apriori(dataList);Set<String> keySet = frequentSetMap.keySet();for(String key:keySet){System.out.println(key+" : "+frequentSetMap.get(key));}System.out.println("=关联规则==========");Map<String, Double> relationRulesMap = apriori2.getRelationRules(frequentSetMap);Set<String> rrKeySet = relationRulesMap.keySet();for (String rrKey : rrKeySet){System.out.println(rrKey + " : " + relationRulesMap.get(rrKey));}}
}