GSP序列模式分析算法

参考资料:http://blog.csdn.net/zone_programming/article/details/42032309

更多数据挖掘代码:https://github.com/linyiqun/DataMiningAlgorithm

介绍

GSP算法是序列模式挖掘算法的一种,他是一种类Apriori的一种,整个过程与Apriori算法比较类似,不过在细节上会略有不同,在下面的描述中,将会有所描述。GSP在原有的频繁模式定义的概念下,增加了3个的概念。

1、加入时间约束min_gap,max_gap,要求原来的连续变为只要满足在规定的min_gap到max_gap之间即可。

2、加入time_windows_size,只要在windows_size内的item,都可以被认为是同一ItemSet。

3、加入分类标准。

以上3点新的中的第一条特征将会在后面的算法中着重展现。

算法原理

1、根据所输入的序列,找出所有的单项集,即1频繁模式,这里会经过最小支持度阈值的判断。

2、根据1频繁模式进行连接运算,产生2频繁模式,这里会有进行最小阈值的判断。

3、根据2频繁模式连接产生3频繁模式,会经过最小支持度判断和剪枝操作,剪枝操作的原理在于判断他的所有子集是否也全是频繁模式。

4、3频繁模式不断的挖掘知道不能够产生出候选集为止。

连接操作的原理

2个序列,全部变为item列表的形式,如果a序列去掉第1个元素后,b序列去掉最后1个序列,2个序列的item完全一致,则代表可以连接,由b的最后一个元素加入到a中,至于是以独立项集的身份加入还是加入到a中最后1个项集中取决于b中的最后一个元素所属项集是否为单项项集。

时间约束计算

这个是用在支持度计数使用的,GSP算法的支持度计算不是那么简单,比如序列判断<2, <3, 4>>是否在序列<(1,5), 2 , <3, 4>, 2>,这就不能仅仅判断序列中是否只包含2,<3, 4>就行了,还要满足时间间隔约束,这就要把2,和<3,4>的所有出现时间都找出来,然后再里面找出一条满足时间约束的路径就算包含。时间的定义是从左往右起1.2,3...继续,以1个项集为单位,所有2的时间有2个分别为t=2和t=4,然后同理,因为<3,4>在序列中只有1次,所以时间为t=3,所以问题就变为了下面一个数组的问题

2  4

3

从时间数组的上往下,通过对多个时间的组合,找出1条满足时间约束的方案,这里的方案只有2-3,4-3,然后判断时间间隔,如果存在这样的方式,则代表此序列支持所给定序列,支持度值加1,这个算法在程序的实现中是比较复杂的。

算法的代码实现

测试数据输入(格式:事务ID item数 item1 item2.....):

[java]  view plain copy print ?
  1. 1 2 1 5  
  2. 1 1 2  
  3. 1 1 3  
  4. 1 1 4  
  5. 2 1 1  
  6. 2 1 3  
  7. 2 1 4  
  8. 2 2 3 5  
  9. 3 1 1  
  10. 3 1 2  
  11. 3 1 3  
  12. 3 1 4  
  13. 3 1 5  
  14. 4 1 1  
  15. 4 1 3  
  16. 4 1 5  
  17. 5 1 4  
  18. 5 1 5  
最后组成的序列为:

<(1,5) 2 3 4>

<1 3 4 (3,5)>

<1 2 3 4 5>

<1 3 5>

<4 5>

也就是说同一序列都是同事务的。下面是关键的类

Sequence.java:

[java]  view plain copy print ?
  1. package DataMining_GSP;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. /** 
  6.  * 序列,每个序列内部包含多组ItemSet项集 
  7.  *  
  8.  * @author lyq 
  9.  *  
  10.  */  
  11. public class Sequence implements Comparable, Cloneable {  
  12.     // 序列所属事务ID  
  13.     private int trsanctionID;  
  14.     // 项集列表  
  15.     private ArrayList itemSetList;  
  16.   
  17.     public Sequence(int trsanctionID) {  
  18.         this.trsanctionID = trsanctionID;  
  19.         this.itemSetList = new ArrayList<>();  
  20.     }  
  21.   
  22.     public Sequence() {  
  23.         this.itemSetList = new ArrayList<>();  
  24.     }  
  25.   
  26.     public int getTrsanctionID() {  
  27.         return trsanctionID;  
  28.     }  
  29.   
  30.     public void setTrsanctionID(int trsanctionID) {  
  31.         this.trsanctionID = trsanctionID;  
  32.     }  
  33.   
  34.     public ArrayList getItemSetList() {  
  35.         return itemSetList;  
  36.     }  
  37.   
  38.     public void setItemSetList(ArrayList itemSetList) {  
  39.         this.itemSetList = itemSetList;  
  40.     }  
  41.   
  42.     /** 
  43.      * 取出序列中第一个项集的第一个元素 
  44.      *  
  45.      * @return 
  46.      */  
  47.     public Integer getFirstItemSetNum() {  
  48.         return this.getItemSetList().get(0).getItems().get(0);  
  49.     }  
  50.   
  51.     /** 
  52.      * 获取序列中最后一个项集 
  53.      *  
  54.      * @return 
  55.      */  
  56.     public ItemSet getLastItemSet() {  
  57.         return getItemSetList().get(getItemSetList().size() - 1);  
  58.     }  
  59.   
  60.     /** 
  61.      * 获取序列中最后一个项集的最后一个一个元素 
  62.      *  
  63.      * @return 
  64.      */  
  65.     public Integer getLastItemSetNum() {  
  66.         ItemSet lastItemSet = getItemSetList().get(getItemSetList().size() - 1);  
  67.         int lastItemNum = lastItemSet.getItems().get(  
  68.                 lastItemSet.getItems().size() - 1);  
  69.   
  70.         return lastItemNum;  
  71.     }  
  72.   
  73.     /** 
  74.      * 判断序列中最后一个项集是否为单一的值 
  75.      *  
  76.      * @return 
  77.      */  
  78.     public boolean isLastItemSetSingleNum() {  
  79.         ItemSet lastItemSet = getItemSetList().get(getItemSetList().size() - 1);  
  80.         int size = lastItemSet.getItems().size();  
  81.   
  82.         return size == 1 ? true : false;  
  83.     }  
  84.   
  85.     @Override  
  86.     public int compareTo(Sequence o) {  
  87.         // TODO Auto-generated method stub  
  88.         return this.getFirstItemSetNum().compareTo(o.getFirstItemSetNum());  
  89.     }  
  90.   
  91.     @Override  
  92.     protected Object clone() throws CloneNotSupportedException {  
  93.         // TODO Auto-generated method stub  
  94.         return super.clone();  
  95.     }  
  96.       
  97.     /** 
  98.      * 拷贝一份一模一样的序列 
  99.      */  
  100.     public Sequence copySeqence(){  
  101.         Sequence copySeq = new Sequence();  
  102.         for(ItemSet itemSet: this.itemSetList){  
  103.             copySeq.getItemSetList().add(new ItemSet(itemSet.copyItems()));  
  104.         }  
  105.           
  106.         return copySeq;  
  107.     }  
  108.   
  109.     /** 
  110.      * 比较2个序列是否相等,需要判断内部的每个项集是否完全一致 
  111.      *  
  112.      * @param seq 
  113.      *            比较的序列对象 
  114.      * @return 
  115.      */  
  116.     public boolean compareIsSame(Sequence seq) {  
  117.         boolean result = true;  
  118.         ArrayList itemSetList2 = seq.getItemSetList();  
  119.         ItemSet tempItemSet1;  
  120.         ItemSet tempItemSet2;  
  121.   
  122.         if (itemSetList2.size() != this.itemSetList.size()) {  
  123.             return false;  
  124.         }  
  125.         for (int i = 0; i < itemSetList2.size(); i++) {  
  126.             tempItemSet1 = this.itemSetList.get(i);  
  127.             tempItemSet2 = itemSetList2.get(i);  
  128.   
  129.             if (!tempItemSet1.compareIsSame(tempItemSet2)) {  
  130.                 // 只要不相等,直接退出函数  
  131.                 result = false;  
  132.                 break;  
  133.             }  
  134.         }  
  135.   
  136.         return result;  
  137.     }  
  138.   
  139.     /** 
  140.      * 生成此序列的所有子序列 
  141.      *  
  142.      * @return 
  143.      */  
  144.     public ArrayList createChildSeqs() {  
  145.         ArrayList childSeqs = new ArrayList<>();  
  146.         ArrayList tempItems;  
  147.         Sequence tempSeq = null;  
  148.         ItemSet tempItemSet;  
  149.   
  150.         for (int i = 0; i < this.itemSetList.size(); i++) {  
  151.             tempItemSet = itemSetList.get(i);  
  152.             if (tempItemSet.getItems().size() == 1) {  
  153.                 tempSeq = this.copySeqence();  
  154.                   
  155.                 // 如果只有项集中只有1个元素,则直接移除  
  156.                 tempSeq.itemSetList.remove(i);  
  157.                 childSeqs.add(tempSeq);  
  158.             } else {  
  159.                 tempItems = tempItemSet.getItems();  
  160.                 for (int j = 0; j < tempItems.size(); j++) {  
  161.                     tempSeq = this.copySeqence();  
  162.   
  163.                     // 在拷贝的序列中移除一个数字  
  164.                     tempSeq.getItemSetList().get(i).getItems().remove(j);  
  165.                     childSeqs.add(tempSeq);  
  166.                 }  
  167.             }  
  168.         }  
  169.   
  170.         return childSeqs;  
  171.     }  
  172.   
  173. }  
