Quantcast
Channel: CodeSection,代码区,数据库(综合) - CodeSec
Viewing all articles
Browse latest Browse all 6262

Apriori初步学习+C++实现

$
0
0
1.基本概念

Apriori算法是一种挖掘关联规则的频繁项集算法,最早由R.Agrawal提出,现已广泛的运用到商业、网络安全等领域。最常见的淘宝相关推荐便包含有这一算法。

该算法的主要步骤为:

(1) 找到所有支持度大于最小支持度的项目集,即频繁项集(Frequent Itemset);

(2) 使用第(1)步的频繁项目集产生期望的规则。

Apriori算法着重与第一步,挖掘频繁项集。
形式化描述如下:令项集I={i1,i2,...in}且有一个数据集合D,它其中的每一条记录T,都是I的子集。
那么关联规则都是形如A->B的表达式,A、B均为I的子集,且A与B的交集为空。
这条关联规则的支持度:support = P(A∪B)
这条关联规则的置信度:confidence = support(A∪B)/suport(A)
如果存在一条关联规则,它的支持度和置信度都大于预先定义好的最小支持度与置信度,我们就称它为强关联规则。强关联规则就可以用来了解项之间的隐藏关系。所以关联分析的主要目的就是为了寻找强关联规则,而Apriori算法则主要用来帮助寻找强关联规则。
2.算法描述

符号说明:

