说起来数据挖掘这门课我还是蛮喜欢的,所以实验内容也都是自己实现的,第一个Apriori算法,思想很简单,什么都没有就是暴力,我加了一个Hash,总共也才写了100来行,具体内容代码注释中很清楚我就不多说了。以下附上主要函数的代码(省去部分)。
主要的东西呢就是把所有的事务映射成一个数字然后直接用string存储。好吧我承认我在偷懒,这个方法是有问题的,事务多了之后会出现歧义。会有错误。但是我不想改了hhhh让我当一条咸鱼吧。
#include <cstdio>
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
using namespace std;
const int maxn = 105;///最大记录条数
int n;///记录条数
int min_sup;///最小支持度
bool flag;///产生新集的标记
map<string, int> m;///将项名Hash后存储
map<int, string> mp;///逆Hash
set<int> D[maxn];///事务数据库
set<string> fre;///频繁项集的集合(每个string存储一个频繁项集)
set<string> cand;///候选项集的集合(每个string存储一个候选项集)
char name[maxn];
string t;
int cnt, x;
///利用先验性质的剪枝
bool check(){
string s;///获取候选项的子集
for(int i = 0;i < t.size();i ++){
s = t;
s.erase(i, 1);
if(!fre.count(s)) return false;///验证失败
}
return true;///验证成功
}
///获取候选项集
void get_cand(int num){
cand.clear();
for(set<string>::iterator i = fre.begin();i != fre.end();i ++)
for(set<string>::iterator j = fre.begin();j != fre.end();j ++){
t = *i;
///去重合并
for(int k = 0;k < (*j).size();k ++)
if(t.find((*j)[k]) == string::npos) t += (*j)[k];
sort(t.begin(), t.end());
if(t.size() != num) continue;
if(check()) cand.insert(t);///剪枝
}
return;
}
///支持度计数,获取频繁项集
bool get_fre(int num){
set<string> tfre;
for(set<string>::iterator i = cand.begin();i != cand.end();i ++){
t = *i;
int sum = 0;
for(int j = 0;j < n;j ++){
bool f1 = true;
///判断是否所有项都存在
for(int k = 0;k < t.size();k ++)
if(!D[j].count(t[k] - 48)) {
f1 = false;
break;
}
if(f1) sum ++;///计数+
}
if(sum >= min_sup) tfre.insert(t);///满足最小支持度
}
if(tfre.size() == 0) return false;
fre = tfre;
return true;
}
int main(){
//freopen("ap.txt", "r", stdin);
printf("记录条数:");
while(~scanf("%d", &n)){
m.clear();
cnt = 0;
for(int i = 0;i < n;i ++){
scanf("%d", &x);
while(x --){
scanf("%s", name);
t = name;
//利用Map的Hash部分和插入事务数据库部分省略...
}
}
printf("最小支持度:");
scanf("%d", &min_sup);
///获得频繁1项集
for(int i = 0;i < cnt;i ++){
int sum = 0;
for(int j = 0;j < n;j ++)
if(D[j].count(i)) sum ++;
if(sum >= min_sup) {///计数完毕,满足最小支持度
t = i + 48;
fre.insert(t);
}
}
flag = true;
int num = 1;///候选项数
while(flag){
flag = false;
get_cand(++ num);///获取候选项集
if(get_fre(num))///获取频繁项集,空集返回false
flag = true;
}
printf("最大项数:%d\n", num - 1);
for(set<string>::iterator i = fre.begin();i != fre.end();i ++){
printf("{");
for(int j = 0;j < (*i).size();j ++)
printf("%s%c", mp[(*i)[j] - 48].c_str(), j + 1 == (*i).size()?'}':',');
printf("\n");
}
}
return 0;
}