浅析数据挖掘Apriori算法 及其Java实现

  1. 概述
    首先,找出频繁 1- 项集的集合。该集合记作L1。L1 用于找频繁2- 项集的集合 L2,而L2 用于找L2,如此下去,直到不能找到 k- 项集。每找一个 Lk 需要一次数据库扫描。为提高频繁项集逐层产生的效率,一种称作Apriori 性质的重 要性质 用于压缩搜索空间。其运行定理在于一是频繁项集的所有非空子集都必须也是频繁的,二是非频繁项集的所有父集都是非频繁的。

  2. 步骤
    1.扫描数据库,对每个候选项进行计数,并得到支持数
    2.比较候选项支持度计数与最小支持度minSupport,产生1维最大项目集L1

连接步
若有两个k-1项集,每个项集按照“属性-值”(一般按值)的字母顺序进行排序。如果两个k-1项集>的前k-2个项相同,而最后一个项不同,则证明它们是可连接的,即这个k-1项集可以联姻,即可连接生成k
项集。使如有两个3项集:{a,
b, c}{a, b, d},这两个3项集就是可连接的,它们可以连接生成4项集{a, b, c, d}。又如两个3项集{a, b,
c}{a, d, e},这两个3项集显示是不能连接生成3项集的。

3.由L1产生候选项

剪枝步 若一个项集的子集不是频繁项集,则该项集肯定也不是频繁项集。这个很好理解,举一个例子,若存在3项集{a, b,
c},如果它的2项子集{a, b}的支持度即同时出现的次数达不到阈值,则{a, b,
c}同时出现的次数显然也是达不到阈值的。因此,若存在一个项集的子集不是频繁项集,那么该项集就应该被无情的舍弃

4.扫描D,对每个候选项集进行支持度计数
5.比较候选项支持度计数与最小支持度minSupport,产生2维最大项目集L2
6.由L2产生候选项集C3
7.比较候选项支持度计数与最小支持度minSupport,产生3维最大项目集L3

例子

8.从频繁集中挖掘相关规则

一条规则P➞H的可信度定义为support(P | H)/support(P),其中“|”表示P和H的并集。可见可信度的计算是基于项集的支持度的。

下图给出了从项集{0,1,2,3}产生的所有关联规则,其中阴影区域给出的是低可信度的规则。可以发现如果{0,1,2}➞{3}是一条低可信度规则,那么所有其他以3作为后件(箭头右部包含3)的规则均为低可信度的。

可以观察到,如果某条规则并不满足最小可信度要求,那么该规则的所有子集也不会满足最小可信度要求。以下图为例,假设规则{0,1,2} ➞ {3}并不满足最小可信度要求,那么就知道任何左部为{0,1,2}子集的规则也不会满足最小可信度要求。可以利用关联规则的上述性质属性来减少需要测试的规则数目,类似于Apriori算法求解频繁项集。

图

Java代码实现

package testApriori;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.junit.runner.manipulation.Sortable;

public class Apriori {

    private final static int SUPPORT = 2; // 支持度阈值
    private final static double CONFIDENCE = 0.5; // 置信度阈值

    private final static String ITEM_SPLIT = ";"; // 项之间的分隔符
    private final static String CON = "->"; // 项之间的分隔符

    private final static List<String> transList = new ArrayList<String>(); // 所有交易

    static {// 初始化交易记录
        transList.add("1;2;5;");
        transList.add("2;4;");
        transList.add("2;3;");
        transList.add("1;2;4;");
        transList.add("1;3;");
        transList.add("2;3;");
        transList.add("1;3;");
        transList.add("1;2;3;5;");
        transList.add("1;2;3;");
    }

