Apriori算法初使用

来源:互联网 发布:电气控制柜的设计软件 编辑:程序博客网 时间:2024/06/03 16:14

Apriori算法初使用

给定某超市购物篮数据库文件basketdata.xls,里面有18项商品的747条购买记录。取支持度阈值s =185,利用A-Priori算法提取其中的最大频繁项集Lk。
数据如下:
数据
每一行为一个购物篮数据。

1、数据读入

首先我们要定义一个数据集合类,将xls中的数据解析并读入内存

package com.cjq.Apriori;import java.io.File;import java.io.FileInputStream;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;//如下是解析xls文件所用到的一些包import org.apache.poi.hssf.usermodel.HSSFCell;import org.apache.poi.hssf.usermodel.HSSFRow;import org.apache.poi.hssf.usermodel.HSSFSheet;import org.apache.poi.hssf.usermodel.HSSFWorkbook;import org.apache.poi.poifs.filesystem.POIFSFileSystem;public class BasketData extends ArrayList<BasketItems>{    public BasketData(){        super();        initData();  //初始化数据    }    /**     * 从Excel文件中读取数据     */    private void initData(){        File file = null;        POIFSFileSystem poifsFileSystem = null;        HSSFWorkbook hssfWorkbook = null;        try{            file = new File("...\\basketdata.xls");//文件路径            poifsFileSystem = new POIFSFileSystem(new FileInputStream(file));            hssfWorkbook = new HSSFWorkbook(poifsFileSystem);        }catch(Exception ex){            System.err.println("文件读取出错");            System.exit(1);        }        HSSFSheet hssfSheet = hssfWorkbook.getSheetAt(0);        int rowstart = hssfSheet.getFirstRowNum();        int rowEnd = hssfSheet.getLastRowNum();        HSSFRow row;        HSSFCell cell;        BasketItems temp;        for (int i = 2; i <= rowEnd; i++) {            row = hssfSheet.getRow(i);            if (null == row)                continue;            int cellStart = row.getFirstCellNum();            int cellEnd = row.getLastCellNum();            temp = new BasketItems();            for (int k = 1; k <= cellEnd; k++) {                cell = row.getCell(k);                if (null == cell)                    continue;                temp.addCommodityByOrder(cell.getStringCellValue());            }            add(temp);        }    }}/** * @author 15656 * 每条购物篮的信息 */class BasketItems {    private boolean[] basketList = new boolean[18]; //每个购物篮最多18中物品    private int index = 0;    //购物信息逐个读入    public void addCommodityByOrder(String isExist) {        if ("T".equals(isExist))            basketList[index++] = true;        else            basketList[index++] = false;    }    public boolean isExist(int index){        return basketList[index];    }    public String toString(){        StringBuffer str = new StringBuffer();        for(boolean b:basketList)            str.append(b+"\t");        return "\n["+str.toString()+"]";    }}

测试:

import static org.junit.Assert.*;import org.junit.Before;import org.junit.Test;public class BasketDataTest {    @Test    public void testBasketData() {        System.out.println(new BasketData());    }}

运行结果
现在读入数据已经完成。

2、Apriori算法的编写

(1)apriori算法的流程图

流程图

首先生成候选一项集,利用阈值筛选出频繁一项集;将由频繁一项集通过组合生成候选二项集,再利用阈值筛选出频繁二项集;以此类推,直至无候选集产生或者无频繁项集产生,算法结束,最后得到的频繁项集则为最大频繁项集。

apriori算法代码如下:

    //阈值    private static int threshold = 185;    //购物篮集合    private static BasketData basketData = new BasketData();    /**     * 获取最大的频繁项集     * @param _basketData  购物篮集合     * @param itemsCount   购物篮物品种类数      * @return frequesntItems 最大的频繁项集     */    public static List getMaxFrequentItems(BasketData _basketData,int itemsCount){        basketData = _basketData;           List<List<Integer>> candidateItems  = new ArrayList();         List<List<Integer>> frequesntItems = null;         List<Integer> temp;        //初始化一项集        for(int i = 1;i<=itemsCount;i++){            temp = new ArrayList();            temp.add(i);            candidateItems .add(temp);        }        //apriori算法开始,最大频繁项集项数不大于物品种类数        for(int i = 1;i<=itemsCount;i++){            frequesntItems = getFrequentItems(candidateItems);    //筛选出频繁k项集                if(frequesntItems == null) break;            System.out.println("*******生成频繁项集********");                info(frequesntItems);            candidateItems  = getGroupItems(frequesntItems);   //组合成候选k+1项集            if(candidateItems  == null)  break;            System.out.println("*******生成候选集********");            info(candidateItems );        }           return frequesntItems;    }    //控制台打印项集    private static void info(List<List<Integer>> list){        if(list == null) return;        for(List<Integer> i:list)        System.out.println(i);      }

注意:
频繁项集、候选项集的类型。Integer代表物品的序号,用一个list的来放物品的序号代表一个k项,外面的list代表k项集。

getFrequentItems函数,通过阈值从候选k项集中筛选出频繁k项集,代码如下:

    /**     * 从候选集中生成频繁项集     * @param FrequentItems     * @return     */    private static List<List<Integer>> getFrequentItems(List<List<Integer>> candidateItems){        if(candidateItems == null)  return null;        List<List<Integer>> FrequesntItems = new ArrayList();        List<Integer> items;        for(int i = 0 ;i<candidateItems.size();i++){            items = candidateItems.get(i);            if(isFrequentItems(items)) FrequesntItems.add(items);        }        return FrequesntItems;      }    /**     * 判断一个项集是否为频繁项集     * @param basketData     * @param items     * @return     */    private static boolean isFrequentItems(List<Integer> items){        int count = itemsAppearCount(items);        if(count>=threshold) return true;        else return false;    }    /**     * 计算某项集出现的次数     * @param basketData     * @param items     * @return     */    public static int itemsAppearCount(List<Integer> items){        if(basketData==null||items==null) return 0;        int count = 0;        int size = basketData.size();        int j;        BasketItems basketItems;        boolean tag = true;        for(int i = 0;i<size;i++){            basketItems = basketData.get(i);            for(j = 0;j<items.size();j++){                if(!basketItems.isExist(items.get(j)-1)){                    tag = false;                    break;                }            }            if(tag){                count++;            }else                 tag = true;         }        return count;       }

