Apriori算法学习心得
来源:互联网 发布:如何找到监控软件 编辑:程序博客网 时间:2024/05/21 09:39
Apriori算法是我在数据挖掘方面接触的第一个算法,一直只知道他的大体步骤,对具体细节和代码实现知道的不是很清楚,最近有点时间就重新复习了这个算法。
首先复习一下Apriori算法的基本思路:Apriori算法的基本过程是:扫描一遍数据库,得到一阶频繁项;用一阶频繁项构造二阶候选项;扫描数据库对二阶候选项进行计数,删除其中的非频繁项,得到二阶频繁项;然后构造三阶候选项,以此类推,直到无法构造更高阶的候选项,或到达频繁项集的最大长度限制。其中,Apriori算法利用这样一条性质:任一频繁项集的所有非空子集也必须是频繁的。因为假如P(I)< 最小支持度阈值,当有元素A添加到I中时,结果项集(A∩I)不可能比I出现次数更多,因此A∩I也不是频繁的。
Apriori算法采用连接步和剪枝步两种方式来找出所有的频繁项集。
1) 连接步
为找出Lk(所有的频繁k项集的集合),通过将Lk-1(所有的频繁k-1项集的集合)与自身连接产生候选k项集的集合。候选集合记作Ck。设l1和l2是Lk-1中的成员。记li[j]表示li中的第j项。假设Apriori算法对事务或项集中的项按字典次序排序,即对于(k-1)项集li,li[1]<li[2]<……….<li[k-1]。将Lk-1与自身连接,如果(l1[1]=l2[1])&&( l1[2]=l2[2])&&……..&& (l1[k-2]=l2[k-2])&&(l1[k-1]<l2[k-1]),那认为l1和l2是可连接。连接l1和l2 产生的结果是{l1[1],l1[2],……,l1[k-1],l2[k-1]}。
2) 剪枝步
CK是LK的超集,也就是说,CK的成员可能是也可能不是频繁的。通过扫描所有的事务(交易),确定CK中每个候选的计数,判断是否小于最小支持度计数,如果不是,则认为该候选是频繁的。为了压缩Ck,可以利用Apriori性质:任一频繁项集的所有非空子集也必须是频繁的,反之,如果某个候选的非空子集不是频繁的,那么该候选肯定不是频繁的,从而可以将其从CK中删除。
感觉只看原理很难真正的理解算法,下面是C++的代码实现:
// Struct.h文件#ifndef STRUCT_H#define STRUCT_H#include <string>#include <vector>#include <algorithm>using namespace std;struct Item{ string key; int value;};struct MutiItem{ vector<string> key; int value;};#endif
//Compare.h 文件#ifndef COMPARE_H#define COMPARE_H#include "Struct.h"MutiItem mutiTemp;bool unaryPred(MutiItem &item){ vector<string> vec1=mutiTemp.key; vector<string> vec2=item.key; int count=0; for(vector<string>::const_iterator iter=vec2.begin();iter!=vec2.end();++iter) { if(find(vec1.begin(),vec1.end(),*iter)<vec1.end()) ++count; } return count==vec1.size();}#endif
//Apriori.h 文件#ifndef APRIORI_H#define APRIORI_H#include "Struct.h"#include <fstream>#include <map>#include <iostream>#include <algorithm>#include <string>using namespace std;class Apriori{private: int Min_support;//最小支持度 vector<string> vec_str;//保存从文件中读取的字符串 map<string,int> map_str_int;//一项备选集 vector<Item> vec_item;//一项频繁集 vector<MutiItem> vec_mutiItem_pre;//高项备选集 vector<MutiItem> vec_mutiItem;//高项频繁集public: Apriori(void); ~Apriori(void); //从文件中读取每一行字符串存入向量vec_str中 void ReadFile(ifstream &infile, const string &filename, const char &separator='\\'); //统计一项备选集支持度 void CountWord(const char &separator='\\'); //生成一项频繁集 void Generate_1ItemSets(); //生成二项频繁项备选集 void GenerateAlternative2(); //生成高项频繁项备选集 void GenerateAlternative(); //统计备选集支持度 void CountSupport(); //生成高项频繁集 void Generate_ItemSets(); //生成所有项频繁集 void Generate_AllItemSets(ostream &outfile); //输出一项频繁集到文件中 void Ouput1(ostream &outfile); //输出高项频繁集到文件中 void Ouput(ostream &outfile);};#endif
// apriori.cpp 文件#include "Apriori.h"#include "Compare.h"Apriori::Apriori(void){ this->Min_support=5;//默认最小支持度}Apriori::~Apriori(void){}//从文件中读取每一行字符串存入向量vec_str中void Apriori::ReadFile(std::ifstream &infile, const std::string &filename, const char &separator){ infile.open(filename.c_str());//打开文件 if(!infile) { cout<<"Open file failed!"<<endl; exit(1); } string word; while(getline(infile,word))//每次从文件中读取一行字符串存入word中 this->vec_str.push_back(word);//在vec_str的末尾增加一个值为word的元素。 infile.close();}//统计一项备选集支持度void Apriori::CountWord(const char &separator){ string sentence,word; for(vector<string>::const_iterator iter=this->vec_str.begin();iter!=this->vec_str.end();++iter) { sentence=*iter;//取出一行字符串 //分隔词语 while(sentence.find(separator) != -1) { word=sentence.substr(0, sentence.find(separator)); ++this->map_str_int[word]; sentence=sentence.substr(sentence.find(separator)+1, sentence.size()-1); } ++this->map_str_int[sentence]; }}//生成一项频繁集void Apriori::Generate_1ItemSets() { Item item; for(map<string,int>::const_iterator iter=this->map_str_int.begin();iter!=this->map_str_int.end();++iter) { //挑选支持度大于等于最小支持度的项 if(iter->second >= this->Min_support) { item.key=iter->first; item.value=iter->second; this->vec_item.push_back(item); } }}//生成二项频繁项备选集void Apriori::GenerateAlternative2(){ vector<string> vecTemp; for(vector<Item>::const_iterator iter=this->vec_item.begin();iter!=this->vec_item.end()-1;++iter) { vecTemp.push_back(iter->key); for(vector<Item>::const_iterator iter2=iter+1;iter2!=this->vec_item.end();++iter2) { vecTemp.push_back(iter2->key); mutiTemp.key=vecTemp; mutiTemp.value=0; this->vec_mutiItem_pre.push_back(mutiTemp);//添加到二项频繁项备选集 vecTemp.pop_back(); } vecTemp.clear(); }}//生成高项频繁项备选集void Apriori::GenerateAlternative(){ vector<string> vecTemp;//低项频繁项元素 int count; vector<string>::const_iterator iterTemp; this->vec_mutiItem_pre.clear();//将备选集清空 for(vector<MutiItem>::const_iterator iter=this->vec_mutiItem.begin();iter!=this->vec_mutiItem.end()-1;++iter) { vecTemp=iter->key; for(vector<MutiItem>::const_iterator iter2=iter+1;iter2!=this->vec_mutiItem.end();++iter2) { count=0; for(vector<string>::const_iterator iter3=iter2->key.begin();iter3!=iter2->key.end();++iter3) if(find(vecTemp.begin(),vecTemp.end(),*iter3)==vecTemp.end()) { ++count; iterTemp=iter3; } if(count!=1)//判断两个频繁项是否只有一个元素不相等 continue; vecTemp.push_back(*iterTemp); mutiTemp.key=vecTemp; mutiTemp.value=0; //判断备选集中是否已有此元素 if(count_if(this->vec_mutiItem_pre.begin(),this->vec_mutiItem_pre.end(),unaryPred)==0) this->vec_mutiItem_pre.push_back(mutiTemp); vecTemp.pop_back(); } vecTemp.clear(); }}//统计备选集支持度void Apriori::CountSupport(){ bool flag; //迭代行字符串 for(vector<string>::const_iterator iter=this->vec_str.begin();iter!=this->vec_str.end();++iter) { //迭代备选集元素 for(vector<MutiItem>::iterator iter2=this->vec_mutiItem_pre.begin();iter2!=this->vec_mutiItem_pre.end();++iter2) { flag=true; for(vector<string>::const_iterator iter3=iter2->key.begin();iter3!=iter2->key.end();++iter3) { if(iter->find(*iter3)==-1) { flag=false; break; } } if(flag==true) ++iter2->value; } }}//生成高项频繁集void Apriori::Generate_ItemSets(){ this->vec_mutiItem.clear(); for(vector<MutiItem>::const_iterator iter=this->vec_mutiItem_pre.begin();iter!=this->vec_mutiItem_pre.end();++iter) { if(iter->value >= this->Min_support) this->vec_mutiItem.push_back(*iter); }}//生成所有项频繁集void Apriori::Generate_AllItemSets(ostream &outfile){ //生成一项频繁集 this->CountWord(); this->Generate_1ItemSets(); this->Ouput1(outfile); //生成二项频繁项集 this->GenerateAlternative2(); this->CountSupport(); this->Generate_ItemSets(); this->Ouput(outfile); //循环生成高项频繁集 while(1) { this->GenerateAlternative(); this->CountSupport(); this->Generate_ItemSets(); if(this->vec_mutiItem.size()==0) return; this->Ouput(outfile); }}//输出一项频繁集到文件中void Apriori::Ouput1(ostream &outfile){ for(vector<Item>::const_iterator iter=this->vec_item.begin();iter!=this->vec_item.end();++iter) { outfile<<iter->key<<":\t"<<iter->value<<endl; } outfile<<endl;}//输出高项频繁集到文件中void Apriori::Ouput(ostream &outfile){ for(vector<MutiItem>::const_iterator iter=this->vec_mutiItem.begin();iter!=this->vec_mutiItem.end();++iter) { vector<string>::const_iterator iter2=iter->key.begin(); for(;iter2!=iter->key.end()-1;++iter2) outfile<<*iter2<<"&"; outfile<<*iter2<<":\t"<<iter->value<<endl; } outfile<<endl;}
// main.cpp 文件#include "apriori.h"void main(){ Apriori ob; ifstream infile; //读取数据集 ob.ReadFile(infile,"in.txt"); ofstream outfile; outfile.open("out.txt"); //生成所有项频繁集 ob.Generate_AllItemSets(outfile); outfile.close(); cout<<"Accomplish!"<<endl;}
程序输入:in.txt亲爱\的\你慢慢飞小心\前面\带刺\的\玫瑰亲爱\的\你\张张嘴风中\花香\会\让\你\沉醉亲爱\的\你\跟我飞穿过\丛林\去\看\小溪水亲爱\的\来\跳个舞爱\的\春天\不会\有\天黑我\和\你\缠缠绵绵\翩翩飞飞跃\这\红尘\永相随追逐\你\一生爱恋\我\千回不\辜负\我\的\柔情你\的\美我\和\你\缠缠绵绵\翩翩飞飞跃\这\红尘\永相随等到\秋风尽\秋叶\落成堆能\陪\你\一起\枯萎\也\无悔亲爱\的\你\慢慢飞小心\前面\带刺\的\玫瑰亲爱\的\你\张张嘴风中\花香\会\让\你沉醉亲爱\的\你\跟我飞穿过\丛林\去\看\小溪水亲爱\的\来\跳个舞爱\的\春天\不会\有\天黑我\和\你\缠缠绵绵\翩翩飞飞跃\这\红尘\永相随追逐\你\一生\爱恋\我\千回不\辜负\我\的\柔情你\的\美我\和\你\缠缠\绵绵\翩翩飞飞跃\这\红尘\永\相随等到\秋风尽\秋叶\落成堆能\陪\你\一起枯萎\也\无悔我\和\你\缠缠绵绵\翩翩飞飞跃\这\红尘\永相随等到\秋风尽\秋叶\落成堆能\陪\你\一起\枯萎\也\无悔等到\秋风尽\秋叶\落成堆能\陪\你\一起\枯萎\也\无悔
程序输出:out.txt的:16飞跃:5和:5红尘:5你:17亲爱:8我:9这:5翩翩飞:5的&你:8的&亲爱:8飞跃&红尘:5飞跃&这:5和&你:5和&我:5和&翩翩飞:5红尘&这:5你&亲爱:6你&我:10你&翩翩飞:5我&翩翩飞:5的&你&亲爱:6飞跃&红尘&这:5和&你&我:5和&你&翩翩飞:5和&我&翩翩飞:5你&我&翩翩飞:5和&你&我&翩翩飞:5
仔细研究一下这个代码会发现里面没有剪枝步啊,是,这里面为了程序便于理解,略去了剪枝步,直接用支持度来判断是否满足支持度要求,在剪枝步一般要利用数据结构哈希树提高效率,关于哈希树的知识以后再学吧,先去happy一下了。
- Apriori算法学习心得
- Apriori算法
- Apriori算法
- Apriori算法
- apriori 算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- Apriori算法
- ubuntu14.04中安装lamp
- 用Java实现简单的 O/R Mapping 模拟
- 导购网站的SEO优化
- 教你如何获取北京Google服务器ip
- 不同浏览器中使用 的差异
- Apriori算法学习心得
- javascript匿名函数的理解,js括号中括function 如(function(){})
- Cocos2d-x学习笔记(16)(常见22种特效)
- Windows SOCKET编程 2-----(面向连接的通信TCP)---客户端
- 输入法之核心词典构建
- android 网络编程:显示从网络获取的图片
- OpenGL ES着色器语言之变量和数据类型和着色器流程
- C# WinForm判断Win7下程序是否以管理员身份运行
- acm第一套 (2)