关联分析(关联挖掘)是指在交易数据、关系数据或其他信息载体中,查找存在于项目集合或对象集合之间的频繁模式、关联、相关性或因果结构。关联分析的一个典型例子是购物篮分析。通过发现顾客放入购物篮中不同商品之间的联系,分析顾客的购买习惯。比如,67%的顾客在购买尿布的同时也会购买啤酒。通过了解哪些商品频繁地被顾客同时购买,可以帮助零售商制定营销策略。分析结果可以应用于商品货架布局、货存安排以及根据购买模式对顾客进行分类。
FPGrowth算法是韩嘉炜等人在2000年提出的关联分析算法,在算法中使用了一种称为频繁模式树(Frequent Pattern Tree)的数据结构,基于上述数据结构加快整个关联规则挖掘过程。采取如下分治策略:将提供频繁项集的数据库压缩到一棵频繁模式树(FP-Tree),但仍保留项集关联信息。该算法和Apriori算法最大的不同有两点:第一,不产生候选集,第二,只需要两次遍历数据库,大大提高了效率。
一、前言
首先理解频繁项集中的以下概念:
频繁项:在多个集合中,频繁出现的元素项。
频繁项集:在一系列集合中每项都含有某些相同的元素,这些元素形成一个子集,满足一定阀值就是频繁项集。
K项集:K个频繁项组成的一个集合。
下面用一个例子(事务数据库)说明支持度与置信度,每一行为一个事务,事务由若干个互不相同的项构成,任意几个项的组合称为一个项集。
A E F G A F G A B E F G E F G
支持度:在所有项集中出现的可能性。如项集{A,F,G}的支持数为3,支持度为3/4。支持数大于阈值minSuport的项集称为频繁项集。{F,G}的支持数为4,支持度为4/4。{A}的支持数为3,支持度为3/4。
置信度:频繁项与某项的并集的支持度与频繁项集支持度的比值。如{F,G}-->{A}的置信度则为{A,F,G}的支持数除以{F,G}的支持数,即3/4。{A}-->{F,G}的置信度则为{A,F,G}的支持数除以{A}的支持数,即3/3。
综上所述,理论上可以通过FPGrowth算法从频繁集中挖掘相关规则,再通过置信度筛选出规则用于推荐功能。在本人这个JavaWeb项目中,使用FPGrowth算法基于所有用户搜索历史记录,结合当前搜索记录推荐用户可能感兴趣的(置信度大于阈值的搜索记录)、以及其他用户搜索过的(频繁项集中非当前搜索记录)。上述仅是个人观点,如有错误之处还请不吝赐教。
二、正文
1、用户搜索记录实体类:
1 package entity; 2 3 /** 4 * 用户搜索历史记录 5 * @author: yjl 6 * @date: 2018/5/24 7 */ 8 public class TQueryHistory { 9 10 private Integer id; 11 12 private String userAccount; //用户账号 13 14 private String queryCorpName; //用户搜索的企业 15 16 public TQueryHistory() { 17 } 18 19 public TQueryHistory(String userAccount, String queryCorpName) { 20 this.userAccount = userAccount; 21 this.queryCorpName = queryCorpName; 22 } 23 24 public TQueryHistory(Integer id, String userAccount, String queryCorpName) { 25 this.id = id; 26 this.userAccount = userAccount; 27 this.queryCorpName = queryCorpName; 28 } 29 30 public Integer getId() { 31 return id; 32 } 33 34 public void setId(Integer id) { 35 this.id = id; 36 } 37 38 public String getUserAccount() { 39 return userAccount; 40 } 41 42 public void setUserAccount(String userAccount) { 43 this.userAccount = userAccount; 44 } 45 46 public String getQueryCorpName() { 47 return queryCorpName; 48 } 49 50 public void setQueryCorpName(String queryCorpName) { 51 this.queryCorpName = queryCorpName; 52 } 53 54 55 @Override 56 public String toString() { 57 return "TQueryHistory{" + 58 "id=" + id + 59 ", userAccount=‘" + userAccount + ‘\‘‘ + 60 ", queryCorpName=‘" + queryCorpName + ‘\‘‘ + 61 ‘}‘; 62 } 63 }
2、FPGrowth挖掘相关规则前的数据准备,类似于上述的事务数据库,corpName为用户当前搜索的企业,最后得到的interestedCorpList与otherSearchCorpList集合分别表示用户感兴趣的企业、其他用户搜索过的企业,若集合数量不足可以根据企业行业等属性补充:
1 //获取所有用户的搜索记录 2 List<TQueryHistory> allQueryHistory = searchCorpService.getAllQueryHistory(); 3 4 //根据用户账号分类 5 Map<String, Integer> accountMap = new HashMap(); 6 for(TQueryHistory tQueryHistory: allQueryHistory){ 7 accountMap.put(tQueryHistory.getUserAccount(),0); 8 } 9 10 //根据已分类账号分配 11 Map<String,List<String>> newQueryHistoryMap = new HashMap<>(); 12 for(Map.Entry<String,Integer> entry: accountMap.entrySet()){ 13 String account = entry.getKey(); 14 List<String> accountTQueryHistoryList = new ArrayList<>(); 15 for(TQueryHistory tQueryHistory: allQueryHistory){ 16 if(tQueryHistory.getUserAccount().equals(account)){ 17 accountTQueryHistoryList.add(tQueryHistory.getQueryCorpName()); 18 } 19 } 20 newQueryHistoryMap.put(account,accountTQueryHistoryList); 21 } 22 23 //遍历Map将企业名称写入文件,并传至FPTree 24 String outfile = "QueryHistory.txt"; 25 BufferedWriter bw = new BufferedWriter(new FileWriter(outfile)); 26 for(Map.Entry<String,List<String>> entry: newQueryHistoryMap.entrySet()){ 27 List<String> corpNameList = entry.getValue(); 28 29 bw.write(joinList(corpNameList)); 30 bw.newLine(); 31 } 32 bw.close(); 33 34 //Map取值分别放入对应的集合 35 Map<String, List<String>> corpMap = FPTree.introQueryHistory(outfile,corpName); 36 List<String> interestedCorpList = new ArrayList<>(); 37 List<String> otherSearchCorpList = new ArrayList<>(); 38 for(Map.Entry<String,List<String>> entry: corpMap.entrySet()){ 39 if("interestedCorpList".equals(entry.getKey())){ 40 interestedCorpList = entry.getValue(); 41 } 42 if("otherSearchCorpList".equals(entry.getKey())){ 43 otherSearchCorpList = entry.getValue(); 44 } 45 }
1 //设置文件写入规则 2 private static String joinList(List<String> list) { 3 if (list == null || list.size() == 0) { 4 return ""; 5 } 6 StringBuilder sb = new StringBuilder(); 7 for (String ele : list) { 8 sb.append(ele); 9 sb.append(","); 10 } 11 return sb.substring(0, sb.length() - 1); 12 }
3、FPStrongAssociationRule类为强关联规则变量:
1 package util; 2 3 import java.util.List; 4 5 public class FPStrongAssociationRule { 6 7 public List<String> condition; 8 9 public String result; 10 11 public int support; 12 13 public double confidence; 14 15 }
4、FPTreeNode类为FPTree的相关变量:
1 package util; 2 3 import java.util.ArrayList; 4 import java.util.List; 5 6 public class FPTreeNode { 7 8 private String name; //节点名称 9 private int count; //频数 10 private FPTreeNode parent; //父节点 11 private List<FPTreeNode> children; //子节点 12 private FPTreeNode nextHomonym; //下一个节点(由表头项维护的那个链表) 13 private FPTreeNode tail; //末节点(由表头项维护的那个链表) 14 15 16 17 public FPTreeNode() { 18 } 19 20 public FPTreeNode(String name) { 21 this.name = name; 22 } 23 24 public String getName() { 25 return this.name; 26 } 27 28 public void setName(String name) { 29 this.name = name; 30 } 31 32 public int getCount() { 33 return this.count; 34 } 35 36 public void setCount(int count) { 37 this.count = count; 38 } 39 40 public FPTreeNode getParent() { 41 return this.parent; 42 } 43 44 public void setParent(FPTreeNode parent) { 45 this.parent = parent; 46 } 47 48 public List<FPTreeNode> getChildren() { 49 return this.children; 50 } 51 52 public void setChildren(List<FPTreeNode> children) { 53 this.children = children; 54 } 55 56 public FPTreeNode getNextHomonym() { 57 return this.nextHomonym; 58 } 59 60 public void setNextHomonym(FPTreeNode nextHomonym) { 61 this.nextHomonym = nextHomonym; 62 } 63 64 public FPTreeNode getTail() { 65 return tail; 66 } 67 68 public void setTail(FPTreeNode tail) { 69 this.tail = tail; 70 } 71 72 //添加子节点 73 public void addChild(FPTreeNode child) { 74 if (getChildren() == null) { 75 List<FPTreeNode> list = new ArrayList<>(); 76 list.add(child); 77 setChildren(list); 78 } else { 79 getChildren().add(child); 80 } 81 } 82 83 //查询子节点 84 public FPTreeNode findChild(String name) { 85 List<FPTreeNode> children = getChildren(); 86 if (children != null) { 87 for (FPTreeNode child : children) { 88 if (child.getName().equals(name)) { 89 return child; 90 } 91 } 92 } 93 return null; 94 } 95 96 97 public void countIncrement(int n) { 98 this.count += n; 99 } 100 101 102 @Override 103 public String toString() { 104 return name; 105 } 106 }
5、FPTree类为FPGrowth算法挖掘规则,introQueryHistory函数根据传入所有用户的搜索记录以及当前搜索的企业,得到用户可能感兴趣的企业以及其他用户搜索过的企业,以及限制每个集合中的企业数量:
1 package util; 2 3 import java.io.BufferedReader; 4 import java.io.FileReader; 5 import java.io.IOException; 6 import java.text.DecimalFormat; 7 import java.util.*; 8 import java.util.Map.Entry; 9 10 public class FPTree { 11 12 private int minSuport; //频繁模式的最小支持数 13 private double confident; //关联规则的最小置信度 14 private int totalSize; //事务项的总数 15 private Map<List<String>, Integer> frequentMap = new HashMap<>(); //存储每个频繁项及其对应的计数 16 private Set<String> decideAttr = null; //关联规则中,哪些项可作为被推导的结果,默认情况下所有项都可以作为被推导的结果 17 18 19 20 public void setMinSuport(int minSuport) { 21 this.minSuport = minSuport; 22 } 23 24 public void setConfident(double confident) { 25 this.confident = confident; 26 } 27 28 public void setDecideAttr(Set<String> decideAttr) { this.decideAttr = decideAttr;} 29 30 31 32 /** 33 * 获取强关联规则 34 * @return 35 * @Description: 36 */ 37 private List<FPStrongAssociationRule> getRules(List<String> list) { 38 List<FPStrongAssociationRule> rect = new LinkedList<>(); 39 if (list.size() > 1) { 40 for (int i = 0; i < list.size(); i++) { 41 String result = list.get(i); 42 if (decideAttr.contains(result)) { 43 List<String> condition = new ArrayList<>(); 44 condition.addAll(list.subList(0, i)); 45 condition.addAll(list.subList(i + 1, list.size())); 46 FPStrongAssociationRule rule = new FPStrongAssociationRule(); 47 rule.condition = condition; 48 rule.result = result; 49 rect.add(rule); 50 } 51 } 52 } 53 return rect; 54 } 55 56 57 /** 58 * 从若干个文件中读入Transaction Record,同时把所有项设置为decideAttr 59 * @return 60 * @Description: 61 */ 62 public List<List<String>> readTransRocords(String[] filenames) { 63 Set<String> set = new HashSet<>(); 64 List<List<String>> transaction = null; 65 if (filenames.length > 0) { 66 transaction = new LinkedList<>(); 67 for (String filename : filenames) { 68 try { 69 FileReader fr = new FileReader(filename); 70 BufferedReader br = new BufferedReader(fr); 71 try { 72 String line; 73 // 一项事务占一行 74 while ((line = br.readLine()) != null) { 75 if (line.trim().length() > 0) { 76 // 每个item之间用","分隔 77 String[] str = line.split(","); 78 //每一项事务中的重复项需要排重 79 Set<String> record = new HashSet<>(); 80 for (String w : str) { 81 record.add(w); 82 set.add(w); 83 } 84 List<String> rl = new ArrayList<>(); 85 rl.addAll(record); 86 transaction.add(rl); 87 } 88 } 89 } finally { 90 br.close(); 91 } 92 } catch (IOException ex) { 93 System.out.println("Read transaction records failed." + ex.getMessage()); 94 System.exit(1); 95 } 96 } 97 } 98 99 this.setDecideAttr(set); 100 return transaction; 101 } 102 103 104 /** 105 * 生成一个序列的各种子序列(序列是有顺序的) 106 * @param residualPath 107 * @param results 108 */ 109 private void combine(LinkedList<FPTreeNode> residualPath, List<List<FPTreeNode>> results) { 110 if (residualPath.size() > 0) { 111 //如果residualPath太长,则会有太多的组合,内存会被耗尽的 112 FPTreeNode head = residualPath.poll(); 113 List<List<FPTreeNode>> newResults = new ArrayList<>(); 114 for (List<FPTreeNode> list : results) { 115 List<FPTreeNode> listCopy = new ArrayList<>(list); 116 newResults.add(listCopy); 117 } 118 119 for (List<FPTreeNode> newPath : newResults) { 120 newPath.add(head); 121 } 122 results.addAll(newResults); 123 List<FPTreeNode> list = new ArrayList<>(); 124 list.add(head); 125 results.add(list); 126 combine(residualPath, results); 127 } 128 } 129 130 /** 131 * 判断是否为单节点 132 * @param root 133 */ 134 private boolean isSingleBranch(FPTreeNode root) { 135 boolean rect = true; 136 while (root.getChildren() != null) { 137 if (root.getChildren().size() > 1) { 138 rect = false; 139 break; 140 } 141 root = root.getChildren().get(0); 142 } 143 return rect; 144 } 145 146 /** 147 * 计算事务集中每一项的频数 148 * @param transRecords 149 * @return 150 */ 151 private Map<String, Integer> getFrequency(List<List<String>> transRecords) { 152 Map<String, Integer> rect = new HashMap<>(); 153 for (List<String> record : transRecords) { 154 for (String item : record) { 155 Integer cnt = rect.get(item); 156 if (cnt == null) { 157 cnt = new Integer(0); 158 } 159 rect.put(item, ++cnt); 160 } 161 } 162 return rect; 163 } 164 165 /** 166 * 根据事务集合构建FPTree 167 * @param transRecords 168 * @Description: 169 */ 170 public void buildFPTree(List<List<String>> transRecords) { 171 totalSize = transRecords.size(); 172 //计算每项的频数 173 final Map<String, Integer> freqMap = getFrequency(transRecords); 174 //每条事务中的项按F1排序 175 for (List<String> transRecord : transRecords) { 176 Collections.sort(transRecord, (o1, o2) -> freqMap.get(o2) - freqMap.get(o1)); 177 } 178 FPGrowth(transRecords, null); 179 } 180 181 182 /** 183 * FP树递归生长,从而得到所有的频繁模式 184 * @param cpb 条件模式基 185 * @param postModel 后缀模式 186 */ 187 private void FPGrowth(List<List<String>> cpb, LinkedList<String> postModel) { 188 Map<String, Integer> freqMap = getFrequency(cpb); 189 Map<String, FPTreeNode> headers = new HashMap<>(); 190 for (Entry<String, Integer> entry : freqMap.entrySet()) { 191 String name = entry.getKey(); 192 int cnt = entry.getValue(); 193 //每一次递归时都有可能出现一部分模式的频数低于阈值 194 if (cnt >= minSuport) { 195 FPTreeNode node = new FPTreeNode(name); 196 node.setCount(cnt); 197 headers.put(name, node); 198 } 199 } 200 201 FPTreeNode treeRoot = buildSubTree(cpb,headers); 202 //如果只剩下虚根节点,则递归结束 203 if ((treeRoot.getChildren() == null) || (treeRoot.getChildren().size() == 0)) { 204 return; 205 } 206 207 //如果树是单枝的,则直接把“路径的各种组合+后缀模式”添加到频繁模式集中。这个技巧是可选的,即跳过此步进入下一轮递归也可以得到正确的结果 208 if (isSingleBranch(treeRoot)) { 209 LinkedList<FPTreeNode> path = new LinkedList<>(); 210 FPTreeNode currNode = treeRoot; 211 while (currNode.getChildren() != null) { 212 currNode = currNode.getChildren().get(0); 213 path.add(currNode); 214 } 215 //调用combine时path不宜过长,否则会OutOfMemory 216 if (path.size() <= 20) { 217 List<List<FPTreeNode>> results = new ArrayList<>(); 218 combine(path, results); 219 for (List<FPTreeNode> list : results) { 220 int cnt = 0; 221 List<String> rule = new ArrayList<>(); 222 for (FPTreeNode node : list) { 223 rule.add(node.getName()); 224 cnt = node.getCount(); //cnt最FPTree叶节点的计数 225 } 226 if (postModel != null) { 227 rule.addAll(postModel); 228 } 229 frequentMap.put(rule, cnt); 230 } 231 return; 232 } else { 233 System.err.println("length of path is too long: " + path.size()); 234 } 235 } 236 237 for (FPTreeNode header : headers.values()) { 238 List<String> rule = new ArrayList<>(); 239 rule.add(header.getName()); 240 if (postModel != null) { 241 rule.addAll(postModel); 242 } 243 //表头项+后缀模式 构成一条频繁模式(频繁模式内部也是按照F1排序的),频繁度为表头项的计数 244 frequentMap.put(rule, header.getCount()); 245 //新的后缀模式:表头项+上一次的后缀模式(注意保持顺序,始终按F1的顺序排列) 246 LinkedList<String> newPostPattern = new LinkedList<>(); 247 newPostPattern.add(header.getName()); 248 if (postModel != null) { 249 newPostPattern.addAll(postModel); 250 } 251 //新的条件模式基 252 List<List<String>> newCPB; 253 newCPB = new LinkedList<>(); 254 FPTreeNode nextNode = header; 255 while ((nextNode = nextNode.getNextHomonym()) != null) { 256 int counter = nextNode.getCount(); 257 //获得从虚根节点(不包括虚根节点)到当前节点(不包括当前节点)的路径,即一条条件模式基。注意保持顺序:你节点在前,子节点在后,即始终保持频率高的在前 258 LinkedList<String> path = new LinkedList<>(); 259 FPTreeNode parent = nextNode; 260 while ((parent = parent.getParent()).getName() != null) {//虚根节点的name为null 261 path.push(parent.getName());//往表头插入 262 } 263 //事务要重复添加counter次 264 while (counter-- > 0) { 265 newCPB.add(path); 266 } 267 } 268 FPGrowth(newCPB, newPostPattern); 269 } 270 } 271 272 /** 273 * 把所有事务插入到一个FP树当中 274 * @param transRecords 275 * @param headers 276 * @return 277 */ 278 private FPTreeNode buildSubTree(List<List<String>> transRecords,final Map<String, FPTreeNode> headers) { 279 FPTreeNode root = new FPTreeNode();//虚根节点 280 for (List<String> transRecord : transRecords) { 281 LinkedList<String> record = new LinkedList<>(transRecord); 282 FPTreeNode subTreeRoot = root; 283 FPTreeNode tmpRoot; 284 if (root.getChildren() != null) { 285 //延已有的分支,令各节点计数加1 286 while (!record.isEmpty() 287 && (tmpRoot = subTreeRoot.findChild(record.peek())) != null) { 288 tmpRoot.countIncrement(1); 289 subTreeRoot = tmpRoot; 290 record.poll(); 291 } 292 } 293 //长出新的节点 294 addNodes(subTreeRoot, record, headers); 295 } 296 return root; 297 } 298 299 /** 300 * 往特定的节点下插入一串后代节点,同时维护表头项到同名节点的链表指针 301 * @param ancestor 302 * @param record 303 * @param headers 304 */ 305 private void addNodes(FPTreeNode ancestor, LinkedList<String> record, 306 final Map<String, FPTreeNode> headers) { 307 while (!record.isEmpty()) { 308 String item = record.poll(); 309 //单个项的出现频数必须大于最小支持数,否则不允许插入FP树。达到最小支持度的项都在headers中。每一次递归根据条件模式基本建立新的FPTree时,把要把频数低于minSuport的排除在外,这也正是FPTree比穷举法快的真正原因 310 if (headers.containsKey(item)) { 311 FPTreeNode leafnode = new FPTreeNode(item); 312 leafnode.setCount(1); 313 leafnode.setParent(ancestor); 314 ancestor.addChild(leafnode); 315 316 FPTreeNode header = headers.get(item); 317 FPTreeNode tail=header.getTail(); 318 if(tail!=null){ 319 tail.setNextHomonym(leafnode); 320 }else{ 321 header.setNextHomonym(leafnode); 322 } 323 header.setTail(leafnode); 324 addNodes(leafnode, record, headers); 325 } 326 327 } 328 } 329 330 /** 331 * 获取所有的强规则 332 * @return 333 */ 334 public List<FPStrongAssociationRule> getAssociateRule() { 335 assert totalSize > 0; 336 List<FPStrongAssociationRule> rect = new ArrayList<>(); 337 //遍历所有频繁模式 338 for (Entry<List<String>, Integer> entry : frequentMap.entrySet()) { 339 List<String> items = entry.getKey(); 340 int count1 = entry.getValue(); 341 //一条频繁模式可以生成很多关联规则 342 List<FPStrongAssociationRule> rules = getRules(items); 343 //计算每一条关联规则的支持度和置信度 344 for (FPStrongAssociationRule rule : rules) { 345 if (frequentMap.containsKey(rule.condition)) { 346 int count2 = frequentMap.get(rule.condition); 347 double confidence = 1.0 * count1 / count2; 348 if (confidence >= this.confident) { 349 rule.support = count1; 350 rule.confidence = confidence; 351 rect.add(rule); 352 } 353 } else { 354 System.err.println(rule.condition + " is not a frequent pattern, however " 355 + items + " is a frequent pattern"); 356 } 357 } 358 } 359 return rect; 360 } 361 362 /** 363 * 限制List集合中企业数目为5条 364 */ 365 private static void limitFiveCorp(List<String> corpList) { 366 if(corpList.size() > 5){ 367 Random randomId = new Random(); 368 //对随机的5个企业名称排成原来的默认顺序 369 List<Integer> indexes = new ArrayList<>(); 370 while(indexes.size() < 5) { 371 int index = randomId.nextInt(corpList.size()); 372 if(!indexes.contains(index)) { 373 indexes.add(index); 374 } 375 } 376 Collections.sort(indexes); 377 //取出indexes对应的list放到newList 378 List<String> tempRelationsCorpList = new ArrayList<>(); 379 for(int index : indexes) { 380 tempRelationsCorpList.add(corpList.get(index)); 381 } 382 corpList.clear(); 383 corpList.addAll(tempRelationsCorpList); 384 } 385 } 386 387 388 public static Map<String, List<String>> introQueryHistory(String outfile,String corpName) { 389 FPTree fpTree = new FPTree(); 390 391 //设置置信度与支持数 392 fpTree.setConfident(0.3); 393 fpTree.setMinSuport(3); 394 395 List<List<String>> trans = fpTree.readTransRocords(new String[] { outfile }); 396 for(int i = 1;i < trans.size() - 1;i++){ 397 System.out.println("第"+i+"行数据:"+ trans.get(i)); 398 } 399 400 fpTree.buildFPTree(trans); 401 402 List<FPStrongAssociationRule> rules = fpTree.getAssociateRule(); 403 DecimalFormat dfm = new DecimalFormat("#.##"); 404 405 Map<String, String> interestedCorpMap = new HashMap<>(); //需要返回的关联企业(您可能感兴趣的公司) 406 Map<String, String> otherSearchCorpMap = new HashMap<>(); //需要返回的关联企业(其他人还搜过的公司) 407 //根据置信度查询关联企业用于返回感兴趣的公司 408 for (FPStrongAssociationRule rule : rules) { 409 System.out.println(rule.condition + "->" + rule.result + "\t" + dfm.format(rule.support) + "\t" + dfm.format(rule.confidence)); 410 List<String> corpCondition = rule.condition; 411 for(int i = 0;i < corpCondition.size();i++){ 412 if(corpName.equals(corpCondition.get(i))){ 413 interestedCorpMap.put(rule.result,dfm.format(rule.confidence)); 414 } 415 } 416 if(corpName.equals(rule.result)){ 417 for(int i = 0;i < corpCondition.size();i++){ 418 if(!corpName.equals(corpCondition.get(i))){ 419 interestedCorpMap.put(corpCondition.get(i),dfm.format(rule.confidence)); 420 } 421 } 422 } 423 } 424 425 //根据多项集查询关联企业用于返回其它搜过的公司 426 for (FPStrongAssociationRule rule : rules) { 427 List<String> corpCondition = rule.condition; 428 for (int i = 0; i < corpCondition.size(); i++) { 429 if (corpName.equals(corpCondition.get(i)) && corpCondition.size() > 1) { 430 for (int j = 0; j < corpCondition.size(); j++) { 431 if (!corpName.equals(corpCondition.get(j))) { 432 otherSearchCorpMap.put(corpCondition.get(j), "0.00"); 433 } 434 } 435 } 436 } 437 } 438 439 440 List<String> interestedCorpList = new ArrayList<>(); 441 List<String> otherSearchCorpList = new ArrayList<>(); 442 for(Map.Entry<String,String> entry: interestedCorpMap.entrySet()){ 443 interestedCorpList.add(entry.getKey()); 444 } 445 for(Map.Entry<String,String> entry: otherSearchCorpMap.entrySet()){ 446 otherSearchCorpList.add(entry.getKey()); 447 } 448 449 limitFiveCorp(interestedCorpList); 450 limitFiveCorp(otherSearchCorpList); 451 452 Map<String, List<String>> corpMap = new HashMap<>(); 453 corpMap.put("interestedCorpList",interestedCorpList); 454 corpMap.put("otherSearchCorpList",otherSearchCorpList); 455 456 return corpMap; 457 } 458 459 460 }
附上控制台打印部分截图:
三、总结
在上面的代码中将整个事务数据库传给FPGrowth,在实际中这是不可取的,因为内存不可能容下整个事务数据库,我们可能需要从关系数据库中一条一条地读入来建立FP-Tree。但无论如何 FP-Tree是肯定需要放在内存中的,但内存如果容不下怎么办?另外FPGrowth仍然是非常耗时的,想提高速度怎么办?解决办法:分而治之,并行计算。
在实践中,关联规则挖掘可能并不像人们期望的那么有用。一方面是因为支持度置信度框架会产生过多的规则,并不是每一个规则都是有用的。另一方面大部分的关联规则并不像“啤酒与尿布”这种经典故事这么普遍。关联规则分析是需要技巧的,有时需要用更严格的统计学知识来控制规则的增殖。
本文部分学习参考了:http://www.cnblogs.com/zhangchaoyang/articles/2198946.html
https://www.cnblogs.com/sddai/p/7486945.html
至此是关于关联分析FPGrowth算法在JavaWeb项目中的应用,上述仅是个人观点,仅供参考。
如有疏漏错误之处,还请不吝赐教!
原文地址:https://www.cnblogs.com/yijialong/p/9763813.html