getGroupItems函数,将频繁k项集组合成候选k+1项集,代码如下:

    /**     * 生成k+1候选集     * @param FrequentItems  k项频繁项集     * @return allgroupItems k+1候选集     */    private static List<List<Integer>> getGroupItems(List<List<Integer>> FrequentItems){        if(FrequentItems == null) return null;        int size = FrequentItems.size();         if(size < 2) return null;        List<List<Integer>> allgroupItems = new ArrayList();        List<Integer> groupItem = null;         for(int i = 0;i<size-1;i++){            for(int j = i+1;j<size;j++){                            groupItem = combin(FrequentItems.get(i),FrequentItems.get(j));                      if(groupItem!=null&&judgeSubsetIsExits(groupItem,FrequentItems))                allgroupItems.add(groupItem);            }        }        if(allgroupItems.size()==0) return null;        return allgroupItems;    }    /**     * 两个k项集合并为k+1项集     * @param item1     * @param item2     * @return groupItem     */    private static List<Integer> combin(List<Integer> item1,List<Integer> item2){        int size1 = item1.size();        int size2 = item2.size();        if(size1!=size2) return null;        List<Integer> groupItem =  new ArrayList();         int temp = 0;        for(int i = 0;i<size1-1;i++){            temp = item1.get(i);            if(temp!=item2.get(i)) return null;            else groupItem.add(temp);        }        groupItem.add(item1.get(size1-1));        groupItem.add(item2.get(size2-1));        return groupItem;    }    /**     * 判断k+1项集的所有k项子集是否存在     * @param groupItem  k+1项集     * @param FrequentItems  k项集集合     * @return result        */    private static boolean judgeSubsetIsExits(List<Integer> groupItem,List<List<Integer>> FrequentItems){        if(groupItem == null) return true;        int size = groupItem.size();        List<Integer> subset = null;        for(int i = 0;i<size;i++){            subset = new ArrayList();            for(int j = 0;j<size;j++){                if(j!=i) subset.add(groupItem.get(j));            }            if(!itemIsExitsInFrequentItems(subset,FrequentItems))  return false;        }           return true;            }    /**     * 判断一个项集是否在一个项集集合里     * @param groupItem     * @param FrequentItems     * @return result     */    private static boolean itemIsExitsInFrequentItems(List<Integer> groupItem,List<List<Integer>> FrequentItems){        int size = groupItem.size();        int j = 0;          List<Integer> temp = null;        boolean tag = true;        for(int i = 0;i<FrequentItems.size();i++){            temp = FrequentItems.get(i);            tag = true;            for(j=0;j<size;j++){                if(!temp.get(j).equals(groupItem.get(j))){                    tag = false;                    break;                }            }               if(tag) return true;        }               return false;       }

组合原则:
两个具有相同的k-1项的k项集才能组合成k+1项集,再由定理:频繁k+1项集的所有k项子集都是频繁项集。由这两个原则,先将具有相同的k-1项的k项集组合成k+1项集,再找出这个k+1项集的所有k项子集,判断这些k项子集是否都是频繁项集,如果都是,则将这个k+1项集加入候选集中,如果不是则去掉。

现在,已经完成了一个简单的Apriori算法。
下面进行测试:

package com.cjq.Apriori;import java.util.ArrayList;import java.util.List;import junit.framework.TestCase;public class Test extends TestCase {    @org.junit.Test    public void testBasketData() {        List<List<Integer>> FrequesntItems = APriori.getMaxFrequentItems(new BasketData(),18);        System.out.println("\n最大频繁项集");        System.out.println(FrequesntItems);    }}

运行结果:
*生成频繁项集**
[1]
[2]
[5]
[9]
[10]
[12]
[13]
[15]
[16]
[17]
*生成候选集**
[1, 2]
[1, 5]
[1, 9]
[1, 10]
[1, 12]
[1, 13]
[1, 15]
[1, 16]
[1, 17]
[2, 5]
[2, 9]
[2, 10]
[2, 12]
[2, 13]
[2, 15]
[2, 16]
[2, 17]
[5, 9]
[5, 10]
[5, 12]
[5, 13]
[5, 15]
[5, 16]
[5, 17]
[9, 10]
[9, 12]
[9, 13]
[9, 15]
[9, 16]
[9, 17]
[10, 12]
[10, 13]
[10, 15]
[10, 16]
[10, 17]
[12, 13]
[12, 15]
[12, 16]
[12, 17]
[13, 15]
[13, 16]
[13, 17]
[15, 16]
[15, 17]
[16, 17]
*生成频繁项集**
[1, 2]
[1, 5]
[1, 9]
[1, 10]
[1, 13]
[1, 15]
[1, 16]
[1, 17]
[5, 16]
[9, 16]
[10, 16]
[15, 16]
*生成候选集**
[1, 5, 16]
[1, 9, 16]
[1, 10, 16]
[1, 15, 16]
*生成频繁项集**
[1, 10, 16]
[1, 15, 16]

最大频繁项集
[[1, 10, 16], [1, 15, 16]]

经校验:结果正确。

原创粉丝点击