k-itemset k维项目集
L(k) 具有最小支持度的最大 k-itemset
C(k) 候选的k维项目集
首先用sc.candidate通过第(k-1)步中生成的最大项目集L(k-1)来生成候选项目集
然后搜索数据库计算候选项目集的C(k)的支持度 By count_support 函数
--------------------------------------------------------------------
综述
C(1) = { candidate 1-itemsets };
L(1) = {c ∈ C(1) c.count >= minsupport};
for(k=2; L(k-1) != NULL; k++) //直到不能再生成最大项目集为止
C(k) = sc.candidate( L(k-1) );//生成含k个元素的候选项目集C(k)
for all transactions t ∈ D//事务 D为数据库
C(t) = count_support(C(k),t);//包含在事务t中的候选项目集 计算支持度
for all candidates c ∈ C(t)
c.count = c.count + 1;
next
L(k) = {c ∈ C(k) c.count >= minsupport};
next
resultset = resultset L(k) //resultset 最大项目集
sc.candidate 函数
该函数的参数为 L(k-1) 即:所有最大 k-1 维项目集,结果返回含有 K 个项目的候选项目集 C(k)
事实上,C(k)是 k 维最大项目集的超集,通过函数 count_support 计算项目的支持度,然后生成 L(k)
该函数的实现步骤如下:
首先,通过对 L(k-1) 自连接操作生成 C(k) ,称 join (连接)步。
insert into C(K)
select P.item1,P.item2,......P.itemk-1,Q.itemk-1
from L(k-1)P,L(k-1)Q
where P.item1 = Q.item1,......P.itemk-2 = Q.itemk-2,P.itemk-1 < Q.itemk-1
然后是 prune(修剪)步,即对任意的 c , c ∈ C(k) ,删除 C(k) 中所有那些(k-1)维子集不在 L(k-1) 中的项目集
得到候选项目集 C(k) ,表述为:
for all itemset c ∈ C(k)
for all (k-1)维子集 s of c
if(s !∈ L(k-1)) then
delete c from C(k)
用集合表示 C(k) == { X ∈ C(k) , X 的所有k-1维子集在 L(k-1) 中}
count_support 函数
参数为候选项目集 C(k) 和某一事务记录 t , 结果返回这一事务 t 中包含的候选项目集
它的主要功能是找到包含在事务 t 中所有的候选项目集。
3.代码
在学习代码中,也学习了STL容器的一些相关使用方法,并记录笔记。想要直接看程序代码的请拖到最后即可。
map
//vector从后面快速的插入与删除,直接访问任何元素
//map 一对多映射,基于关键字快速查找,不允许重复值
For example, the following code creates a map that associates a string with an integer
map ages;
ages["Homer"] = 38;
ages["Marge"] = 37;
ages["Lisa"] = 8;
ages["Maggie"] = 1;
ages["Bart"] = 11;
insert的使用
pair insert( const pair &val );
//只有在val不存在时插入val。返回值是一个指向被插入元素的迭代器和一个描述是否插入的bool值。,value_type>,>
迭代器 iterator 的使用
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围。迭代器就如同一个指针。
事实上,C++的指针也是一种迭代器。但是,迭代器不仅仅是指针,因此你不能认为他们一定具有地址值。
如下代码对vector容器对象生成和使用了迭代器:
vector the_vector;
vector::iterator the_iterator;
for( int i=0; i < 10; i++ )
the_vector.push_back(i);//push_back() 在Vector最后添加一个元素
int total = 0;
the_iterator = the_vector.begin();
while( the_iterator != the_vector.end() ) {
total += *the_iterator; //point是地址 *p 是取地址p里面的值
the_iterator++;
}
cout << "Total=" << total << endl;//提示:通过对一个迭代器的解引用操作(*),可以访问到容器所包含的元素。
cout << "Bart is " << ages["Bart"] << " years old" << endl;
map容器的迭代器里面 有first 和 second
例如
map m;
m["one"] = 1;
map::iterator p = m.begin();
p->first; // 这个是 string 值是 "one"
p->second; //这个是 int 值是 1,>,>
pair类型 (http://blog.csdn.net/xywlpo/article/details/6458867)
pair是一种模版类型,其中包含两个数值,两个数据的类型可以不同,基本的定义如下:
pair a;
表示a中有两个类型,第一个元素是int型的,第二个元素是string类型的,
如果创建pair的时候没有对其进行初始化,则调用默认构造函数对其初始化。
pair a("James", "Joy");
也可以像上面一样在定义的时候直接对其初始化。
由于pair类型的使用比较繁琐,因为如果要定义多个形同的pair类型的时候,可以时候typedef简化声明:
typedef pair author;
author pro("May", "Lily");
author joye("James", "Joyce");,>
pair对象的操作:
对于pair类,它只有两个元素,分别为first 和 second
pair a("Lily", "Poly");
string name;
name = pair.second;,>
生成新的pair对象
可以使用make_pair对已存在的两个数据构造一个新的pair类型:
int a = 8;
string m = "James";
pair newone;
newone = make_pair(a, m);,>
完整代码如下:
#include
#include
#include
#include
#include
using namespace std;
class Apriori
{
public:
//构造函数
Apriori(size_t is =0,unsigned int mv=0)
{
item_size = is;
min_value = mv;
}
//~Apriori() {};
void getItem();
map< vector,unsigned int> find_freitem();//求事务的频繁项
//连接两个k-1级频繁项,得到第k级频繁项
map< vector,unsigned int > apri_gen(unsigned int K , map< vector,unsigned int > K_item);
//展示频繁项集
void showAprioriItem(unsigned int K,map< vector,unsigned int > showmap);
private:
map< int , vector > item;//存储所有最开始的事务及其项
map< vector,unsigned int > K_item;//存储频繁项集
size_t item_size;//事务数目
unsigned int min_value;//最小阈值
};
void Apriori::getItem()//用户输入最初的事务集
{
int ci = item_size;
for (int i=0;i temp;
cout<<"请输入第 "<>str && str !="123")
{
temp.push_back(str);
}
sort(temp.begin(),temp.end());
pair< map >::iterator , bool> ret = item.insert(make_pair(i+1 ,temp));
if (!ret.second)
{
--i;
cout<<"你输入的元素已存在!请重新输入!"< >::iterator mit ;
for (mit=item.begin();mit != item.end();mit++)
{
vector vec = mit->second;
if (vec.size() != 0) //vec不为空则跳出
break;
}
if (mit == item.end())//事务集为空
{
isEmpty = true;
cout<<"事务集为空!程序无法进行..."<,unsigned int> empty;
return empty;
}
while(1)
{
map< vector,unsigned int > K_itemTemp = K_item;//k_item 储存频繁项集
K_item = apri_gen(i++,K_item);//循环生成k_item
if (K_itemTemp == K_item)
{
i = UINT_MAX;
break;
}
//判断是否需要进行下一次的寻找
map< vector,unsigned int > pre_K_item = K_item;
size_t Kitemsize = K_item.size();
//存储应该删除的第K级频繁项集,不能和其他K级频繁项集构成第K+1级项集的集合
if (Kitemsize != 1 && i != 1)
{
vector< map< vector,unsigned int >::iterator > eraseVecMit;
map< vector,unsigned int >::iterator pre_K_item_it1 = pre_K_item.begin() , pre_K_item_it2;
while (pre_K_item_it1 != pre_K_item.end() )
{
map< vector,unsigned int >::iterator mit = pre_K_item_it1;
bool isExist = true;
vector vec1;
vec1 = pre_K_item_it1->first;
vector vec11(vec1.begin(),vec1.end()-1);
while (mit != pre_K_item.end())
{
vector vec2;
vec2 = mit->first;
vector vec22(vec2.begin(),vec2.end()-1);
if (vec11 == vec22)
break;
++mit;
}
if (mit == pre_K_item.end())
isExist = false;
if (!isExist && pre_K_item_it1 != pre_K_item.end())
eraseVecMit.push_back(pre_K_item_it1);//该第K级频繁项应该删除
++pre_K_item_it1;
}
size_t eraseSetSize = eraseVecMit.size();
if (eraseSetSize == Kitemsize)
break;
else
{
vector< map< vector,unsigned int >::iterator >::iterator currentErs = eraseVecMit.begin();
while (currentErs != eraseVecMit.end())//删除所有应该删除的第K级频繁项
{
map< vector,unsigned int >::iterator eraseMit = *currentErs;
K_item.erase(eraseMit);
++currentErs;
}
}
}
else
if(Kitemsize == 1 )
break;
}
cout<,unsigned int > Apriori::apri_gen(unsigned int K , map< vector,unsigned int > K_item)
{
if (1 == K)//求候选集C1
{
size_t c1 = item_size;
map< int , vector >::iterator mapit = item.begin();
vector vec;
map c1_itemtemp;
while (mapit != item.end() )//将原事务中所有的单项统计出来
{
vector temp = mapit->second;
vector::iterator vecit = temp.begin();
while (vecit != temp.end() )
{
pair< map::iterator , bool > ret = c1_itemtemp.insert(make_pair(*vecit++ , 1));
if (!ret.second)
{
++ ret.first->second;
}
}
++mapit;
}
map::iterator item_it = c1_itemtemp.begin();
map< vector,unsigned int > c1_item;
while (item_it != c1_itemtemp.end() )//构造第一级频繁项集
{
vector temp;
if ( item_it->second >= min_value)
{
temp.push_back(item_it->first);
c1_item.insert(make_pair(temp , item_it->second) );
}
++item_it;
}
return c1_item;
}
else
{
cout<,unsigned int >::iterator ck_item_it1 = K_item.begin(),ck_item_it2;
map< vector,unsigned int > ck_item;
while (ck_item_it1 != K_item.end() )
{
ck_item_it2 = ck_item_it1;
++ck_item_it2;
map< vector,unsigned int >::iterator mit = ck_item_it2;
//取当前第K级频繁项与其后面的第K级频繁项集联合,但要注意联合条件
//联合条件:连个频繁项的前K-1项完全相同,只是第K项不同,然后两个联合生成第K+1级候选频繁项
while(mit != K_item.end() )
{
vector vec,vec1,vec2;
vec1 = ck_item_it1->first;
vec2 = mit->first;
vector::iterator vit1,vit2;
vit1 = vec1.begin();
vit2 = vec2.begin();
while (vit1 < vec1.end() && vit2 < vec2.end() )
{
string str1 = *vit1;
string str2 = *vit2;
++vit1;
++vit2;
if ( K ==2 || str1 == str2 )
{
if (vit1 != vec1.end() && vit2 != vec2.end() )
{
vec.push_back(str1);
}
}
else
break;
}
if (vit1 == vec1.end() && vit2 == vec2.end() )
{
--vit1;
--vit2;
string str1 = *vit1;
string str2 = *vit2;
if (str1>str2)
{
vec.push_back(str2);
vec.push_back(str1);
}
else
{
vec.push_back(str1);
vec.push_back(str2);
}
map< int , vector >::iterator base_item = item.begin();
unsigned int Acount = 0 ;
while (base_item != item.end() )//统计该K+1级候选项在原事务集出现次数
{
unsigned int count = 0 ,mincount = UINT_MAX;
vector vv = base_item->second;
vector::iterator vecit , bvit ;
for (vecit = vec.begin();vecit < vec.end();vecit++)
{
string t = *vecit;
count = 0;
for (bvit=vv.begin();bvit < vv.end();bvit++)
{
if (t == *bvit)
count++;
}
mincount = (count < mincount ? count : mincount );
}
if (mincount >=1 && mincount != UINT_MAX)
Acount += mincount;
++base_item;
}
if (Acount >= min_value && Acount != 0)
{
sort(vec.begin(),vec.end());
//该第K+1级候选项为频繁项,插入频繁项集
pair< map< vector,unsigned int >::iterator , bool> ret = ck_item.insert(make_pair(vec,Acount));
if (! ret.second)
{
ret.first->second += Acount;
}
}
}
++mit;
}
++ck_item_it1;
}
if (ck_item.empty())//该第K+1级频繁项集为空,说明调用结束,把上一级频繁项集返回
return K_item;
else
return ck_item;
}
}
void Apriori::showAprioriItem(unsigned int K,map< vector,unsigned int > showmap)
{
map< vector,unsigned int >::iterator showit = showmap.begin();
if (K != UINT_MAX)
cout<::iterator vecit = vec.begin();
cout<<"{ ";
while (vecit != vec.end())
{
cout<<*vecit<<" ";
++vecit;
}
cout<<"}"<<"\t";
cout<second<= '0' && str[i] <= '9')
num += str[i] - '0';
else
return 0;
}
return num;
}
}
void main()
{
//Apriori a;
unsigned int itemsize = 0;
unsigned int min;
//输入 事务数(itemsize) 和 最小阀值(minsupport)
do
{
cout<<"请输入事务数:";
char * str = new char;
cin>>str;
itemsize = parseNumber(str);
if (itemsize == 0)
{
cout<<"请输入大于0正整数!"<,unsigned int> AprioriMap = a.find_freitem();
//a.showAprioriItem(UINT_MAX,AprioriMap);
system("pause");
};>;>;>,unsigned>,unsigned>,unsigned>;>;>;>+1;i++)>
,>,>,>,>,>,>,>
,value_type>,>

Viewing all articles
Browse latest Browse all 6262

Trending Articles