標籤:pts for file href ddn poll input fileinput continue
本文參考韓家煒《資料採礦-概念與技術》一書第六章,前提條件要理解 apriori演算法。
另外一篇寫得較好的文章在此推薦:
http://hi.baidu.com/nefzpohtpndhovr/item/9d5c371ba2dbdc0ed1d66dca
0.實驗資料集:user2items.csv
I1,I2,I5I2,I4I2,I3I1,I2,I4 I1,I3 I2,I3I1,I3I1,I2,I3,I5I1,I2,I3
1.演算法原理構造FPTree
1、首先讀取資料庫中全部種類的項和這些項的支援度計數。
存入到itTotal鏈表中。
2、將itTotal鏈表依照支援度計數從大到小排序
3、將itTotal鏈表插入到ItemTb表中
4、第二便讀取資料庫中的事務,將事務中的項依照支援度計數由大到小的順序插入到樹中。
5、遍曆樹,將屬於同一項的結點通過bnode指標串連起來。
本程式中,FP-tree中儲存了全部的項集,沒有考慮最小支援度。
僅僅是在FP-growth中挖掘頻繁項集時考慮最小支援度
/** * * @param records 構建樹的記錄,如I1,I2,I3 * @param header 韓書中介紹的表頭 * @return 返回構建好的樹 */public TreeNode2 builderFpTree(LinkedList<LinkedList<String>> records,List<TreeNode2> header){ TreeNode2 root; if(records.size()<=0){ return null; } root=new TreeNode2(); for(LinkedList<String> items:records){ itemsort(items,header); addNode(root,items,header);}String dd="dd";String test=dd;return root;}//當已經有分枝存在的時候,推斷新來的節點是否屬於該分枝的某個節點。或所有重合,遞迴public TreeNode2 addNode(TreeNode2 root,LinkedList<String> items,List<TreeNode2> header){if(items.size()<=0)return null;String item=items.poll();//當前節點的孩子節點不包括該節點。那麼另外建立一支分支。TreeNode2 node=root.findChild(item);if(node==null){ node=new TreeNode2();node.setName(item);node.setCount(1);node.setParent(root);root.addChild(node);//加將各個同名的節點加到鏈頭中 for(TreeNode2 head:header){if(head.getName().equals(item)){while(head.getNextHomonym()!=null){head=head.getNextHomonym();}head.setNextHomonym(node);break;}}//加將各個節點加到鏈頭中}else{node.setCount(node.getCount()+1);} addNode(node,items,header);return root;}
FP_growth演算法:
從一棵FPTree的ItemTb表中取得第一個項I1。假設該項的支援度計數滿足最小支援度計數{
1、把該項I1增加到儲存挖掘到的頻繁項集的資料結構ItemSet中
2、得到該項I1在眼下FPTree中的條件模式基。即該項在樹中的結點的首碼路徑(路徑中不再包含該項)。
注意該項I1的條件模式基中各個項的支援度計數相等。等於該項I1的支援度計數
3、每條路徑看作一個事務,用這些路徑建造該項的條件FPTree,然後遞迴調用FP_growth演算法。
在遞迴調用FP_growth演算法時,那些大於支援度計數的項作為項I1的孩子結點儲存在ItemSet中。
}
本人認為要想更好的理解,或者有不明之處應該參考http://hi.baidu.com/nefzpohtpndhovr/item/9d5c371ba2dbdc0ed1d66dca
這篇文章的這個地方,見。
public void fpgrowth(LinkedList<LinkedList<String>> records,String item){//儲存新的條件模式基的各個記錄,以又一次構造FP-treeLinkedList<LinkedList<String>> newrecords=new LinkedList<LinkedList<String>>();//構建鏈頭LinkedList<TreeNode2> header=buildHeaderLink(records);//建立FP-TreeTreeNode2 fptree= builderFpTree(records,header);//結束遞迴的條件if(header.size()<=0||fptree==null){System.out.println("-----------------");return;}//列印結果,輸出頻繁項集if(item!=null){//尋找條件模式基,從鏈尾開始for(int i=header.size()-1;i>=0;i--){TreeNode2 head=header.get(i);String itemname=head.getName();Integer count=0;while(head.getNextHomonym()!=null){head=head.getNextHomonym();//葉子count等於多少。就算多少條記錄count=count+head.getCount();}//列印頻繁項集System.out.println(head.getName()+","+item+"\t"+count);}}//尋找條件模式基,從鏈尾開始for(int i=header.size()-1;i>=0;i--){TreeNode2 head=header.get(i);String itemname;//再組合if(item==null){itemname=head.getName();}else{itemname=head.getName()+","+item;}while(head.getNextHomonym()!=null){head=head.getNextHomonym();//葉子count等於多少,就算多少條記錄Integer count=head.getCount();for(int n=0;n<count;n++){ LinkedList<String> record=new LinkedList<String>(); toroot(head.getParent(),record); newrecords.add(record);}}//System.out.println("-----------------");//遞迴之,以求子FP-Treefpgrowth(newrecords,itemname);} }
2.tree的結構 private String name; // 節點名稱
private Integer count; // 計數
private TreeNode2 parent; // 父節點
private List<TreeNode2> children; // 子節點
private TreeNode2 nextHomonym; // 下一個同名節點詳見以下的TreeNode2類3.完整的原始碼:共兩份.java檔案,直接貼到eclipse中即能夠運行。
package mysequence.machineleaning.association.fpgrowth;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStreamReader;import java.util.ArrayList;import java.util.Collections;import java.util.HashMap;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Set;public class Myfptree2 {public static final int support = 2; // 設定最小支援頻次為2 //儲存第一次的次序public Map<String,Integer> ordermap=new HashMap<String,Integer>();public LinkedList<LinkedList<String>> readF1() throws IOException { LinkedList<LinkedList<String>> records=new LinkedList<LinkedList<String>>();//String filePath="scripts/clustering/canopy/canopy.dat";String filePath="datafile/association/user2items.csv";BufferedReader br = new BufferedReader(new InputStreamReader( new FileInputStream(filePath))); for (String line = br.readLine(); line != null; line = br.readLine()) { if(line.length()==0||"".equals(line))continue; String[] str=line.split(","); LinkedList<String> litm=new LinkedList<String>(); for(int i=0;i<str.length;i++){ litm.add(str[i].trim()); } records.add(litm); } br.close(); return records; }//建立表頭鏈public LinkedList<TreeNode2> buildHeaderLink(LinkedList<LinkedList<String>> records){LinkedList<TreeNode2> header=null;if(records.size()>0){header=new LinkedList<TreeNode2>();}else{return null;}Map<String, TreeNode2> map = new HashMap<String, TreeNode2>();for(LinkedList<String> items:records){for(String item:items){//假設存在數量增1,不存在則新增if(map.containsKey(item)){map.get(item).Sum(1);}else{TreeNode2 node=new TreeNode2();node.setName(item);node.setCount(1);map.put(item, node);} }} // 把支援度大於(或等於)minSup的項增加到F1中 Set<String> names = map.keySet(); for (String name : names) { TreeNode2 tnode = map.get(name); if (tnode.getCount() >= support) { header.add(tnode); } } sort(header); String test="ddd";return header;}//選擇法排序,假設次數相等,則按名字排序,字典順序,先小寫後大寫public List<TreeNode2> sort(List<TreeNode2> list){int len=list.size();for(int i=0;i<len;i++){for(int j=i+1;j<len;j++){TreeNode2 node1=list.get(i);TreeNode2 node2=list.get(j);if(node1.getCount()<node2.getCount()){TreeNode2 tmp=new TreeNode2();tmp=node2;list.remove(j);//list指定位置插入,原來的>=j元素都會往下移,不會刪除,所以插入前要刪除掉原來的元素list.add(j,node1);list.remove(i);list.add(i,tmp);}//假設次數相等,則按名字排序,字典順序,先小寫後大寫if(node1.getCount()==node2.getCount()){String name1=node1.getName();String name2=node2.getName();int flag=name1.compareTo(name2);if(flag>0){TreeNode2 tmp=new TreeNode2();tmp=node2;list.remove(j);//list指定位置插入,原來的>=j元素都會往下移。不會刪除,所以插入前要刪除掉原來的元素list.add(j,node1);list.remove(i);list.add(i,tmp);}}}}return list;}//選擇法排序。降序,假設同名按L 中的次序排序public List<String> itemsort(LinkedList<String> lis,List<TreeNode2> header){//List<String> list=new ArrayList<String>();//選擇法排序int len=lis.size();for(int i=0;i<len;i++){for(int j=i+1;j<len;j++){String key1=lis.get(i);String key2=lis.get(j);Integer value1=findcountByname(key1,header);if(value1==-1)continue;Integer value2=findcountByname(key2,header);if(value2==-1)continue;if(value1<value2){String tmp=key2;lis.remove(j);lis.add(j,key1);lis.remove(i);lis.add(i,tmp);}if(value1==value2){int v1=ordermap.get(key1);int v2=ordermap.get(key2);if(v1>v2){String tmp=key2;lis.remove(j);lis.add(j,key1);lis.remove(i);lis.add(i,tmp);}} }}return lis;}public Integer findcountByname(String itemname,List<TreeNode2> header){Integer count=-1;for(TreeNode2 node:header){if(node.getName().equals(itemname)){count= node.getCount();}}return count;}/** * * @param records 構建樹的記錄,如I1,I2,I3 * @param header 韓書中介紹的表頭 * @return 返回構建好的樹 */public TreeNode2 builderFpTree(LinkedList<LinkedList<String>> records,List<TreeNode2> header){ TreeNode2 root; if(records.size()<=0){ return null; } root=new TreeNode2(); for(LinkedList<String> items:records){ itemsort(items,header); addNode(root,items,header);}String dd="dd";String test=dd;return root;}//當已經有分枝存在的時候。推斷新來的節點是否屬於該分枝的某個節點。或所有重合,遞迴public TreeNode2 addNode(TreeNode2 root,LinkedList<String> items,List<TreeNode2> header){if(items.size()<=0)return null;String item=items.poll();//當前節點的孩子節點不包括該節點,那麼另外建立一支分支。TreeNode2 node=root.findChild(item);if(node==null){ node=new TreeNode2();node.setName(item);node.setCount(1);node.setParent(root);root.addChild(node);//加將各個節點加到鏈頭中 for(TreeNode2 head:header){if(head.getName().equals(item)){while(head.getNextHomonym()!=null){head=head.getNextHomonym();}head.setNextHomonym(node);break;}}//加將各個節點加到鏈頭中}else{node.setCount(node.getCount()+1);} addNode(node,items,header);return root;}//從葉子找到根節點。遞迴之public void toroot(TreeNode2 node,LinkedList<String> newrecord){if(node.getParent()==null)return;String name=node.getName();newrecord.add(name);toroot(node.getParent(),newrecord);}//對條件FP-tree樹進行組合,以求出頻繁項集public void combineItem(TreeNode2 node,LinkedList<String> newrecord,String Item){if(node.getParent()==null)return;String name=node.getName();newrecord.add(name);toroot(node.getParent(),newrecord);}//fp-growthpublic void fpgrowth(LinkedList<LinkedList<String>> records,String item){//儲存新的條件模式基的各個記錄,以又一次構造FP-treeLinkedList<LinkedList<String>> newrecords=new LinkedList<LinkedList<String>>();//構建鏈頭LinkedList<TreeNode2> header=buildHeaderLink(records);//建立FP-TreeTreeNode2 fptree= builderFpTree(records,header);//結束遞迴的條件if(header.size()<=0||fptree==null){System.out.println("-----------------");return;}//列印結果,輸出頻繁項集if(item!=null){//尋找條件模式基,從鏈尾開始for(int i=header.size()-1;i>=0;i--){TreeNode2 head=header.get(i);String itemname=head.getName();Integer count=0;while(head.getNextHomonym()!=null){head=head.getNextHomonym();//葉子count等於多少。就算多少條記錄count=count+head.getCount();}//列印頻繁項集System.out.println(head.getName()+","+item+"\t"+count);}}//尋找條件模式基,從鏈尾開始for(int i=header.size()-1;i>=0;i--){TreeNode2 head=header.get(i);String itemname;//再組合if(item==null){itemname=head.getName();}else{itemname=head.getName()+","+item;}while(head.getNextHomonym()!=null){head=head.getNextHomonym();//葉子count等於多少,就算多少條記錄Integer count=head.getCount();for(int n=0;n<count;n++){ LinkedList<String> record=new LinkedList<String>(); toroot(head.getParent(),record); newrecords.add(record);}}//System.out.println("-----------------");//遞迴之,以求子FP-Treefpgrowth(newrecords,itemname);} }//儲存次序。此步也能夠省略,為了降低再加工結果的麻煩而加public void orderF1(LinkedList<TreeNode2> orderheader){for(int i=0;i<orderheader.size();i++){TreeNode2 node=orderheader.get(i);ordermap.put(node.getName(), i);}}public static void main(String[] args) throws IOException {// TODO Auto-generated method stub/*String s1="i1";int flag=s1.compareTo("I1");System.out.println(flag);*///讀取資料Myfptree2 fpg=new Myfptree2();LinkedList<LinkedList<String>> records=fpg.readF1();LinkedList<TreeNode2> orderheader=fpg.buildHeaderLink(records);fpg.orderF1(orderheader); fpg.fpgrowth(records,null);}}
樹的結構:
package mysequence.machineleaning.association.fpgrowth;import java.util.ArrayList;import java.util.List;public class TreeNode2 implements Comparable<TreeNode2>{ private String name; // 節點名稱 private Integer count; // 計數 private TreeNode2 parent; // 父節點 private List<TreeNode2> children; // 子節點 private TreeNode2 nextHomonym; // 下一個同名節點 public TreeNode2() { }public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getCount() {return count;}public void setCount(Integer count) {this.count = count;}public void Sum(Integer count) {this.count =this.count+count;}public TreeNode2 getParent() {return parent;}public void setParent(TreeNode2 parent) {this.parent = parent;}public List<TreeNode2> getChildren() {return children;}public void setChildren(List<TreeNode2> children) {this.children = children;}public TreeNode2 getNextHomonym() {return nextHomonym;}public void setNextHomonym(TreeNode2 nextHomonym) {this.nextHomonym = nextHomonym;} /** * 加入一個節點 * @param child */ public void addChild(TreeNode2 child) { if (this.getChildren() == null) { List<TreeNode2> list = new ArrayList<TreeNode2>(); list.add(child); this.setChildren(list); } else { this.getChildren().add(child); } } /** * 是否存在著該節點,存在返回該節點,不存在返回空 * @param name * @return */ public TreeNode2 findChild(String name) { List<TreeNode2> children = this.getChildren(); if (children != null) { for (TreeNode2 child : children) { if (child.getName().equals(name)) { return child; } } } return null; } @Override public int compareTo(TreeNode2 arg0) { // TODO Auto-generated method stub int count0 = arg0.getCount(); // 跟預設的比較大小相反。導致調用Arrays.sort()時是按降序排列 return count0 - this.count; }}
java實現fp-growth演算法