    public Map<String, Integer> getFC() {
        Map<String, Integer> frequentCollectionMap = new HashMap<String, Integer>();// 所有的频繁集

        frequentCollectionMap.putAll(getItem1FC());

        Map<String, Integer> itemkFcMap = new HashMap<String, Integer>();
        itemkFcMap.putAll(getItem1FC());
        while (itemkFcMap != null && itemkFcMap.size() != 0) {
            Map<String, Integer> candidateCollection = getCandidateCollection(itemkFcMap);
            Set<String> ccKeySet = candidateCollection.keySet();

            // 对候选集项进行累加计数
            for (String trans : transList) {
                for (String candidate : ccKeySet) {
                    boolean flag = true;// 用来判断交易中是否出现该候选项,如果出现,计数加1
                    String[] candidateItems = candidate.split(ITEM_SPLIT);
                    for (String candidateItem : candidateItems) {
                        if (trans.indexOf(candidateItem + ITEM_SPLIT) == -1) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag) {
                        Integer count = candidateCollection.get(candidate);
                        candidateCollection.put(candidate, count + 1);
                    }
                }
            }

            // 从候选集中找到符合支持度的频繁集项
            itemkFcMap.clear();
            for (String candidate : ccKeySet) {
                if (candidateCollection.get(candidate) >= SUPPORT) {
                    itemkFcMap.put(candidate, candidateCollection.get(candidate));
                }
            }

            // 合并所有频繁集
            frequentCollectionMap.putAll(itemkFcMap);

        }

        return frequentCollectionMap;
    }

    private Map<String, Integer> getCandidateCollection(
            Map<String, Integer> itemkFcMap) {
        Map<String, Integer> candidateCollection = new HashMap<String, Integer>();
        Set<String> itemkSet1 = itemkFcMap.keySet();
        Set<String> itemkSet2 = itemkFcMap.keySet();

        for (String itemk1 : itemkSet1) {
            for (String itemk2 : itemkSet2) {
                // 进行连接
                String[] tmp1 = itemk1.split(ITEM_SPLIT);
                String[] tmp2 = itemk2.split(ITEM_SPLIT);

                String c = "";
                if (tmp1.length == 1) {
                    if (tmp1[0].compareTo(tmp2[0]) < 0) {
                        c = tmp1[0] + ITEM_SPLIT + tmp2[0] + ITEM_SPLIT;
                    }
                } else {
                    boolean flag = true;
                    for (int i = 0; i < tmp1.length - 1; i++) {
                        if (!tmp1[i].equals(tmp2[i])) {
                            flag = false;
                            break;
                        }
                    }
                    if (flag
                            && (tmp1[tmp1.length - 1]
                                    .compareTo(tmp2[tmp2.length - 1]) < 0)) {
                        c = itemk1 + tmp2[tmp2.length - 1] + ITEM_SPLIT;
                    }
                }

                // 进行剪枝
                boolean hasInfrequentSubSet = false;
                if (!c.equals("")) {
                    String[] tmpC = c.split(ITEM_SPLIT);
                    for (int i = 0; i < tmpC.length; i++) {
                        String subC = "";
                        for (int j = 0; j < tmpC.length; j++) {
                            if (i != j) {
                                subC = subC + tmpC[j] + ITEM_SPLIT;
                            }
                        }
                        if (itemkFcMap.get(subC) == null) {
                            hasInfrequentSubSet = true;
                            break;
                        }
                    }
                } else {
                    hasInfrequentSubSet = true;
                }

                if (!hasInfrequentSubSet) {
                    candidateCollection.put(c, 0);
                }
            }
        }

        return candidateCollection;
    }

    private Map<String, Integer> getItem1FC() {
        Map<String, Integer> sItem1FcMap = new HashMap<String, Integer>();
        Map<String, Integer> rItem1FcMap = new HashMap<String, Integer>();// 频繁1项集

        for (String trans : transList) {
            String[] items = trans.split(ITEM_SPLIT);
            for (String item : items) {
                Integer count = sItem1FcMap.get(item + ITEM_SPLIT);
                if (count == null) {
                    sItem1FcMap.put(item + ITEM_SPLIT, 1);
                } else {
                    sItem1FcMap.put(item + ITEM_SPLIT, count + 1);
                }
            }
        }

        Set<String> keySet = sItem1FcMap.keySet();
        for (String key : keySet) {
            Integer count = sItem1FcMap.get(key);
            if (count >= SUPPORT) {
                rItem1FcMap.put(key, count);
            }
        }
        return rItem1FcMap;
    }

