数据挖掘 apriori算法

这个算法是数据挖掘的经典算法,而且写起来并不麻烦,我是apriori的详解~

这个算法是我们数据结构老师让我们编的,事物集达到了88000多条,第一次验证xcode读txt还是蛮简单的哈哈哈哈哈哈哈哈~( ̄▽ ̄)~

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
using namespace std;

struct L   //频繁项集存储的结构体
{
    int itemm[100];  //每次求n项频繁项集时都会刷新一遍l,这个数组存放的是n项集里的每个项
    int itemm_num;  //存放n项集的n,有点麻烦了
}L[90000];

struct C  //候选项集存储结构体
//每次求n项候选项集时会刷新c
{
    int itemmm[100];  //每次求n项候选项集时,每个n项候选项存放在这里,编号从0到n-1
    int itemmm_num;
}C[90000];

struct RowFromTxt   //存放资料的结构题,一行用一个结构体存储,一行里的每个数据存在item的数组里
{
    int item[1000];
    int alldatafromtxt[17000]={0};  //为了查找方便特意安排一个数组,数字最大不超过17000,所以可以存放一行里每个数字出现过几遍
    int item_num;  //存放一行里几个数字
}RowFromTxt[90000];

double AllDataFromTxt[17000]={0};   //所有数字出现的频率,计算频繁一项集时会用
int RowNumTxt=0;  //资料里一共有多少行
double support;    //支持度,在程序里自定的,可以改,不要小于0.005~
//int c_num[100];

int change_row(char row_string[],int row_num)
{
    char row_end[]=" \n";
    char *new_row;
    new_row=strtok(row_string, row_end);
    int row_item_num=0;
    int item;
    while (new_row!=NULL) {
        row_item_num++;
        item=atoi(new_row);
        AllDataFromTxt[item]+=1.0000;
        RowFromTxt[row_num].item[row_item_num]=item;
        RowFromTxt[row_num].alldatafromtxt[item]++;
        new_row=strtok(NULL, row_end);
        if (new_row==NULL) {
            break;
        }
    }
    RowFromTxt[row_num].item_num=row_item_num;
    return 0;
}

int GetCnplus1(int Cplus1EachStructNum,int LTotalStructNum)   //得到n+1项的候选项集
{
    int i,j,m;
    cout<<"候选"<<Cplus1EachStructNum<<"项集为:"<<endl;
    int Cplus1TotalStructNum=0;
    for (i=1; i<=LTotalStructNum; i++) {   //和其他频繁项对比,如果前n-1项一样,则其他频繁项合起来存进新的候选项
        for (j=i+1; j<=LTotalStructNum; j++) {
            int flag=1;
            for (m=0; m<Cplus1EachStructNum-2; m++) {
                if (L[i].itemm[m]!=L[j].itemm[m]) {
                    flag=0;
                    break;
                }
            }
            if (flag==0) {
                continue;
            }
            if (flag==1) {        //合并两个n项频繁项,存进n+1的频繁项集
                Cplus1TotalStructNum++;
                C[Cplus1TotalStructNum].itemmm_num=Cplus1EachStructNum;
                for (m=0; m<Cplus1EachStructNum-1; m++) {
                    C[Cplus1TotalStructNum].itemmm[m]=L[i].itemm[m];
                }
                C[Cplus1TotalStructNum].itemmm[m]=L[j].itemm[m-1];
            }
        }
    }
    for (i=1; i<=Cplus1TotalStructNum; i++) {
        for (j=0; j<Cplus1EachStructNum; j++) {
            cout<<C[i].itemmm[j]<<" ";
        }
        cout<<"   ";
    }
    cout<<endl;
    cout<<"共"<<Cplus1TotalStructNum<<"项"<<endl;
    return Cplus1TotalStructNum;
}


