Apriori算法的C++实现
Apriori是经典的购物篮分析算法。该算法用SQL实现难度较大,所以考虑用C++实现。
花了两天,代码例如以下。原创转载请注明出处
//Apriori.c
#include<iostream>
#include<set>
#include<map>
#include<string>
#include<vector>
using namespace std;
typedef map<set<string>,int> map_s; map_s Ck ;//候选集Ck
map_s Lk ; //频繁项集Lk
vector<set<string> > data; //原始数据
vector<set<string> > L; //频繁项集合
vector<string> data2; //切割后的原始数据
int n,m;
int minSup = 2;
int minConf = 0.2;
set<string> s;
string in;
void Delete(map_s &Ck)
{
for( map_s::iterator l_it=Ck.begin();l_it!=Ck.end();l_it++ )
{
if( l_it->second< minSup)
{
Ck.erase(l_it);
}
}
} int compset(set<string> s1,set<string> s2)
{
int flag=0;
//推断集合s1是不是s2的子集
for( set<string>::iterator it=s1.begin(); it!=s1.end();it++ )
{
//s1有元素不在s2中
if( s2.find(*it)==s2.end() )
{
flag=10;
break;
}
}
for( set<string>::iterator it=s2.begin(); it!=s2.end();it++ )
{
//s2有元素不在s1中
if( s1.find(*it)==s1.end() )
{
flag+=1;
break;
}
}
/*当flag==0,s1元素所有在s2中,s2元素也所有在s1中,s1==s2
当flag==10,s1有元素不在s2中,s2所有元素都在s1中。s1包括了s2
当flag==1,s1所有元素在s2中,s2有元素不在s1中。s2包括了s1
当flag==11,s1 s2集合互不包括
*/
return flag;
} map_s apriori_gen(map_s &Ck,int k)
{
//生成子集
map_s Ck_temp;
set<string> s_temp;
for( map_s::iterator l_it1=Ck.begin();l_it1!=Ck.end();l_it1++ )
{
for( map_s::iterator l_it2=Ck.begin();l_it2!=Ck.end();l_it2++ )
{
//假设两个set一样,则说明是同一个KEY。跳过
if(!((l_it1->first > l_it2->first)||(l_it1->first < l_it2->first)))
continue;
//否则開始组装,遍历整个Ck
for( set<string>::iterator s_it=l_it2->first.begin();s_it!=l_it2->first.end();s_it++ )
{
//假设该值在l_it1 set里面能够找到,不能组装
if( l_it1->first.find(*s_it)!=l_it1->first.end())
continue;
//否则进行组装,先把l_it1的set复制进去
s_temp = l_it1->first;
//再把l_it2的值放进去
s_temp.insert(*s_it);
//推断该组装的set是否已在生成集合中。假设之前已生成。则不须要往下运算
if(Ck_temp.find(s_temp)!=Ck_temp.end())
continue;
else //否则放到生成的子集中
{
Ck_temp.insert(pair<set<string>,int >(s_temp,0));
}
}
}
} //对于k=2的情况。须要扫描原始数据得出计数值
if( 2 == k )
{
for( map_s::iterator l_it=Ck_temp.begin();l_it!=Ck_temp.end();l_it++ )
for(int i=0;i<data.size();i++)
//l_it集合被data[i]完整包括,则计数值+1
if( (10 == compset(data[i],l_it->first)) || (0 == compset(data[i],l_it->first)) )
Ck_temp[l_it->first]++; //扫描完之后排除 非频繁项
for( map_s::iterator l_it=Ck_temp.begin();l_it!=Ck_temp.end();l_it++ )
if( Ck_temp[l_it->first] < minSup )
Ck_temp.erase(l_it);
}
//假设是大于2的情况,扫描k-1的频繁项子集
if( 2 < k )
{
//每次都循环获取每一个Ck的k-1子集元素
//如{I1,I2,I3}C3的子集是{I1,I2} {I2,I3} {I3,I4}
//假设Ck的子集不在k-1的频繁项子集中,则去掉该Ck项
for( map_s::iterator l_it=Ck_temp.begin();l_it!=Ck_temp.end();l_it++ )
{
int flag;
for( set<string>::iterator s_it=l_it->first.begin();s_it!=l_it->first.end();s_it++ )
{
//開始求子集
//首先把当前Ck项的集合保存
s_temp=l_it->first;
//去掉一个元素。即是它的k-1子集
s_temp.erase(*s_it);
//遍历频繁项集合L。看看是不是在频繁集中
flag=1;
for( int i=0;i<L.size();i++ )
{
//假设K-1子集在频繁项集中存在,则保留
if( 0 == compset(s_temp,L[i]) )
{
flag=0;
break;
}
}
//假设找到了哪怕一个k-1子集项不在频繁项集中。直接退出
if( flag ) break;
}
//仅仅有所有的k-1子集在频繁项集中。才保留该Ck项
if( flag ) Ck_temp.erase(l_it);
}
} cout<<"由L"<<k-1<<"产生的候选集C"<<k<<" "<<"cout数(k=2以上不做计数)"<<endl;
for( map_s::iterator l_it=Ck_temp.begin();l_it!=Ck_temp.end();l_it++ )
{
for( set<string>::iterator s_it=l_it->first.begin();s_it!=l_it->first.end();s_it++ )
cout<<*s_it<<" ";
cout<<l_it->second<<endl;
}
return Ck_temp;
} int main()
{
cout<<"请输入事务,第一行输入事务数。每行第一个值输入该事务的item数"<<endl;
//生成原始数据集
cin>>n;
for(int i=0;i<n;i++)
{
s.clear();
cin>>m;
for(int j=0;j<m;j++)
{
cin>>in;
s.insert(in);
data2.push_back(in);
}
data.push_back(s);
}
//扫描数据集D。生成C1
//对于每一个候选集里面的元素
for( int j=0; j<data2.size();j++ )
{
int flag=1;
//假设C1中存在该元素,计数值加1
for( map_s::iterator l_it=Ck.begin();l_it!=Ck.end();l_it++ )
{
if( (l_it->first).find(data2[j]) != (l_it->first).end() )
{
Ck[l_it->first]++;
flag=0;
break;
}
}
//不存在,插入到C1集合中
if(flag)
{
s.clear();
s.insert(data2[j]);
Ck.insert(pair<set<string>,int>(s,1));
}
}
//去掉支持度不足的
for( map_s::iterator l_it=Ck.begin();l_it!=Ck.end();l_it++ )
{
if( l_it->second< minSup)
Ck.erase(l_it);
} cout<<"C1候选集:"<<endl;
cout<<"项集"<<" "<<"支持度计数"<<endl; for( map_s::iterator l_it=Ck.begin();l_it!=Ck.end();l_it++ )
{
for( set<string>::iterator s_it=(l_it->first).begin(); s_it!=(l_it->first).end(); s_it++)
cout<<*s_it<<" "<<l_it->second<<endl;
} int f_count=2;
while( f_count )
{
//将Ck内的k-1频繁集所有保存到L集中
for( map_s::iterator l_it=Ck.begin();l_it!=Ck.end();l_it++ )
L.push_back(l_it->first);
//获取Ck集,已清除掉小于支持度的候选集
Ck=apriori_gen(Ck,f_count); if( Ck.empty() )
{
break;
}else{ f_count++; }
} cout<<"终于的频繁集集合"<<endl;
for( int i=0; i<L.size(); i++ )
{
for( set<string>::iterator s_it=L[i].begin(); s_it!=L[i].end(); s_it++)
cout<<*s_it<<" ";
cout<<endl;
} }
眼下仅仅实现到产生频繁集合,支持度默认计数2。在g++环境下编译 g++ -g Apriori.c -o apr
測试数据例如以下:
4
3 I1 I2 I6
4 I1 I2 I3 I5
3 I2 I3 I7
5 I1 I3 I5 I6 I2
输出例如以下:
用ORACLE格式化数据导出成文件,C++处理后返回文件给ORACLE,传到推荐数据库中就可以完毕这个算法的全流程。
当然眼下还仅仅是儿童玩具,由于全部的数据都是放在内存里的,数据量一大这个代码就不有用了。
C++牛逼的地方在于能够直接调用linux底层的接口处理这一类问题。比方当内存不足时数据存到磁盘。我们这边内存有几十G。订单总量不超过1G。所以这个代码应该够用了,不够用时能够再扩展
Apriori算法的C++实现的更多相关文章
- Apriori算法的原理与python 实现。
前言:这是一个老故事, 但每次看总是能从中想到点什么.在一家超市里,有一个有趣的现象:尿布和啤酒赫然摆在一起出售.但是这个奇怪的举措却使尿布和啤酒的销量双双增加了.这不是一个笑话,而是发生在美国沃尔玛 ...
- #研发解决方案#基于Apriori算法的Nginx+Lua+ELK异常流量拦截方案
郑昀 基于杨海波的设计文档 创建于2015/8/13 最后更新于2015/8/25 关键词:异常流量.rate limiting.Nginx.Apriori.频繁项集.先验算法.Lua.ELK 本文档 ...
- 数据挖掘算法(四)Apriori算法
参考文献: 关联分析之Apriori算法
- 机器学习实战 - 读书笔记(11) - 使用Apriori算法进行关联分析
前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第11章 - 使用Apriori算法进行关联分析. 基本概念 关联分析(associat ...
- 关联规则挖掘之apriori算法
前言: 众所周知,关联规则挖掘是数据挖掘中重要的一部分,如著名的啤酒和尿布的问题.今天要学习的是经典的关联规则挖掘算法--Apriori算法 一.算法的基本原理 由k项频繁集去导出k+1项频繁集. 二 ...
- 利用Apriori算法对交通路况的研究
首先简单描述一下Apriori算法:Apriori算法分为频繁项集的产生和规则的产生. Apriori算法频繁项集的产生: 令ck为候选k-项集的集合,而Fk为频繁k-项集的集合. 1.首先通过单遍扫 ...
- Apriori算法例子
1 Apriori介绍 Apriori算法使用频繁项集的先验知识,使用一种称作逐层搜索的迭代方法,k项集用于探索(k+1)项集.首先,通过扫描事务(交易)记录,找出所有的频繁1项集,该集合记做L1,然 ...
- Apriori算法实例----Weka,R, Using Weka in my javacode
学习数据挖掘工具中,下面使用4种工具来对同一个数据集进行研究. 数据描述:下面这些数据是15个同学选修课程情况,在课程大纲中共有10门课程供学生选择,下面给出具体的选课情况,以ARFF数据文件保存,名 ...
- Apriori算法在购物篮分析中的运用
购物篮分析是一个很经典的数据挖掘案例,运用到了Apriori算法.下面从网上下载的一超市某月份的数据库,利用Apriori算法进行管理分析.例子使用Python+MongoDB 处理过程1 数据建模( ...
- 关于apriori算法的一个简单的例子
apriori算法是关联规则挖掘中很基础也很经典的一个算法,我认为很多教程出现大堆的公式不是很适合一个初学者理解.因此,本文列举一个简单的例子来演示下apriori算法的整个步骤. 下面这个表格是代表 ...
随机推荐
- javaweb部署多个项目(复制的项目)
最近需要在一台服务器部署两个已经编译完了的javaweb项目,但是因为项目名一样,仅修改文件夹的名字无法实现两个项目共存,最后只能考虑采用部署多个tomcat服务器的方法来实现.搜索后终于找到个好方法 ...
- 开源API测试工具 Hitchhiker v0.4更新 - 没有做不到,只有想不到
Hitchhiker 是一款开源的 Restful Api 测试工具,支持Schedule, 数据对比,压力测试,支持上传脚本定制请求,可以轻松部署到本地,和你的team成员一起管理Api. 详细介绍 ...
- js 切换全屏
公司有一个需求就是点击某一个按钮实现全屏切换功能,然后呢我就在网上扒了段代码.封装了一下.使用的小伙伴们可以看看哦! 切换全屏代码 <!DOCTYPE html> <html> ...
- ssh相关原理学习与常见错误总结
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- [转]SQL Server为啥使用了这么多内存?
原文地址:http://support.microsoft.com/gp/anxin_techtip6/zh-cn SQL Server为啥使用了这么多内存? SQL Server的用户,常常会发现S ...
- git命令提交项目
相关的操作命令,总是忘记,故在此记录下: 此为linux下的命, windows的话,去掉sudo即可 1.进入项目代码根目录,执行: sudo git init 把这个目录变成git可以管理的仓库. ...
- 使用JavaScript生成二维码教程-附qrcodejs中文文档
使用javascript生成二维码 依赖jquery 需要使用到的库 https://github.com/davidshimjs/qrcodejs DIV <div id="qrco ...
- [C#]使用TcpListener及TcpClient开发一个简单的Chat工具
本文为原创文章.源代码为原创代码,如转载/复制,请在网页/代码处明显位置标明原文名称.作者及网址,谢谢! 本文使用的开发环境是VS2017及dotNet4.0,写此随笔的目的是给自己及新开发人员作为参 ...
- thinkphp系列:类的自动加载是如何设计的
在使用框架开发时,可以发现框架有很多核心类,却很少看到显示的引入某个文件的代码,这是因为框架都采用了类的自动加载机制,即使用到类时,框架会自动找到该类所在文件的位置并引入该文件.为了更容易看出代码思路 ...
- android扫描网页二维码进行网页登录
转载请标明出处: http://www.cnblogs.com/dingxiansen/: 本文出自:丁先森-博客园 周六和朋友去网吧开黑,开机打开TGP,朋友那边开始输入账号密码,我看了他一眼low ...