免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 6066 | 回复: 1
打印 上一主题 下一主题

数据挖掘之分类(kNN算法的描述及使用) [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-03-30 16:04 |只看该作者 |倒序浏览
数据挖掘之分类(kNN算法的描述及使用)



kNN算法简介:
kNN(k Nearest Neighbors)算法又叫k最临近方法, 总体来说kNN算法是相对比较容易理解的算法之一,假设每一个类包含多个样本数据,而且每个数据都有一个唯一的类标记表示这些样本是属于哪一个分类, kNN就是计算每个样本数据到待分类数据的距离,取和待分类数据最近的k各样本数据,那么这个k个样本数据中哪个类别的样本数据占多数,则待分类数据就属于该类别。

基于kNN算法的思想,我们必须找出使用该算法的突破点,本文的目的是使用kNN算法对文本进行分类,那么和之前的文章一样,关键还是项向量的比较问题,之前的文章中的分类代码仅使用的反余弦来匹配项向量,找到关键的“距离”,那么我们可以试想反余弦之后使用kNN的结果如何。

补充上一篇文章中没有详细讲解的反余弦匹配问题:
Lucene中有一个term vectors这个东东,它表示该词汇单元在文档中出现的次数,比如说这里有两篇文章,这两篇文章中都有hibernate和spring这两个单词,在第一篇文章中hibernate出现了10次,spring出现了20次,第二篇文章中hibernate出现15次,spring出现10次,那么对第一篇文章来说有两个项向量,分别是hibernate:10,spring:20,第二篇文章类似,hibernate:15,spring:10。然后我们就可以在二维空间的x,y组上表示出来,如图:

这样看来我们其实是要得到两者之间的夹角,计算两个向量之间夹角的公式为A*B/||A||*||B||。按照这个原理我们就可以得到新文章和样本文章之间的距离,代码如下,这个份代码在第一篇文章提供的代码下载中。

Java代码
  1. public double caculateVectorSpace(Map<String, Integer> articleVectorMap, Map<String, Integer> classVectorMap) {
  2.                 if (articleVectorMap == null || classVectorMap == null) {
  3.                         if (logger.isDebugEnabled()) {
  4.                                 logger.debug("itemVectorMap or classVectorMap is null");
  5.                         }
  6.                        
  7.                         return 20;
  8.                 }
  9.                
  10.                 int dotItem = 0;
  11.                 double denominatorOne = 0;
  12.                 double denominatorTwo = 0;
  13.                
  14.                
  15.                 for (Entry<String, Integer> entry : articleVectorMap.entrySet()) {
  16.                         String word = entry.getKey();
  17.                         double categoryWordFreq = 0;
  18.                         double articleWordFreq = 0;
  19.                        
  20.                         if (classVectorMap.containsKey(word)) {
  21.                                 categoryWordFreq = classVectorMap.get(word).intValue() / classVectorMap.size();
  22.                                 articleWordFreq = entry.getValue().intValue() / articleVectorMap.size();
  23.                         }
  24.                        
  25.                         dotItem += categoryWordFreq * articleWordFreq;
  26.                         denominatorOne += categoryWordFreq * categoryWordFreq;
  27.                         denominatorTwo += articleWordFreq * articleWordFreq;
  28.                 }
  29.                
  30.                 double denominator = Math.sqrt(denominatorOne) * Math.sqrt(denominatorTwo);
  31.                
  32.                 double ratio =  dotItem / denominator;
  33.                
  34.                 return Math.acos(ratio);
  35.         }
复制代码
接着根据kNN的原理,我们记录下待分类数据和样本数据的距离,对每一个待分类数据都找出k个距离最小的样本,最后判断这些样本所在的分类, 这些样本所在的分类就是该新数据应该所在的分类。

那么根据以上的描述,我把结合使用反余弦匹配和kNN结合的过程分成以下几个步骤:
1, 计算出样本数据和待分类数据的距离
2, 为待分类数据选择k个与其距离最小的样本
3, 统计出k个样本中大多数样本所属的分类
4, 这个分类就是待分类数据所属的分类

根据上面的步骤,我写出了以下代码,这些代码都包含在提供下载的代码里,我将不断的扩充这些代码,可以说一下代码是使用kNN比较核心的代码。

MatchCondition这个类包括,待分类数据,样本数据,样本类别,和距离。

Java代码
  1. protected Map<String, List<MatchCondition>> analyse(Map<String, Map<String, Integer>> articleVectorMap, Map<String, Map<String, Integer>> categoryVectorMap) {
  2.                
  3.                 Map<String, List<MatchCondition>> result = new HashMap<String, List<MatchCondition>>();
  4.                
  5.                 for (Entry<String, Map<String, Integer>> categoryEntry : categoryVectorMap.entrySet()) {
  6.                        
  7.                         for (Entry<String, Map<String, Integer>> itemEntry : articleVectorMap.entrySet()) {
  8.                                 double acos = caculateVector(itemEntry.getValue(), filterVectorMap(categoryEntry.getValue()));
  9.                                 if (acos < vectorGene) {
  10.                                         if (result.get(itemEntry.getKey()) != null) {
  11.                                                 List<MatchCondition> list = result.get(itemEntry.getKey());
  12.                                                
  13.                                                 if (list.size() < kNum) {
  14.                                                         list.add(new MatchCondition(itemEntry.getKey(), categoryEntry.getKey(), acos));
  15.                                                 } else {
  16.                                                         if (list.size() == kNum) {
  17.                                                                 Collections.sort(list, new MatchConditionComparator());
  18.                                                         }
  19.                                                        
  20.                                                         int n = 0;
  21.                                                         for (MatchCondition condition : list) {
  22.                                                                 if (acos < condition.getAcos()) {
  23.                                                                         list.set(n, new MatchCondition(itemEntry.getKey(), categoryEntry.getKey(), acos));
  24.                                                                 }
  25.                                                                 n++;
  26.                                                         }
  27.                                                 }
  28.                                         } else {
  29.                                                 List<MatchCondition> list = new LinkedList<MatchCondition>();
  30.                                                 list.add(new MatchCondition(itemEntry.getKey(), categoryEntry.getKey(), acos));
  31.                                                 result.put(itemEntry.getKey(), list);
  32.                                         }
  33.                                        
  34.                                 }
  35.                         }
  36.                        
  37.                 }
  38.                
  39.                 return result;
  40.         }
复制代码
所有的代码在本文提供的下载代码中,以第一篇文章中的测试数据运行测试,所得的结果为:
2008-02-23 14:04:15,646 DEBUG ArticleKNNClassifierImpl:81 - ---------------- The article id is 3
2008-02-23 14:04:15,646 DEBUG ArticleKNNClassifierImpl:83 - categoryId : a | count : 1
2008-02-23 14:04:15,646 DEBUG ArticleKNNClassifierImpl:81 - ---------------- The article id is 2
2008-02-23 14:04:15,646 DEBUG ArticleKNNClassifierImpl:83 - categoryId : b | count : 2
2008-02-23 14:04:15,646 DEBUG ArticleKNNClassifierImpl:83 - categoryId : a | count : 3
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:81 - ---------------- The article id is 1
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : b | count : 1
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : a | count : 4
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:81 - ---------------- The article id is 5
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : b | count : 1
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : a | count : 4
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:81 - ---------------- The article id is 4
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : b | count : 3
2008-02-23 14:04:15,656 DEBUG ArticleKNNClassifierImpl:83 - categoryId : a | count : 2
从这里我们可以看出articleId为2的应该属于a分类,articleId为1的也属于a分类,articleId为5的也属于a分类,articleId为4的属于b分类。当然其实我们的样本数量太少了,并不能说明acos+knn结合的的效果。

也有人提出了一种结合kNN分类器的加权特征提取问题,该分类通过每次的分类结果不断的调整权值,具有较好的分类效果。所以说虽然kNN算法比较简单,但是事实上如果使用正确,应该也可以收到不错的效果。

论坛徽章:
3
天秤座
日期:2013-12-27 13:44:58射手座
日期:2014-05-22 16:52:43天蝎座
日期:2014-08-13 16:03:21
2 [报告]
发表于 2011-03-30 19:19 |只看该作者
kankan
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP