首页 > 代码库 > Apriori算法及其代码

Apriori算法及其代码

Apriori算法是一个容易理解,逻辑简单,代码容易编写的一个大数据频繁项集查找的算法。



设最小支持度计数为3  即个数要大于等于3的才是频繁项


如图1--原始数据库                  计数得到图2--每个东西的个数            则得到图3的频繁一项

                                                           

图1                                                图2                                                  图3


由频繁一项集两两配对得到候选项集合{A,B},{A,E},{B,E}

扫面原始数据库,即图1

{A,B}2个,{A,E}3个,{B,E}1个,所以得到频繁二项集{A,E}。由于此时二项集只剩下一个了,所以无法产生三项集,故程序结束。



看如下图所示程序流程图:


图5(图片来源于网络,仅供学习参考)



C++代码:完整说明以及大数据测试数据可以从这里下载http://download.csdn.net/download/my_acm/8042909

本程序为了简单编程使用直接把原始数据读入内存中,所以不能处理非常大的数据,而正真的apriori算法处理超大规模数据时会一遍一遍的从数据库中读取数据。这也是为什么apriori算法效率不高的原因之一。

/*
    function: apriori算法查找频繁集
    authour:
    date: 
    Code::Blocks 12.11下运行通过
*/
#include<vector>
#include<iostream>
#include<cstring>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<map>
using namespace std;

#define maxn 100000
#define maxItem 90
#define suport 0.01     //最小支持度
struct Item{
    vector <int> num;
};
typedef vector <int> i_list;

class Apriori{
public:
    int suport_num;        //最小支持度计数
    int num_max;           //单行最大数量
    int num_sol;           //交易条数
    int num_fre;           //频繁项种类的数量
    Item item[maxn];       //初始交易信息
    vector <i_list> fre_item[maxn];   //保存所有频繁项信息,fre_item[i]表示频繁i项信息
    map <int,int> list_item;         //标记某一个项目序号的总数
public:
    void init(){
        num_fre=0;
        num_max=0;
        suport_num=0;
        num_sol=0;
    }
    void input(){                        //输入,初始化交易信息
        char str[3000];
        int t=0;
        while(gets(str)){     //按行逐个读入数据
            char *f;
            f=strtok(str," ");
            while(f){
                int x;
                x=atoi(f);
                list_item[x]++;      //商品计数
                item[t].num.push_back(x);
                f=strtok(NULL," ");
            }
            if(item[t].num.size()>num_max)
                    num_max=item[t].num.size();
            t++;
        }
        num_sol=t;

        for(int i=0;i<num_sol;i++){
            sort(item[i].num.begin(),item[i].num.end());      //交易项目序号从小到大排列
        }
        suport_num=ceil(suport*num_sol);         //最小支持度计数
        cout<<"数据总行数: "<<num_sol<<" 最小支持度"<<suport<<" 最小支持度计数: "<<suport_num<<endl;
//        for(int i=0;i<num_sol;i++){
//            int len=item[i].num.size();
//            for(int j=0;j<len;j++){
//                printf("%d ",item[i].num[j]);
//            }
//            printf("\n");
//        }
    }
    void output(){                  //输出频繁项集
        if(!fre_item[1].size()){
            printf("no frequent item!\n");
            return ;
        }
        for(int k=1;k<=num_fre;k++){
            printf("%d frequent item is:\n",k);
            for(int i=0;i<fre_item[k].size();i++){
                for(int j=0;j<fre_item[k][i].size();j++){
                    printf("%d ",fre_item[k][i][j]);
                }
                printf("\n");
            }
            printf("\n");
        }
    }
    void LCS(i_list &tmp,i_list &t1,i_list &t2){//匹配最长公共子序列
        int len=t1.size();
        int sucess=1;
        for(int i=0;i<len-1;i++){
            if(t1[i]!=t2[i]){
                sucess=0;
                break;
            }
        }
        if(t1[len-1]==t2[len-1])
            sucess=0;
        if(sucess){
            tmp=t1;
            tmp.push_back(t2[len-1]);
        }
    }
    int judge(i_list tmp){              //判断tmp是否是频繁项
        int len=tmp.size();
        int sum=0;
        int sucess=1;
        for(int i=0;i<num_sol;i++){         //遍历所有原始数据
            sucess=1;
            if(item[i].num.size()<len)
                continue;
            for(int k=0;k<len;k++){
                int j;
                int tlen=item[i].num.size();
                for(j=0;j<tlen;j++){
                    if(tmp[k]==item[i].num[j])
                        break;
                }
                if(j>=tlen){
                    sucess=0;
                    break;
                }
            }
            if(sucess)
                sum++;
        }
        if(sum>=suport_num)            //大于等于最小支持度则是频繁项
            return 1;
        return 0;                //不是频繁项
    }
    void find_fre_item(){          //找出所有频繁项
        for(map <int,int>::iterator it=list_item.begin();it!=list_item.end();it++){   //找出所有的频繁一项
            if(it->second>=suport_num){
                i_list tmp;
                tmp.push_back(it->first);
                fre_item[1].push_back(tmp);
            }
        }
        list_item.clear();       //释放lisg_item
        if(0==fre_item[1].size())
            return ;
        if(1==fre_item[1].size()){
            num_fre=1;
            return ;
        }

        int len=num_max;
        for(int k=2;k<=len;k++){                   //找出所有二项以后的频繁项集
            //枚举k-1项的所有单项的数据,进行LCS匹配,得到k频繁项
            if(fre_item[k-1].size()>=2)
            for(int i=0;i<fre_item[k-1].size();i++){
                for(int j=i+1;j<fre_item[k-1].size();j++){

                    i_list tmp; tmp.clear();

                    LCS(tmp,fre_item[k-1][i],fre_item[k-1][j]);
                    if(!tmp.size())
                        continue;
                    if(judge(tmp)){
                        fre_item[k].push_back(tmp);
                        num_fre=k;
                    }
                }
            }
        }
    }
    void calculate_fre_item(){   //频繁项计算
        init();
        input();
        find_fre_item();
        output();
    }
}sol;
int main(){
    freopen("retail.dat","r",stdin);
    freopen("result.txt","w",stdout);
    sol.calculate_fre_item();
    return 0;
}


Apriori算法及其代码