    public Map<String, Double> getRelationRules(
            Map<String, Integer> frequentCollectionMap) {
        Map<String, Double> relationRules = new HashMap<String, Double>();
        Set<String> keySet = frequentCollectionMap.keySet();
        for (String key : keySet) {

            double countAll = frequentCollectionMap.get(key);
            String[] keyItems = key.split(ITEM_SPLIT);
            if (keyItems.length > 1) {
                List<String> source = new ArrayList<String>();
                Collections.addAll(source, keyItems);
                List<List<String>> result = new ArrayList<List<String>>();

                buildSubSet(source, result);// 获得source的所有非空子集

                System.out.println("----------\n"+source.toString()+"\n"+result.toString()+"\n-----------------\n");
                for (List<String> resultItemList : result) {
                    if (resultItemList.size() < source.size()) {// 只处理真子集
                        List<String> otherList = new ArrayList<String>();
                        for (String sourceItem : source) {
                            if (!resultItemList.contains(sourceItem)) {
                                otherList.add(sourceItem);
                            }
                        }
                        String reasonStr = "";// 前置
                        String resultStr = "";// 结果
                        for (String item : resultItemList) {
                            reasonStr = reasonStr + item + ITEM_SPLIT;
                        }
                        for (String item : otherList) {
                            resultStr = resultStr + item + ITEM_SPLIT;
                        }

                        double countReason = frequentCollectionMap
                                .get(reasonStr);
                        double itemConfidence = countAll / countReason;// 计算置信度
                        if (itemConfidence >= CONFIDENCE) {
                            String rule = reasonStr + CON + resultStr;
                            relationRules.put(rule, itemConfidence);
                        }
                    }
                }
            }
        }

        return relationRules;
    }

    private void buildSubSet(List<String> sourceSet, List<List<String>> result) {
        // 仅有一个元素时,递归终止。此时非空子集仅为其自身,所以直接添加到result中
        if (sourceSet.size() == 1) {
            List<String> set = new ArrayList<String>();
            set.add(sourceSet.get(0));
            result.add(set);
        } else if (sourceSet.size() > 1) {
            // 当有n个元素时,递归求出前n-1个子集,在于result中
            buildSubSet(sourceSet.subList(0, sourceSet.size() - 1), result);
            int size = result.size();// 求出此时result的长度,用于后面的追加第n个元素时计数
            // 把第n个元素加入到集合中
            List<String> single = new ArrayList<String>();
            single.add(sourceSet.get(sourceSet.size() - 1));
            result.add(single);
            // 在保留前面的n-1子集的情况下,把第n个元素分别加到前n个子集中,并把新的集加入到result中;
            // 为保留原有n-1的子集,所以需要先对其进行复制
            List<String> clone;
            for (int i = 0; i < size; i++) {
                clone = new ArrayList<String>();
                for (String str : result.get(i)) {
                    clone.add(str);
                }
                clone.add(sourceSet.get(sourceSet.size() - 1));

                result.add(clone);
            }
        }
    }

    public static void main(String[] args) {
        Apriori apriori = new Apriori();
        Map<String, Integer> frequentCollectionMap = apriori.getFC();
        System.out.println("----------------频繁集" + "----------------");
        Set<String> fcKeySet = frequentCollectionMap.keySet();
        for (String fcKey : fcKeySet) {
            System.out.println(fcKey + "  :  "
                    + frequentCollectionMap.get(fcKey));
        }
        Map<String, Double> relationRulesMap = apriori
                .getRelationRules(frequentCollectionMap);
        System.out.println("----------------关联规则" + "----------------");
        Set<String> rrKeySet = relationRulesMap.keySet();
        for (String rrKey : rrKeySet) {
            System.out.println(rrKey + "  :  " + relationRulesMap.get(rrKey));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值