• 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.....):

    1 2 1 5
    1 1 2
    1 1 3
    1 1 4
    2 1 1
    2 1 3
    2 1 4
    2 2 3 5
    3 1 1
    3 1 2
    3 1 3
    3 1 4
    3 1 5
    4 1 1
    4 1 3
    4 1 5
    5 1 4
    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:

    package DataMining_GSP;
    
    import java.util.ArrayList;
    
    /**
     * 序列,每个序列内部包含多组ItemSet项集
     * 
     * @author lyq
     * 
     */
    public class Sequence implements Comparable<Sequence>, Cloneable {
    	// 序列所属事务ID
    	private int trsanctionID;
    	// 项集列表
    	private ArrayList<ItemSet> itemSetList;
    
    	public Sequence(int trsanctionID) {
    		this.trsanctionID = trsanctionID;
    		this.itemSetList = new ArrayList<>();
    	}
    
    	public Sequence() {
    		this.itemSetList = new ArrayList<>();
    	}
    
    	public int getTrsanctionID() {
    		return trsanctionID;
    	}
    
    	public void setTrsanctionID(int trsanctionID) {
    		this.trsanctionID = trsanctionID;
    	}
    
    	public ArrayList<ItemSet> getItemSetList() {
    		return itemSetList;
    	}
    
    	public void setItemSetList(ArrayList<ItemSet> itemSetList) {
    		this.itemSetList = itemSetList;
    	}
    
    	/**
    	 * 取出序列中第一个项集的第一个元素
    	 * 
    	 * @return
    	 */
    	public Integer getFirstItemSetNum() {
    		return this.getItemSetList().get(0).getItems().get(0);
    	}
    
    	/**
    	 * 获取序列中最后一个项集
    	 * 
    	 * @return
    	 */
    	public ItemSet getLastItemSet() {
    		return getItemSetList().get(getItemSetList().size() - 1);
    	}
    
    	/**
    	 * 获取序列中最后一个项集的最后一个一个元素
    	 * 
    	 * @return
    	 */
    	public Integer getLastItemSetNum() {
    		ItemSet lastItemSet = getItemSetList().get(getItemSetList().size() - 1);
    		int lastItemNum = lastItemSet.getItems().get(
    				lastItemSet.getItems().size() - 1);
    
    		return lastItemNum;
    	}
    
    	/**
    	 * 判断序列中最后一个项集是否为单一的值
    	 * 
    	 * @return
    	 */
    	public boolean isLastItemSetSingleNum() {
    		ItemSet lastItemSet = getItemSetList().get(getItemSetList().size() - 1);
    		int size = lastItemSet.getItems().size();
    
    		return size == 1 ? true : false;
    	}
    
    	@Override
    	public int compareTo(Sequence o) {
    		// TODO Auto-generated method stub
    		return this.getFirstItemSetNum().compareTo(o.getFirstItemSetNum());
    	}
    
    	@Override
    	protected Object clone() throws CloneNotSupportedException {
    		// TODO Auto-generated method stub
    		return super.clone();
    	}
    	
    	/**
    	 * 拷贝一份一模一样的序列
    	 */
    	public Sequence copySeqence(){
    		Sequence copySeq = new Sequence();
    		for(ItemSet itemSet: this.itemSetList){
    			copySeq.getItemSetList().add(new ItemSet(itemSet.copyItems()));
    		}
    		
    		return copySeq;
    	}
    
    	/**
    	 * 比较2个序列是否相等,需要判断内部的每个项集是否完全一致
    	 * 
    	 * @param seq
    	 *            比较的序列对象
    	 * @return
    	 */
    	public boolean compareIsSame(Sequence seq) {
    		boolean result = true;
    		ArrayList<ItemSet> itemSetList2 = seq.getItemSetList();
    		ItemSet tempItemSet1;
    		ItemSet tempItemSet2;
    
    		if (itemSetList2.size() != this.itemSetList.size()) {
    			return false;
    		}
    		for (int i = 0; i < itemSetList2.size(); i++) {
    			tempItemSet1 = this.itemSetList.get(i);
    			tempItemSet2 = itemSetList2.get(i);
    
    			if (!tempItemSet1.compareIsSame(tempItemSet2)) {
    				// 只要不相等,直接退出函数
    				result = false;
    				break;
    			}
    		}
    
    		return result;
    	}
    
    	/**
    	 * 生成此序列的所有子序列
    	 * 
    	 * @return
    	 */
    	public ArrayList<Sequence> createChildSeqs() {
    		ArrayList<Sequence> childSeqs = new ArrayList<>();
    		ArrayList<Integer> tempItems;
    		Sequence tempSeq = null;
    		ItemSet tempItemSet;
    
    		for (int i = 0; i < this.itemSetList.size(); i++) {
    			tempItemSet = itemSetList.get(i);
    			if (tempItemSet.getItems().size() == 1) {
    				tempSeq = this.copySeqence();
    				
    				// 如果只有项集中只有1个元素,则直接移除
    				tempSeq.itemSetList.remove(i);
    				childSeqs.add(tempSeq);
    			} else {
    				tempItems = tempItemSet.getItems();
    				for (int j = 0; j < tempItems.size(); j++) {
    					tempSeq = this.copySeqence();
    
    					// 在拷贝的序列中移除一个数字
    					tempSeq.getItemSetList().get(i).getItems().remove(j);
    					childSeqs.add(tempSeq);
    				}
    			}
    		}
    
    		return childSeqs;
    	}
    
    }
    
    ItemSet.java:

    package DataMining_GSP;
    
    import java.util.ArrayList;
    
    /**
     * 序列中的子项集
     * 
     * @author lyq
     * 
     */
    public class ItemSet {
    	/**
    	 * 项集中保存的是数字项数组
    	 */
    	private ArrayList<Integer> items;
    
    	public ItemSet(String[] itemStr) {
    		items = new ArrayList<>();
    		for (String s : itemStr) {
    			items.add(Integer.parseInt(s));
    		}
    	}
    
    	public ItemSet(int[] itemNum) {
    		items = new ArrayList<>();
    		for (int num : itemNum) {
    			items.add(num);
    		}
    	}
    	
    	public ItemSet(ArrayList<Integer> itemNum) {
    		this.items = itemNum;
    	}
    
    	public ArrayList<Integer> getItems() {
    		return items;
    	}
    
    	public void setItems(ArrayList<Integer> items) {
    		this.items = items;
    	}
    
    	/**
    	 * 判断2个项集是否相等
    	 * 
    	 * @param itemSet
    	 *            比较对象
    	 * @return
    	 */
    	public boolean compareIsSame(ItemSet itemSet) {
    		boolean result = true;
    
    		if (this.items.size() != itemSet.items.size()) {
    			return false;
    		}
    
    		for (int i = 0; i < itemSet.items.size(); i++) {
    			if (this.items.get(i) != itemSet.items.get(i)) {
    				// 只要有值不相等,直接算作不相等
    				result = false;
    				break;
    			}
    		}
    
    		return result;
    	}
    
    	/**
    	 * 拷贝项集中同样的数据一份
    	 * 
    	 * @return
    	 */
    	public ArrayList<Integer> copyItems() {
    		ArrayList<Integer> copyItems = new ArrayList<>();
    
    		for (int num : this.items) {
    			copyItems.add(num);
    		}
    
    		return copyItems;
    	}
    }
    
    GSPTool.java(算法工具类):

    package DataMining_GSP;
    
    import java.io.BufferedReader;
    import java.io.File;
    import java.io.FileReader;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * GSP序列模式分析算法
     * 
     * @author lyq
     * 
     */
    public class GSPTool {
    	// 测试数据文件地址
    	private String filePath;
    	// 最小支持度阈值
    	private int minSupportCount;
    	// 时间最小间隔
    	private int min_gap;
    	// 时间最大间隔
    	private int max_gap;
    	// 原始数据序列
    	private ArrayList<Sequence> totalSequences;
    	// GSP算法中产生的所有的频繁项集序列
    	private ArrayList<Sequence> totalFrequencySeqs;
    	// 序列项数字对时间的映射图容器
    	private ArrayList<ArrayList<HashMap<Integer, Integer>>> itemNum2Time;
    
    	public GSPTool(String filePath, int minSupportCount, int min_gap,
    			int max_gap) {
    		this.filePath = filePath;
    		this.minSupportCount = minSupportCount;
    		this.min_gap = min_gap;
    		this.max_gap = max_gap;
    		totalFrequencySeqs = new ArrayList<>();
    		readDataFile();
    	}
    
    	/**
    	 * 从文件中读取数据
    	 */
    	private void readDataFile() {
    		File file = new File(filePath);
    		ArrayList<String[]> dataArray = new ArrayList<String[]>();
    
    		try {
    			BufferedReader in = new BufferedReader(new FileReader(file));
    			String str;
    			String[] tempArray;
    			while ((str = in.readLine()) != null) {
    				tempArray = str.split(" ");
    				dataArray.add(tempArray);
    			}
    			in.close();
    		} catch (IOException e) {
    			e.getStackTrace();
    		}
    
    		HashMap<Integer, Sequence> mapSeq = new HashMap<>();
    		Sequence seq;
    		ItemSet itemSet;
    		int tID;
    		String[] itemStr;
    		for (String[] str : dataArray) {
    			tID = Integer.parseInt(str[0]);
    			itemStr = new String[Integer.parseInt(str[1])];
    			System.arraycopy(str, 2, itemStr, 0, itemStr.length);
    			itemSet = new ItemSet(itemStr);
    
    			if (mapSeq.containsKey(tID)) {
    				seq = mapSeq.get(tID);
    			} else {
    				seq = new Sequence(tID);
    			}
    			seq.getItemSetList().add(itemSet);
    			mapSeq.put(tID, seq);
    		}
    
    		// 将序列图加入到序列List中
    		totalSequences = new ArrayList<>();
    		for (Map.Entry entry : mapSeq.entrySet()) {
    			totalSequences.add((Sequence) entry.getValue());
    		}
    	}
    
    	/**
    	 * 生成1频繁项集
    	 * 
    	 * @return
    	 */
    	private ArrayList<Sequence> generateOneFrequencyItem() {
    		int count = 0;
    		int currentTransanctionID = 0;
    		Sequence tempSeq;
    		ItemSet tempItemSet;
    		HashMap<Integer, Integer> itemNumMap = new HashMap<>();
    		ArrayList<Sequence> seqList = new ArrayList<>();
    
    		for (Sequence seq : totalSequences) {
    			for (ItemSet itemSet : seq.getItemSetList()) {
    				for (int num : itemSet.getItems()) {
    					// 如果没有此种类型项,则进行添加操作
    					if (!itemNumMap.containsKey(num)) {
    						itemNumMap.put(num, 1);
    					}
    				}
    			}
    		}
    		
    		boolean isContain = false;
    		int number = 0;
    		for (Map.Entry entry : itemNumMap.entrySet()) {
    			count = 0;
    			number = (int) entry.getKey();
    			for (Sequence seq : totalSequences) {
    				isContain = false;
    				
    				for (ItemSet itemSet : seq.getItemSetList()) {
    					for (int num : itemSet.getItems()) {
    						if (num == number) {
    							isContain = true;
    							break;
    						}
    					}
    					
    					if(isContain){
    						break;
    					}
    				}
    				
    				if(isContain){
    					count++;
    				}
    			}
    			
    			itemNumMap.put(number, count);
    		}
    		
    
    		for (Map.Entry entry : itemNumMap.entrySet()) {
    			count = (int) entry.getValue();
    			if (count >= minSupportCount) {
    				tempSeq = new Sequence();
    				tempItemSet = new ItemSet(new int[] { (int) entry.getKey() });
    
    				tempSeq.getItemSetList().add(tempItemSet);
    				seqList.add(tempSeq);
    			}
    
    		}
    		// 将序列升序排列
    		Collections.sort(seqList);
    		// 将频繁1项集加入总频繁项集列表中
    		totalFrequencySeqs.addAll(seqList);
    
    		return seqList;
    	}
    
    	/**
    	 * 通过1频繁项集连接产生2频繁项集
    	 * 
    	 * @param oneSeq
    	 *            1频繁项集序列
    	 * @return
    	 */
    	private ArrayList<Sequence> generateTwoFrequencyItem(
    			ArrayList<Sequence> oneSeq) {
    		Sequence tempSeq;
    		ArrayList<Sequence> resultSeq = new ArrayList<>();
    		ItemSet tempItemSet;
    		int num1;
    		int num2;
    
    		// 假如将<a>,<b>2个1频繁项集做连接组合,可以分为<a a>,<a b>,<b a>,<b b>4个序列模式
    		// 注意此时的每个序列中包含2个独立项集
    		for (int i = 0; i < oneSeq.size(); i++) {
    			num1 = oneSeq.get(i).getFirstItemSetNum();
    			for (int j = 0; j < oneSeq.size(); j++) {
    				num2 = oneSeq.get(j).getFirstItemSetNum();
    
    				tempSeq = new Sequence();
    				tempItemSet = new ItemSet(new int[] { num1 });
    				tempSeq.getItemSetList().add(tempItemSet);
    				tempItemSet = new ItemSet(new int[] { num2 });
    				tempSeq.getItemSetList().add(tempItemSet);
    
    				if (countSupport(tempSeq) >= minSupportCount) {
    					resultSeq.add(tempSeq);
    				}
    			}
    		}
    
    		// 上面连接还有1种情况是每个序列中只包含有一个项集的情况,此时a,b的划分则是<(a,a)> <(a,b)> <(b,b)>
    		for (int i = 0; i < oneSeq.size(); i++) {
    			num1 = oneSeq.get(i).getFirstItemSetNum();
    			for (int j = i; j < oneSeq.size(); j++) {
    				num2 = oneSeq.get(j).getFirstItemSetNum();
    
    				tempSeq = new Sequence();
    				tempItemSet = new ItemSet(new int[] { num1, num2 });
    				tempSeq.getItemSetList().add(tempItemSet);
    
    				if (countSupport(tempSeq) >= minSupportCount) {
    					resultSeq.add(tempSeq);
    				}
    			}
    		}
    		// 同样将2频繁项集加入到总频繁项集中
    		totalFrequencySeqs.addAll(resultSeq);
    
    		return resultSeq;
    	}
    
    	/**
    	 * 根据上次的频繁集连接产生新的侯选集
    	 * 
    	 * @param seqList
    	 *            上次产生的候选集
    	 * @return
    	 */
    	private ArrayList<Sequence> generateCandidateItem(
    			ArrayList<Sequence> seqList) {
    		Sequence tempSeq;
    		ArrayList<Integer> tempNumArray;
    		ArrayList<Sequence> resultSeq = new ArrayList<>();
    		// 序列数字项列表
    		ArrayList<ArrayList<Integer>> seqNums = new ArrayList<>();
    
    		for (int i = 0; i < seqList.size(); i++) {
    			tempNumArray = new ArrayList<>();
    			tempSeq = seqList.get(i);
    			for (ItemSet itemSet : tempSeq.getItemSetList()) {
    				tempNumArray.addAll(itemSet.copyItems());
    			}
    			seqNums.add(tempNumArray);
    		}
    
    		ArrayList<Integer> array1;
    		ArrayList<Integer> array2;
    		// 序列i,j的拷贝
    		Sequence seqi = null;
    		Sequence seqj = null;
    		// 判断是否能够连接,默认能连接
    		boolean canConnect = true;
    		// 进行连接运算,包括自己与自己连接
    		for (int i = 0; i < seqNums.size(); i++) {
    			for (int j = 0; j < seqNums.size(); j++) {
    				array1 = (ArrayList<Integer>) seqNums.get(i).clone();
    				array2 = (ArrayList<Integer>) seqNums.get(j).clone();
    
    				// 将第一个数字组去掉第一个,第二个数字组去掉最后一个,如果剩下的部分相等,则可以连接
    				array1.remove(0);
    				array2.remove(array2.size() - 1);
    
    				canConnect = true;
    				for (int k = 0; k < array1.size(); k++) {
    					if (array1.get(k) != array2.get(k)) {
    						canConnect = false;
    						break;
    					}
    				}
    
    				if (canConnect) {
    					seqi = seqList.get(i).copySeqence();
    					seqj = seqList.get(j).copySeqence();
    
    					int lastItemNum = seqj.getLastItemSetNum();
    					if (seqj.isLastItemSetSingleNum()) {
    						// 如果j序列的最后项集为单一值,则最后一个数字以独立项集加入i序列
    						ItemSet itemSet = new ItemSet(new int[] { lastItemNum });
    						seqi.getItemSetList().add(itemSet);
    					} else {
    						// 如果j序列的最后项集为非单一值,则最后一个数字加入i序列最后一个项集中
    						ItemSet itemSet = seqi.getLastItemSet();
    						itemSet.getItems().add(lastItemNum);
    					}
    
    					// 判断是否超过最小支持度阈值
    					if (isChildSeqContained(seqi)
    							&& countSupport(seqi) >= minSupportCount) {
    						resultSeq.add(seqi);
    					}
    				}
    			}
    		}
    
    		totalFrequencySeqs.addAll(resultSeq);
    		return resultSeq;
    	}
    
    	/**
    	 * 判断此序列的所有子序列是否也是频繁序列
    	 * 
    	 * @param seq
    	 *            待比较序列
    	 * @return
    	 */
    	private boolean isChildSeqContained(Sequence seq) {
    		boolean isContained = false;
    		ArrayList<Sequence> childSeqs;
    
    		childSeqs = seq.createChildSeqs();
    		for (Sequence tempSeq : childSeqs) {
    			isContained = false;
    
    			for (Sequence frequencySeq : totalFrequencySeqs) {
    				if (tempSeq.compareIsSame(frequencySeq)) {
    					isContained = true;
    					break;
    				}
    			}
    
    			if (!isContained) {
    				break;
    			}
    		}
    
    		return isContained;
    	}
    
    	/**
    	 * 候选集判断支持度的值
    	 * 
    	 * @param seq
    	 *            待判断序列
    	 * @return
    	 */
    	private int countSupport(Sequence seq) {
    		int count = 0;
    		int matchNum = 0;
    		Sequence tempSeq;
    		ItemSet tempItemSet;
    		HashMap<Integer, Integer> timeMap;
    		ArrayList<ItemSet> itemSetList;
    		ArrayList<ArrayList<Integer>> numArray = new ArrayList<>();
    		// 每项集对应的时间链表
    		ArrayList<ArrayList<Integer>> timeArray = new ArrayList<>();
    
    		for (ItemSet itemSet : seq.getItemSetList()) {
    			numArray.add(itemSet.getItems());
    		}
    
    		for (int i = 0; i < totalSequences.size(); i++) {
    			timeArray = new ArrayList<>();
    
    			for (int s = 0; s < numArray.size(); s++) {
    				ArrayList<Integer> childNum = numArray.get(s);
    				ArrayList<Integer> localTime = new ArrayList<>();
    				tempSeq = totalSequences.get(i);
    				itemSetList = tempSeq.getItemSetList();
    
    				for (int j = 0; j < itemSetList.size(); j++) {
    					tempItemSet = itemSetList.get(j);
    					matchNum = 0;
    					int t = 0;
    
    					if (tempItemSet.getItems().size() == childNum.size()) {
    						timeMap = itemNum2Time.get(i).get(j);
    						// 只有当项集长度匹配时才匹配
    						for (int k = 0; k < childNum.size(); k++) {
    							if (timeMap.containsKey(childNum.get(k))) {
    								matchNum++;
    								t = timeMap.get(childNum.get(k));
    							}
    						}
    
    						// 如果完全匹配,则记录时间
    						if (matchNum == childNum.size()) {
    							localTime.add(t);
    						}
    					}
    
    				}
    
    				if (localTime.size() > 0) {
    					timeArray.add(localTime);
    				}
    			}
    
    			// 判断时间是否满足时间最大最小约束,如果满足,则此条事务包含候选事务
    			if (timeArray.size() == numArray.size()
    					&& judgeTimeInGap(timeArray)) {
    				count++;
    			}
    		}
    
    		return count;
    	}
    
    	/**
    	 * 判断事务是否满足时间约束
    	 * 
    	 * @param timeArray
    	 *            时间数组,每行代表各项集的在事务中的发生时间链表
    	 * @return
    	 */
    	private boolean judgeTimeInGap(ArrayList<ArrayList<Integer>> timeArray) {
    		boolean result = false;
    		int preTime = 0;
    		ArrayList<Integer> firstTimes = timeArray.get(0);
    		timeArray.remove(0);
    
    		if (timeArray.size() == 0) {
    			return false;
    		}
    
    		for (int i = 0; i < firstTimes.size(); i++) {
    			preTime = firstTimes.get(i);
    
    			if (dfsJudgeTime(preTime, timeArray)) {
    				result = true;
    				break;
    			}
    		}
    
    		return result;
    	}
    
    	/**
    	 * 深度优先遍历时间,判断是否有符合条件的时间间隔
    	 * 
    	 * @param preTime
    	 * @param timeArray
    	 * @return
    	 */
    	private boolean dfsJudgeTime(int preTime,
    			ArrayList<ArrayList<Integer>> timeArray) {
    		boolean result = false;
    		ArrayList<ArrayList<Integer>> timeArrayClone = (ArrayList<ArrayList<Integer>>) timeArray
    				.clone();
    		ArrayList<Integer> firstItemItem = timeArrayClone.get(0);
    
    		for (int i = 0; i < firstItemItem.size(); i++) {
    			if (firstItemItem.get(i) - preTime >= min_gap
    					&& firstItemItem.get(i) - preTime <= max_gap) {
    				// 如果此2项间隔时间满足时间约束,则继续往下递归
    				preTime = firstItemItem.get(i);
    				timeArrayClone.remove(0);
    
    				if (timeArrayClone.size() == 0) {
    					return true;
    				} else {
    					result = dfsJudgeTime(preTime, timeArrayClone);
    					if (result) {
    						return true;
    					}
    				}
    			}
    		}
    
    		return result;
    	}
    
    	/**
    	 * 初始化序列项到时间的序列图,为了后面的时间约束计算
    	 */
    	private void initItemNumToTimeMap() {
    		Sequence seq;
    		itemNum2Time = new ArrayList<>();
    		HashMap<Integer, Integer> tempMap;
    		ArrayList<HashMap<Integer, Integer>> tempMapList;
    
    		for (int i = 0; i < totalSequences.size(); i++) {
    			seq = totalSequences.get(i);
    			tempMapList = new ArrayList<>();
    
    			for (int j = 0; j < seq.getItemSetList().size(); j++) {
    				ItemSet itemSet = seq.getItemSetList().get(j);
    				tempMap = new HashMap<>();
    				for (int itemNum : itemSet.getItems()) {
    					tempMap.put(itemNum, j + 1);
    				}
    
    				tempMapList.add(tempMap);
    			}
    
    			itemNum2Time.add(tempMapList);
    		}
    	}
    
    	/**
    	 * 进行GSP算法计算
    	 */
    	public void gspCalculate() {
    		ArrayList<Sequence> oneSeq;
    		ArrayList<Sequence> twoSeq;
    		ArrayList<Sequence> candidateSeq;
    
    		initItemNumToTimeMap();
    		oneSeq = generateOneFrequencyItem();
    		twoSeq = generateTwoFrequencyItem(oneSeq);
    		candidateSeq = twoSeq;
    
    		// 不断连接生产候选集,直到没有产生出侯选集
    		for (;;) {
    			candidateSeq = generateCandidateItem(candidateSeq);
    
    			if (candidateSeq.size() == 0) {
    				break;
    			}
    		}
    
    		outputSeqence(totalFrequencySeqs);
    
    	}
    
    	/**
    	 * 输出序列列表信息
    	 * 
    	 * @param outputSeqList
    	 *            待输出序列列表
    	 */
    	private void outputSeqence(ArrayList<Sequence> outputSeqList) {
    		for (Sequence seq : outputSeqList) {
    			System.out.print("<");
    			for (ItemSet itemSet : seq.getItemSetList()) {
    				System.out.print("(");
    				for (int num : itemSet.getItems()) {
    					System.out.print(num + ",");
    				}
    				System.out.print("), ");
    			}
    			System.out.println(">");
    		}
    	}
    
    }
    
    调用类Client.java:

    package DataMining_GSP;
    
    /**
     * GSP序列模式分析算法
     * @author lyq
     *
     */
    public class Client {
    	public static void main(String[] args){
    		String filePath = "C:\Users\lyq\Desktop\icon\testInput.txt";
    		//最小支持度阈值
    		int minSupportCount = 2;
    		//时间最小间隔
    		int min_gap = 1;
    		//施加最大间隔
    		int max_gap = 5;
    		
    		GSPTool tool = new GSPTool(filePath, minSupportCount, min_gap, max_gap);
    		tool.gspCalculate();
    	}
    }
    
    算法的输出(挖掘出的所有频繁模式):

    <(1,), >
    <(2,), >
    <(3,), >
    <(4,), >
    <(5,), >
    <(1,), (3,), >
    <(1,), (4,), >
    <(1,), (5,), >
    <(2,), (3,), >
    <(2,), (4,), >
    <(3,), (4,), >
    <(3,), (5,), >
    <(4,), (5,), >
    <(1,), (3,), (4,), >
    <(1,), (3,), (5,), >
    <(2,), (3,), (4,), >

    算法实现的难点

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

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

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

    GSP算法和Apriori算法的比较

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

  • 相关阅读:
    109 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 05 问题解析--通过一个方法完成学生和专业的双向关联
    108 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 04 问题解析--数组未实例化造成的空指针异常
    107 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 03 编写方法完成学生个数统计功能
    106 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 02 新增属性完成学生信息存储
    105 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 01 新增需求及分析
    session与cookie的区别和联系
    session和cookie的区别
    Web服务器主动推送技术
    webSocket的场景应用
    TCP、Http和Socket 优劣比较
  • 原文地址:https://www.cnblogs.com/bianqi/p/12184005.html
Copyright © 2020-2023  润新知