ItemSet.java:

[java]  view plain copy print ?
  1. package DataMining_GSP;  
  2.   
  3. import java.util.ArrayList;  
  4.   
  5. /** 
  6.  * 序列中的子项集 
  7.  *  
  8.  * @author lyq 
  9.  *  
  10.  */  
  11. public class ItemSet {  
  12.     /** 
  13.      * 项集中保存的是数字项数组 
  14.      */  
  15.     private ArrayList items;  
  16.   
  17.     public ItemSet(String[] itemStr) {  
  18.         items = new ArrayList<>();  
  19.         for (String s : itemStr) {  
  20.             items.add(Integer.parseInt(s));  
  21.         }  
  22.     }  
  23.   
  24.     public ItemSet(int[] itemNum) {  
  25.         items = new ArrayList<>();  
  26.         for (int num : itemNum) {  
  27.             items.add(num);  
  28.         }  
  29.     }  
  30.       
  31.     public ItemSet(ArrayList itemNum) {  
  32.         this.items = itemNum;  
  33.     }  
  34.   
  35.     public ArrayList getItems() {  
  36.         return items;  
  37.     }  
  38.   
  39.     public void setItems(ArrayList items) {  
  40.         this.items = items;  
  41.     }  
  42.   
  43.     /** 
  44.      * 判断2个项集是否相等 
  45.      *  
  46.      * @param itemSet 
  47.      *            比较对象 
  48.      * @return 
  49.      */  
  50.     public boolean compareIsSame(ItemSet itemSet) {  
  51.         boolean result = true;  
  52.   
  53.         if (this.items.size() != itemSet.items.size()) {  
  54.             return false;  
  55.         }  
  56.   
  57.         for (int i = 0; i < itemSet.items.size(); i++) {  
  58.             if (this.items.get(i) != itemSet.items.get(i)) {  
  59.                 // 只要有值不相等,直接算作不相等  
  60.                 result = false;  
  61.                 break;  
  62.             }  
  63.         }  
  64.   
  65.         return result;  
  66.     }  
  67.   
  68.     /** 
  69.      * 拷贝项集中同样的数据一份 
  70.      *  
  71.      * @return 
  72.      */  
  73.     public ArrayList copyItems() {  
  74.         ArrayList copyItems = new ArrayList<>();  
  75.   
  76.         for (int num : this.items) {  
  77.             copyItems.add(num);  
  78.         }  
  79.   
  80.         return copyItems;  
  81.     }  
  82. }  
GSPTool.java(算法工具类):

