·背景 ios
前一陣,一直在研究一些ML的東東,後來工做關係暫停了一陣。如今繼續把剩下一些熱門的算法再吃吃透,"無聊+逗比"地把他們搞到MapReduce上。此次選擇的入手對象爲Apriori,也就是你們俗稱的"關聯規則挖掘",有別於CF(協同過濾)的正交輸出。再俗一點,就是常被人說起的"啤酒+麪包"的故事。 c++
·Apriori算法簡介 算法
在關聯規則挖掘方面,有兩項著名的算法:Apriori和FPgrowth。二者各有特色,因爲計算量級別的差別,愈來愈多的人選擇了後者。但這並不意味着Apriori就是垃圾。我的的理解,FPgrowth爲MP而生,Apriori爲容器而生。當單日誌量達到5G,10G以上Apriori在計算方面的吃虧逐步顯現,即使如此,對於人們對於儘量減小Apriori掃描次數的優化機制仍然樂此不疲。尤爲是做爲容器方面的選擇,能夠極大的減小整個代碼的實現過程和增長可讀性,同時又能訓練你的腦力和對容器的使用創意。 centos
做爲單機版原本說,總體Apriori的邏輯過程如上所述,相比"樹"和"圖"來講要簡單許多,可是仍然暗藏很多重複計算的陷阱。 數據結構
做爲MP版來講,Apriopi如何壓榨Map的資源,真是件使人頭痛的事情。如上圖所述: oracle
· 一些心得體會 函數
· 單機版 centos 6(2.6)+gcc433oop
#include <iostream> #include <sstream> #include <fstream> #include <string.h> #include <vector> #include <map> #include <set> #include <algorithm> using namespace std; typedef struct { //原始集合結構定義 vector<string> ss; } t_raw_jh; typedef struct { //有效數據/統計集合定義 set<string> ss; int sup_num; } t_raw_tj; t_raw_jh raw_c[50]; //原始數據 map<set<string>,int> raw_cnt_base; //原始元素統計集合 t_raw_tj L[10]; //洗出來的單集合組合 //set<set> new_kc; //洗出來的排列對象集,做爲下次掃描的催化劑 int raw_num=0; //原始數據計數器 int l_num=0; //統計數據計算器 int raw_msup=2; //頻繁項支持度 /* C[頻繁set<set>]-> [Struct/raw_c] -> Map<set,int> -> L -> set<set> */ void CountEleBase(string line,const char* delim,int raw_num); //1+pre,把一條元素洗到二維顆粒,同時統計group by count void CountEleReal(set<set<string> > &cc); //1+real,根據3的催化劑,掃描原始記錄,同時統計group by count int WashEleBase(); //2,把MAP SORT[group by count]洗出大於支持度的對象集 set<set<string> > GetNewKc(int size); //3,把洗出的對象集合,極限排列出全部可能,做爲下次掃描的催化劑 void Display(); //顯示原始集合、單元素非排序group by count void ClearTj(); //把統計表給清空 void RunApriori(set<set<string> > &fc); //嵌套跑,固然也能夠迭代WHILE跑,入參爲頻繁項 int main() { std::ios::sync_with_stdio(false); string filename="./ap001.txt"; string line; ifstream ifs; ifs.open(filename.c_str()); while(getline(ifs,line)) { CountEleBase(line,",",raw_num); raw_num++; } // Display(); //獲得第一組通過支持度過濾的C set<set<string> > aaa; //頻繁項,根據有效支持元素得出的組合 aaa=GetNewKc(WashEleBase()); RunApriori(aaa); } void RunApriori(set<set<string> > &fc) { if(l_num==1) return; CountEleReal(fc); fc.clear(); fc=GetNewKc(WashEleBase()); RunApriori(fc); } void CountEleReal(set<set<string> > &cc) { //掃描記錄集 cout<<"\n-----掃描記錄集-----"<<endl; //迭代器定義好,在該函數內以後會用到 set<set<string> >::iterator ot_it; set<string>::iterator in_it; raw_cnt_base.clear(); for(ot_it=cc.begin();ot_it!=cc.end();ot_it++) { int map_cc=0; for(int i=0;i<raw_num;i++) { vector<string>::iterator res; for(res=raw_c[i].ss.begin();res!=raw_c[i].ss.end();res++) { cout<<*res<<" "; } cout<<"|"; int map_in_cc=0; for(in_it=(*ot_it).begin();in_it!=(*ot_it).end();in_it++) { cout<<*in_it<<" "; res=find(raw_c[i].ss.begin(),raw_c[i].ss.end(),*in_it); if(res!=raw_c[i].ss.end()) map_in_cc++; } if(map_in_cc==(*ot_it).size()) map_cc++; cout<<"|"<<map_in_cc<<endl; } raw_cnt_base[*ot_it]=map_cc; cout<<"-->"<<map_cc<<endl; } } set<set<string> > GetNewKc(int size) { vector<string>::iterator ss_it; set<string> kk[size]; set<set<string> > new_kc; int pi=0; set<string>::iterator kk_it; //作兩兩極限排列組合 for(int i=0;i<l_num;i++) { set<string> tmp=L[i].ss; for(int j=i+1;j<l_num;j++) { for(kk_it=L[j].ss.begin();kk_it!=L[j].ss.end();kk_it++) { tmp.insert(*kk_it); } new_kc.insert(tmp); tmp=L[i].ss; } } cout<<"有效支持元素 ---> C組合[頻繁項]:"<<endl; set<set<string> >::iterator out_it; set<string>::iterator in_it; for(out_it=new_kc.begin();out_it!=new_kc.end();out_it++) { for(in_it=(*out_it).begin();in_it!=(*out_it).end();in_it++) { cout<<*in_it<<","; } cout<<endl; } return new_kc; } int WashEleBase() { map<set<string>,int>::iterator raw_cnt_it; int i=0; l_num=0; ClearTj(); for(raw_cnt_it=raw_cnt_base.begin();raw_cnt_it!=raw_cnt_base.end();raw_cnt_it++) { if(raw_cnt_it->second>=raw_msup) { L[i].ss=raw_cnt_it->first; L[i++].sup_num=raw_cnt_it->second; l_num++; } } //Display cout<<"有效支持元素:"<<endl; set<string>::iterator ss_it; for(i=0;i<l_num;i++) { for(ss_it=L[i].ss.begin();ss_it!=L[i].ss.end();ss_it++) { cout<<*ss_it<<","; } cout<<"|"<<L[i].sup_num<<endl; } return i; } void CountEleBase(string line,const char* delim,int raw_num) { char *p=NULL,*q=NULL; p=const_cast<char*>(line.c_str()); while(p) { q=strsep(&p,","); set<string> load_ss; raw_c[raw_num].ss.push_back(q); load_ss.insert(q); raw_cnt_base[load_ss]++; } } void Display() { cout<<"----Print Map-------"<<endl; map<set<string>,int>::iterator raw_cnt_it; set<string>::iterator ss_it; for(raw_cnt_it=raw_cnt_base.begin();raw_cnt_it!=raw_cnt_base.end();raw_cnt_it++) { for(ss_it=(raw_cnt_it->first).begin();ss_it!=(raw_cnt_it->first).end();ss_it++) { cout<<*ss_it<<" "; } cout<<":"<<raw_cnt_it->second<<endl; } //raw_cnt_base.clear(); cout<<"----Print Raw-------"<<endl; vector<string>::iterator raw_c_it; for(int i=0;i<raw_num;i++) { for(raw_c_it=raw_c[i].ss.begin();raw_c_it!=raw_c[i].ss.end();raw_c_it++) { cout<<*raw_c_it<<" "; } cout<<endl; } } void ClearTj() { for(int i=0;i<10;i++) { L[i].sup_num=0; L[i].ss.clear(); } }
· 另優化
望各位路過的大俠,嘴上留情,手上斧正,看看可否進一步壓縮計算空間量~~。^_^。 spa