int apriori(int ThisCRowTotalStructNum,int ThisCEveryRowDataNumber)   //高能!!!
{
    int i,j,m,n;
    int count=0;
    cout<<"频繁"<<C[1].itemmm_num<<"项集有:"<<endl;   //频繁n项集有……
    for (i=1; i<ThisCRowTotalStructNum; i++) {   //所有频繁候选n项集的总项数
        double show=0;                           //每一项里每个数字在资料里每一行出现的个数统计
        
        for (j=1; j<RowNumTxt; j++) {     //资料里总的行数,全局变量
            int flag=1;
            for (m=0; m<C[i].itemmm_num; m++) {    //一个n项集里每个数是否在资料里的第j行存在?
                if (RowFromTxt[j].alldatafromtxt[C[i].itemmm[m]]==0) {
                    flag=0;         //不存在退出
                    break;
                }
            }
            if (flag==1) {    //存在说明这一行可以统计,事物里有这个项
                show+=1.00;
            }
        }
        if (show/RowNumTxt>=support) {         //如果出现次数除以总的事物rownumtxt大于支持度,那就是频繁项啦~
            for (n=0; n<C[1].itemmm_num; n++) {
                cout<<C[i].itemmm[n]<<" ";   //输出看看~~
            }
            cout<<"    ";
            count++;
            for (m=0; m<C[i].itemmm_num; m++) {
                L[count].itemm[m]=C[i].itemmm[m];   //把这个候选项一个一个存进l
            }
        }
    }
    cout<<endl;
    cout<<"共"<<count<<"项"<<endl;
    
    if (count==1||count==0) {       //如果频繁项只有一个或没有的话,挖掘就结束了
        return 0;
    }
    
    int Cplus1TotalstructNum=GetCnplus1(C[1].itemmm_num+1, count);  //如果没有结束的话继续得到n+1项的候选项
    if(apriori(Cplus1TotalstructNum , C[1].itemmm_num+1)==0)  //计算n+1项的频繁项
        return 0;
    return 0;
}

int main(int argc, const char * argv[])
{
    freopen("/Users/gray/Documents/数据挖掘/数据挖掘课程资料大全/retail副本.txt", "r", stdin);  //打开并读取文件
    char row_string[1000];   //每行字符串
    while (gets(row_string)) {
        RowNumTxt++;
        change_row(row_string, RowNumTxt);
        memset(row_string, 0, sizeof(1000));
    }
    support=0.0113;      //定义支持度0.01
    int i,j;
    int l_num=1;       //开始计算频繁一项集
    for (i=0; i<17000; i++) {
        if (AllDataFromTxt[i]/RowNumTxt>=support) {   //alldatafromtxt在changerow函数里记录了每个数字出现的次数们可以直接用
            L[l_num].itemm[0]=i;   //讲频繁一项集存入l(其实可以直接存入c用作频繁二项集候选项)
            L[l_num].itemm_num=1;   //此l的频繁n项集,n为1
            l_num++;    //频繁1项集的总数
        }
    }
    cout<<"频繁1项集有:"<<endl;
    for (i=1; i<l_num; i++) {
        cout<<L[i].itemm[0]<<" ";
        cout<<AllDataFromTxt[L[i].itemm[0]]<<endl;
    }
    //cout<<endl;
    //c_num[1]=l_num-1;    //频繁候选2项集的
    int l2_num=1;   //统计频繁候选二项集,其实叫c2_num更合适
    for (i=1; i<l_num; i++) {       //得到频繁候选二项集,存入结构体
        for (j=i+1; j<l_num; j++) {
            C[l2_num].itemmm[0]=L[i].itemm[0];
            C[l2_num].itemmm[1]=L[j].itemm[0];
            C[l2_num].itemmm_num=2;
            l2_num++;
        }
    }
    //准备工作完成,开始各种候选
    apriori(l2_num, 2);  //输入频繁候选二项集的个数,和频繁候选二项集里每个项集的个数,就是2
    return 0;
}

事物都是数字,可以直接改字符型……

点赞