[java]  view plain copy print ?
  1. package DataMining_GSP;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.File;  
  5. import java.io.FileReader;  
  6. import java.io.IOException;  
  7. import java.util.ArrayList;  
  8. import java.util.Collections;  
  9. import java.util.HashMap;  
  10. import java.util.Map;  
  11.   
  12. /** 
  13.  * GSP序列模式分析算法 
  14.  *  
  15.  * @author lyq 
  16.  *  
  17.  */  
  18. public class GSPTool {  
  19.     // 测试数据文件地址  
  20.     private String filePath;  
  21.     // 最小支持度阈值  
  22.     private int minSupportCount;  
  23.     // 时间最小间隔  
  24.     private int min_gap;  
  25.     // 时间最大间隔  
  26.     private int max_gap;  
  27.     // 原始数据序列  
  28.     private ArrayList totalSequences;  
  29.     // GSP算法中产生的所有的频繁项集序列  
  30.     private ArrayList totalFrequencySeqs;  
  31.     // 序列项数字对时间的映射图容器  
  32.     private ArrayList>> itemNum2Time;  
  33.   
  34.     public GSPTool(String filePath, int minSupportCount, int min_gap,  
  35.             int max_gap) {  
  36.         this.filePath = filePath;  
  37.         this.minSupportCount = minSupportCount;  
  38.         this.min_gap = min_gap;  
  39.         this.max_gap = max_gap;  
  40.         totalFrequencySeqs = new ArrayList<>();  
  41.         readDataFile();  
  42.     }  
  43.   
  44.     /** 
  45.      * 从文件中读取数据 
  46.      */  
  47.     private void readDataFile() {  
  48.         File file = new File(filePath);  
  49.         ArrayList dataArray = new ArrayList();  
  50.   
  51.         try {  
  52.             BufferedReader in = new BufferedReader(new FileReader(file));  
  53.             String str;  
  54.             String[] tempArray;  
  55.             while ((str = in.readLine()) != null) {  
  56.                 tempArray = str.split(" ");  
  57.                 dataArray.add(tempArray);  
  58.             }  
  59.             in.close();  
  60.         } catch (IOException e) {  
  61.             e.getStackTrace();  
  62.         }  
  63.   
  64.         HashMap mapSeq = new HashMap<>();  
  65.         Sequence seq;  
  66.         ItemSet itemSet;  
  67.         int tID;  
  68.         String[] itemStr;  
  69.         for (String[] str : dataArray) {  
  70.             tID = Integer.parseInt(str[0]);  
  71.             itemStr = new String[Integer.parseInt(str[1])];  
  72.             System.arraycopy(str, 2, itemStr, 0, itemStr.length);  
  73.             itemSet = new ItemSet(itemStr);  
  74.   
  75.             if (mapSeq.containsKey(tID)) {  
  76.                 seq = mapSeq.get(tID);  
  77.             } else {  
  78.                 seq = new Sequence(tID);  
  79.             }  
  80.             seq.getItemSetList().add(itemSet);  
  81.             mapSeq.put(tID, seq);  
  82.         }  
  83.   
  84.         // 将序列图加入到序列List中  
  85.         totalSequences = new ArrayList<>();  
  86.         for (Map.Entry entry : mapSeq.entrySet()) {  
  87.             totalSequences.add((Sequence) entry.getValue());  
  88.         }  
  89.     }  
  90.   
  91.     /** 
  92.      * 生成1频繁项集 
  93.      *  
  94.      * @return 
  95.      */  
  96.     private ArrayList generateOneFrequencyItem() {  
  97.         int count = 0;  
  98.         int currentTransanctionID = 0;  
  99.         Sequence tempSeq;  
  100.         ItemSet tempItemSet;  
  101.         HashMap itemNumMap = new HashMap<>();  
  102.         ArrayList seqList = new ArrayList<>();  
  103.   
  104.         for (Sequence seq : totalSequences) {  
  105.             for (ItemSet itemSet : seq.getItemSetList()) {  
  106.                 for (int num : itemSet.getItems()) {  
  107.                     // 如果没有此种类型项,则进行添加操作  
  108.                     if (!itemNumMap.containsKey(num)) {  
  109.                         itemNumMap.put(num, 1);  
  110.                     }  
  111.                 }  
  112.             }  
  113.         }  
  114.           
  115.         boolean isContain = false;  
  116.         int number = 0;  
  117.         for (Map.Entry entry : itemNumMap.entrySet()) {  
  118.             count = 0;  
  119.             number = (int) entry.getKey();  
  120.             for (Sequence seq : totalSequences) {  
  121.                 isContain = false;  
  122.                   
  123.                 for (ItemSet itemSet : seq.getItemSetList()) {  
  124.                     for (int num : itemSet.getItems()) {  
  125.                         if (num == number) {  
  126.                             isContain = true;  
  127.                             break;  
  128.                         }  
  129.                     }  
  130.                       
  131.                     if(isContain){  
  132.                         break;  
  133.                     }  
  134.                 }  
  135.                   
  136.                 if(isContain){  
  137.                     count++;  
  138.                 }  
  139.             }  
  140.               
  141.             itemNumMap.put(number, count);  
  142.         }  
  143.           
  144.   
  145.         for (Map.Entry entry : itemNumMap.entrySet()) {  
  146.             count = (int) entry.getValue();  
  147.             if (count >= minSupportCount) {  
  148.                 tempSeq = new Sequence();  
  149.                 tempItemSet = new ItemSet(new int[] { (int) entry.getKey() });  
  150.   
  151.                 tempSeq.getItemSetList().add(tempItemSet);  
  152.                 seqList.add(tempSeq);  
  153.             }  
  154.   
  155.         }  
  156.         // 将序列升序排列  
  157.         Collections.sort(seqList);  
  158.         // 将频繁1项集加入总频繁项集列表中  
  159.         totalFrequencySeqs.addAll(seqList);  
  160.   
  161.         return seqList;  
  162.     }  
  163.   
  164.     /** 
  165.      * 通过1频繁项集连接产生2频繁项集 
  166.      *  
  167.      * @param oneSeq 
  168.      *            1频繁项集序列 
  169.      * @return 
  170.      */  
  171.     private ArrayList generateTwoFrequencyItem(  
  172.             ArrayList oneSeq) {  
  173.         Sequence tempSeq;  
  174.         ArrayList resultSeq = new ArrayList<>();  
  175.         ItemSet tempItemSet;  
  176.         int num1;  
  177.         int num2;  
  178.   
  179.         // 假如将,2个1频繁项集做连接组合,可以分为,4个序列模式  
  180.         // 注意此时的每个序列中包含2个独立项集  
  181.         for (int i = 0; i < oneSeq.size(); i++) {  
  182.             num1 = oneSeq.get(i).getFirstItemSetNum();  
  183.             for (int j = 0; j < oneSeq.size(); j++) {  
  184.                 num2 = oneSeq.get(j).getFirstItemSetNum();  
  185.   
  186.                 tempSeq = new Sequence();  
  187.                 tempItemSet = new ItemSet(new int[] { num1 });  
  188.                 tempSeq.getItemSetList().add(tempItemSet);  
  189.                 tempItemSet = new ItemSet(new int[] { num2 });  
  190.                 tempSeq.getItemSetList().add(tempItemSet);  
  191.   
  192.                 if (countSupport(tempSeq) >= minSupportCount) {  
  193.                     resultSeq.add(tempSeq);  
  194.                 }  
  195.             }  
  196.         }  
  197.   
  198.         // 上面连接还有1种情况是每个序列中只包含有一个项集的情况,此时a,b的划分则是<(a,a)> <(a,b)> <(b,b)>  
  199.         for (int i = 0; i < oneSeq.size(); i++) {  
  200.             num1 = oneSeq.get(i).getFirstItemSetNum();  
  201.             for (int j = i; j < oneSeq.size(); j++) {  
  202.                 num2 = oneSeq.get(j).getFirstItemSetNum();  
  203.   
  204.                 tempSeq = new Sequence();  
  205.                 tempItemSet = new ItemSet(new int[] { num1, num2 });  
  206.                 tempSeq.getItemSetList().add(tempItemSet);  
  207.   
  208.                 if (countSupport(tempSeq) >= minSupportCount) {  
  209.                     resultSeq.add(tempSeq);  
  210.                 }  
  211.             }  
  212.         }  
  213.         // 同样将2频繁项集加入到总频繁项集中  
  214.         totalFrequencySeqs.addAll(resultSeq);  
  215.   
  216.         return resultSeq;  
  217.     }  
  218.   
  219.     /** 
  220.      * 根据上次的频繁集连接产生新的侯选集 
  221.      *  
  222.      * @param seqList 
  223.      *            上次产生的候选集 
  224.      * @return 
  225.      */  
  226.     private ArrayList generateCandidateItem(  
  227.             ArrayList seqList) {  
  228.         Sequence tempSeq;  
  229.         ArrayList tempNumArray;  
  230.         ArrayList resultSeq = new ArrayList<>();  
  231.         // 序列数字项列表  
  232.         ArrayList> seqNums = new ArrayList<>();  
  233.   
  234.         for (int i = 0; i < seqList.size(); i++) {  
  235.             tempNumArray = new ArrayList<>();  
  236.             tempSeq = seqList.get(i);  
  237.             for (ItemSet itemSet : tempSeq.getItemSetList()) {  
  238.                 tempNumArray.addAll(itemSet.copyItems());  
  239.             }  
  240.             seqNums.add(tempNumArray);  
  241.         }  
  242.   
  243.         ArrayList array1;  
  244.         ArrayList array2;  
  245.         // 序列i,j的拷贝  
  246.         Sequence seqi = null;  
  247.         Sequence seqj = null;  
  248.         // 判断是否能够连接,默认能连接  
  249.         boolean canConnect = true;  
  250.         // 进行连接运算,包括自己与自己连接  
  251.         for (int i = 0; i < seqNums.size(); i++) {  
  252.             for (int j = 0; j < seqNums.size(); j++) {  
  253.                 array1 = (ArrayList) seqNums.get(i).clone();  
  254.                 array2 = (ArrayList) seqNums.get(j).clone();  
  255.   
  256.                 // 将第一个数字组去掉第一个,第二个数字组去掉最后一个,如果剩下的部分相等,则可以连接  
  257.                 array1.remove(0);  
  258.                 array2.remove(array2.size() - 1);  
  259.   
  260.                 canConnect = true;  
  261.                 for (int k = 0; k < array1.size(); k++) {  
  262.                     if (array1.get(k) != array2.get(k)) {  
  263.                         canConnect = false;  
  264.                         break;  
  265.                     }  
  266.                 }  
  267.   
  268.                 if (canConnect) {  
  269.                     seqi = seqList.get(i).copySeqence();  
  270.                     seqj = seqList.get(j).copySeqence();  
  271.   
  272.                     int lastItemNum = seqj.getLastItemSetNum();  
  273.                     if (seqj.isLastItemSetSingleNum()) {  
  274.                         // 如果j序列的最后项集为单一值,则最后一个数字以独立项集加入i序列  
  275.                         ItemSet itemSet = new ItemSet(new int[] { lastItemNum });  
  276.                         seqi.getItemSetList().add(itemSet);  
  277.                     } else {  
  278.                         // 如果j序列的最后项集为非单一值,则最后一个数字加入i序列最后一个项集中  
  279.                         ItemSet itemSet = seqi.getLastItemSet();  
  280.                         itemSet.getItems().add(lastItemNum);  
  281.                     }  
  282.   
  283.                     // 判断是否超过最小支持度阈值  
  284.                     if (isChildSeqContained(seqi)  
  285.                             && countSupport(seqi) >= minSupportCount) {  
  286.                         resultSeq.add(seqi);  
  287.                     }  
  288.                 }  
  289.             }  
  290.         }  
  291.   
  292.         totalFrequencySeqs.addAll(resultSeq);  
  293.         return resultSeq;  
  294.     }  
  295.   
  296.     /** 
  297.      * 判断此序列的所有子序列是否也是频繁序列 
  298.      *  
  299.      * @param seq 
  300.      *            待比较序列 
  301.      * @return 
  302.      */  
  303.     private boolean isChildSeqContained(Sequence seq) {  
  304.         boolean isContained = false;  
  305.         ArrayList childSeqs;  
  306.   
  307.         childSeqs = seq.createChildSeqs();  
  308.         for (Sequence tempSeq : childSeqs) {  
  309.             isContained = false;  
  310.   
  311.             for (Sequence frequencySeq : totalFrequencySeqs) {  
  312.                 if (tempSeq.compareIsSame(frequencySeq)) {  
  313.                     isContained = true;  
  314.                     break;  
  315.                 }  
  316.             }  
  317.   
  318.             if (!isContained) {  
  319.                 break;  
  320.             }  
  321.         }  
  322.   
  323.         return isContained;  
  324.     }  
  325.   
  326.     /** 
  327.      * 候选集判断支持度的值 
  328.      *  
  329.      * @param seq 
  330.      *            待判断序列 
  331.      * @return 
  332.      */  
  333.     private int countSupport(Sequence seq) {  
  334.         int count = 0;  
  335.         int matchNum = 0;  
  336.         Sequence tempSeq;  
  337.         ItemSet tempItemSet;  
  338.         HashMap timeMap;  
  339.         ArrayList itemSetList;  
  340.         ArrayList> numArray = new ArrayList<>();  
  341.         // 每项集对应的时间链表  
  342.         ArrayList> timeArray = new ArrayList<>();  
  343.   
  344.         for (ItemSet itemSet : seq.getItemSetList()) {  
  345.             numArray.add(itemSet.getItems());  
  346.         }  
  347.   
  348.         for (int i = 0; i < totalSequences.size(); i++) {  
  349.             timeArray = new ArrayList<>();  
  350.   
  351.             for (int s = 0; s < numArray.size(); s++) {  
  352.                 ArrayList childNum = numArray.get(s);  
  353.                 ArrayList localTime = new ArrayList<>();  
  354.                 tempSeq = totalSequences.get(i);  
  355.                 itemSetList = tempSeq.getItemSetList();  
  356.   
  357.                 for (int j = 0; j < itemSetList.size(); j++) {  
  358.                     tempItemSet = itemSetList.get(j);  
  359.                     matchNum = 0;  
  360.                     int t = 0;  
  361.   
  362.                     if (tempItemSet.getItems().size() == childNum.size()) {  
  363.                         timeMap = itemNum2Time.get(i).get(j);  
  364.                         // 只有当项集长度匹配时才匹配  
  365.                         for (int k = 0; k < childNum.size(); k++) {  
  366.                             if (timeMap.containsKey(childNum.get(k))) {  
  367.                                 matchNum++;  
  368.                                 t = timeMap.get(childNum.get(k));  
  369.                             }  
  370.                         }  
  371.   
  372.                         // 如果完全匹配,则记录时间  
  373.                         if (matchNum == childNum.size()) {  
  374.                             localTime.add(t);  
  375.                         }  
  376.                     }  
  377.   
  378.                 }  
  379.   
  380.                 if (localTime.size() > 0) {  
  381.                     timeArray.add(localTime);  
  382.                 }  
  383.             }  
  384.   
  385.             // 判断时间是否满足时间最大最小约束,如果满足,则此条事务包含候选事务  
  386.             if (timeArray.size() == numArray.size()  
  387.                     && judgeTimeInGap(timeArray)) {  
  388.                 count++;  
  389.             }  
  390.         }  
  391.   
  392.         return count;  
  393.     }  
  394.   
  395.     /** 
  396.      * 判断事务是否满足时间约束 
  397.      *  
  398.      * @param timeArray 
  399.      *            时间数组,每行代表各项集的在事务中的发生时间链表 
  400.      * @return 
  401.      */  
  402.     private boolean judgeTimeInGap(ArrayList> timeArray) {  
  403.         boolean result = false;  
  404.         int preTime = 0;  
  405.         ArrayList firstTimes = timeArray.get(0);  
  406.         timeArray.remove(0);  
  407.   
  408.         if (timeArray.size() == 0) {  
  409.             return false;  
  410.         }  
  411.   
  412.         for (int i = 0; i < firstTimes.size(); i++) {  
  413.             preTime = firstTimes.get(i);  
  414.   
  415.             if (dfsJudgeTime(preTime, timeArray)) {  
  416.                 result = true;  
  417.                 break;  
  418.             }  
  419.         }  
  420.   
  421.         return result;  
  422.     }  
  423.   
  424.     /** 
  425.      * 深度优先遍历时间,判断是否有符合条件的时间间隔 
  426.      *  
  427.      * @param preTime 
  428.      * @param timeArray 
  429.      * @return 
  430.      */  
  431.     private boolean dfsJudgeTime(int preTime,  
  432.             ArrayList> timeArray) {  
  433.         boolean result = false;  
  434.         ArrayList> timeArrayClone = (ArrayList>) timeArray  
  435.                 .clone();  
  436.         ArrayList firstItemItem = timeArrayClone.get(0);  
  437.   
  438.         for (int i = 0; i < firstItemItem.size(); i++) {  
  439.             if (firstItemItem.get(i) - preTime >= min_gap  
  440.                     && firstItemItem.get(i) - preTime <= max_gap) {  
  441.                 // 如果此2项间隔时间满足时间约束,则继续往下递归  
  442.                 preTime = firstItemItem.get(i);  
  443.                 timeArrayClone.remove(0);  
  444.   
  445.                 if (timeArrayClone.size() == 0) {  
  446.                     return true;  
  447.                 } else {  
  448.                     result = dfsJudgeTime(preTime, timeArrayClone);  
  449.                     if (result) {  
  450.                         return true;  
  451.                     }  
  452.                 }  
  453.             }  
  454.         }  
  455.   
  456.         return result;  
  457.     }  
  458.   
  459.     /** 
  460.      * 初始化序列项到时间的序列图,为了后面的时间约束计算 
  461.      */  
  462.     private void initItemNumToTimeMap() {  
  463.         Sequence seq;  
  464.         itemNum2Time = new ArrayList<>();  
  465.         HashMap tempMap;  
  466.         ArrayList> tempMapList;  
  467.   
  468.         for (int i = 0; i < totalSequences.size(); i++) {  
  469.             seq = totalSequences.get(i);  
  470.             tempMapList = new ArrayList<>();  
  471.   
  472.             for (int j = 0; j < seq.getItemSetList().size(); j++) {  
  473.                 ItemSet itemSet = seq.getItemSetList().get(j);  
  474.                 tempMap = new HashMap<>();  
  475.                 for (int itemNum : itemSet.getItems()) {  
  476.                     tempMap.put(itemNum, j + 1);  
  477.                 }  
  478.   
  479.                 tempMapList.add(tempMap);  
  480.             }  
  481.   
  482.             itemNum2Time.add(tempMapList);  
  483.         }  
  484.     }  
  485.   
  486.     /** 
  487.      * 进行GSP算法计算 
  488.      */  
  489.     public void gspCalculate() {  
  490.         ArrayList oneSeq;  
  491.         ArrayList twoSeq;  
  492.         ArrayList candidateSeq;  
  493.   
  494.         initItemNumToTimeMap();  
  495.         oneSeq = generateOneFrequencyItem();  
  496.         twoSeq = generateTwoFrequencyItem(oneSeq);  
  497.         candidateSeq = twoSeq;  
  498.   
  499.         // 不断连接生产候选集,直到没有产生出侯选集  
  500.         for (;;) {  
  501.             candidateSeq = generateCandidateItem(candidateSeq);  
  502.   
  503.             if (candidateSeq.size() == 0) {  
  504.                 break;  
  505.             }  
  506.         }  
  507.   
  508.         outputSeqence(totalFrequencySeqs);  
  509.   
  510.     }  
  511.   
  512.     /** 
  513.      * 输出序列列表信息 
  514.      *  
  515.      * @param outputSeqList 
  516.      *            待输出序列列表 
  517.      */  
  518.     private void outputSeqence(ArrayList outputSeqList) {  
  519.         for (Sequence seq : outputSeqList) {  
  520.             System.out.print("<");  
  521.             for (ItemSet itemSet : seq.getItemSetList()) {  
  522.                 System.out.print("(");  
  523.                 for (int num : itemSet.getItems()) {  
  524.                     System.out.print(num + ",");  
  525.                 }  
  526.                 System.out.print("), ");  
  527.             }  
  528.             System.out.println(">");  
  529.         }  
  530.     }  
  531.   
  532. }  
