这个算法是数据挖掘的经典算法,而且写起来并不麻烦,我是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;
}
事物都是数字,可以直接改字符型……