刘 勇 Email:lyssym@sina.com
简介
在研究文本推荐算法时,需要挖掘关键字之间的规则,其中比较重要的一步是构建关键字的集合,即需要求取一个集合的所有子集。因此本文根据需求,采用3种方式实现该算法,以期对后续算法研究提供帮助。
本文下面从二叉树递归、位图和集合3个角度,对该算法进行研究与实现。
二叉树递归
为简要描述,采用数据集为:A= {1,2,3}。二叉树递归如下图-1所示。
图-1 二叉树递归过程
对图-1采用二叉树递归解释为:集合中每个元素有2中状态,属于某个集合,或者不属于该集合,因此求取子集的过程则为对每个元素进行取舍的过程。如图-1所示,根节点为初始状态,叶子节点为终结状态,除第一层(根节点)为,后续每一层即为对每个元素展开的一次取舍操作。整个过程采用二叉树的先序遍历。
1 import java.util.List; 2 import java.util.ArrayList; 3 4 public class SubSet { 5 private List<List<String>> listList = null; 6 7 public SubSet(List<String> list) 8 { 9 listList = new ArrayList<List<String>>(); 10 int len = list.size(); 11 List<String> dst = new ArrayList<String>(); 12 for (int i = 0; i < len; i++) { 13 generate(list, 0, i, dst); 14 } 15 } 16 17 18 public void generate(List<String> list, int index, int number, List<String> dst) { 19 if (number == -1) { 20 List<String> strList = new ArrayList<String>(); 21 for (String s : dst) 22 strList.add(s); 23 listList.add(strList); 24 return; 25 } 26 27 if (index == list.size()) { 28 return; 29 } 30 String element = list.get(index); 31 dst.add(element); 32 generate(list, index+1, number-1, dst); 33 dst.remove(element); 34 generate(list, index+1, number, dst); 35 } 36 37 38 public void printList() 39 { 40 for (List<String> list : listList) { 41 for (String s : list) { 42 System.out.print(s + " "); 43 } 44 System.out.println(); 45 } 46 } 47 }
位图
为描述方便,采用数据集为:A= {1,2,3}。对于任意一个元素,属于某个集合或者不属于该集合。前述集合以“1”为存在于集合,若为“0”则不存在于该集合,采用位图映射为:
{1,2,3}
{0,0,0}-->{}
{0,0,1}-->{3}
{0,1,0}-->{2}
{0,1,1}-->{2,3}
{1,0,0}-->{1}
{1,0,1}-->{1,3}
{1,1,0}-->{1,2}
{1,1,1}-->{1,2,3}
import java.util.List; import java.util.ArrayList; public class BitSet { private List<List<String>> listList= null; public BitSet(List<String> list) { listList = new ArrayList<List<String>>(); int len = list.size(); int mark = 0; long end = (1<<len) -1; // 2^len-1 for (mark = 0; mark <= end; mark++) { List<String> dst = new ArrayList<String>(); for (int i = 0; i < len ; i++) { if ((1<<i & mark) != 0) { // i has one element dst.add((list.get(i))); } } if (dst.size() > 0) { listList.add(dst); } } } public void printList() { for (List<String> list : listList) { for (String s : list) { System.out.print(s + " "); } System.out.println(); } } }
集合
为描述方便,采用数据集为:A={1,2,3,4},其根据两个上一级目标集合生成下一级的目标集合,其核心解决方案为通过上一层集合的前K-2个元素相同(K为新集合的元素个数),则将上一层集合元素合并生成新的集合,如A31={1,2,3},A32={1,2,4},则生成新的目标集合A41={1,2,3,4},该方案最大的优点是:使得生成的集合中,元素没有重复。
1 import java.util.ArrayList; 2 import java.util.List; 3 import java.util.Set; 4 import java.util.TreeSet; 5 6 public class SetSet { 7 private List<List<Set<String>>> L = null; 8 9 public SetSet(List<String> set) { 10 List<Set<String>> initSet = createInitSet(set); 11 L = new ArrayList<List<Set<String>>>(); // contains all the subsets 12 L.add(initSet); 13 int k = 2; 14 while (L.get(k-2).size() > 0) { 15 List<Set<String>> Ck = aprioriGen(L.get(k-2), k); 16 L.add(Ck); // add the C(k) and the generate C(k+1) 17 k += 1; 18 } 19 } 20 21 /** 22 * create one list 23 * @param set : the data set 24 * @return the list generated 25 */ 26 public List<Set<String>> createInitSet(List<String> set) 27 { 28 List<Set<String>> list = new ArrayList<Set<String>>(); 29 for (String element : set) { 30 Set<String> e = new TreeSet<String>(); 31 e.add(element); 32 if (!list.contains(e)) 33 list.add(e); 34 } 35 return list; 36 } 37 38 /** 39 * generate the number of k items 40 * @param list : the source list 41 * @param k : the numbers 42 * @return the list with set 43 */ 44 public List<Set<String>> aprioriGen(List<Set<String>> list, int k) 45 { 46 List<Set<String>> retList = new ArrayList<Set<String>>(); 47 int size = list.size(); 48 for (int i = 0; i < size; i++) { 49 Set<String> set1 = list.get(i); 50 for (int j = i+1; j < size; j++) { 51 Set<String> set2 = list.get(j); 52 if (isEquals(getSubclass(list.get(i), k-2), getSubclass(list.get(j), k-2))) { // the 0:k-2 contain the same elements 53 retList.add(getUnion(set1, set2)); 54 } 55 } 56 } 57 return retList; 58 } 59 60 /** 61 * get the union of two sets 62 * @param src : the source set 63 * @param dst : destination set 64 * @return one set 65 */ 66 public Set<String> getUnion(Set<String> src, Set<String> dst) 67 { 68 Set<String> set = new TreeSet<String>(); 69 for (String element : src) 70 set.add(element); 71 72 for (String item : dst) 73 if (!set.contains(item)) 74 set.add(item); 75 76 return set; 77 } 78 79 /** 80 * get the top K elements of the set 81 * @param src : the source set 82 * @param k : the top K 83 * @return the top K elements 84 */ 85 public Set<String> getSubclass(Set<String> src, int k) 86 { 87 Set<String> set = new TreeSet<String>(); 88 int index = 0; 89 for (String s : src) { 90 if (index < k) 91 set.add(s); 92 else 93 break; 94 95 index++; 96 } 97 return set; 98 } 99 100 /** 101 * assert the equals of tow sets 102 * @param src : the source set 103 * @param dst : the destination set 104 * @return if src == dst, return true else return false 105 */ 106 public boolean isEquals(Set<String> src, Set<String> dst) 107 { 108 boolean ret = false; 109 if (src.size() == dst.size()) { 110 if (src.size() == 0) 111 ret = true; 112 else if (src.containsAll(dst)) 113 ret = true; 114 } 115 return ret; 116 } 117 }
由于本文在研究文本推荐时,参考《机器学习实战》,故此先入为主,采用了第三种方法。但是,本文作者并不认为第三种方法效率较高,在大规模数据时,作者倾向于先用方案二(位图运算)。
参考
[1] Peter Harrington, Machine Learning in action, 人民邮电出版社,2015.4.
[2] http://blog.csdn.net/pony_maggie/article/details/31042651
作者:志青云集
出处:http://www.cnblogs.com/lyssym
如果,您认为阅读这篇博客让您有些收获,不妨点击一下右下角的【推荐】。
如果,您希望更容易地发现我的新博客,不妨点击一下左下角的【关注我】。
如果,您对我的博客所讲述的内容有兴趣,请继续关注我的后续博客,我是【志青云集】。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。