调用类Client.java:

[java]  view plain copy print ?
  1. package DataMining_GSP;  
  2.   
  3. /** 
  4.  * GSP序列模式分析算法 
  5.  * @author lyq 
  6.  * 
  7.  */  
  8. public class Client {  
  9.     public static void main(String[] args){  
  10.         String filePath = "C:\\Users\\lyq\\Desktop\\icon\\testInput.txt";  
  11.         //最小支持度阈值  
  12.         int minSupportCount = 2;  
  13.         //时间最小间隔  
  14.         int min_gap = 1;  
  15.         //施加最大间隔  
  16.         int max_gap = 5;  
  17.           
  18.         GSPTool tool = new GSPTool(filePath, minSupportCount, min_gap, max_gap);  
  19.         tool.gspCalculate();  
  20.     }  
  21. }  
算法的输出(挖掘出的所有频繁模式):

[java]  view plain copy print ?
  1. <(1,), >  
  2. <(2,), >  
  3. <(3,), >  
  4. <(4,), >  
  5. <(5,), >  
  6. <(1,), (3,), >  
  7. <(1,), (4,), >  
  8. <(1,), (5,), >  
  9. <(2,), (3,), >  
  10. <(2,), (4,), >  
  11. <(3,), (4,), >  
  12. <(3,), (5,), >  
  13. <(4,), (5,), >  
  14. <(1,), (3,), (4,), >  
  15. <(1,), (3,), (5,), >  
  16. <(2,), (3,), (4,), >  

算法实现的难点

1、算法花费了几天的时间,难点首先在于对算法原理本身的理解,网上对于此算法的资料特别少,而且不同的人所表达的意思 都有少许的不同,讲的也不是很详细,于是就通过阅读别人的代码理解GSP算法的原理,我的代码实现也是参考了参考资料的C语言的实现。

2、在实现时间约束的支持度计数统计的时候,调试了一段时间,做时间统计容易出错,因为层级实在太多容易搞晕。

3、还有1个是Sequence和ItemSet的拷贝时的引用问题,在产生新的序列时一定要深拷贝1个否则导致同一引用会把原数据给改掉的。

GSP算法和Apriori算法的比较

我是都实现过了GSP算法和Apriori算法的,后者是被称为关联规则挖掘算法,偏向于挖掘关联规则的,2个算法在连接的操作上有不一样的地方,还有在数据的构成方式上,Apriori的数据会简单一点,都是单项单项构成的,而且在做支持度统计的时候只需判断存在与否即可。不需要考虑时间约束。Apriori算法给定K项集,连接到K-1项集算法就停止了,而GSP算法是直到不能够产生候选集为止。

你可能感兴趣的:(算法)