论坛首页 Java企业应用论坛

数据挖掘之分类

浏览 38929 次
精华帖 (10) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
作者 正文
   发表时间:2008-02-19  
/**

*作者:张荣华

*日期:2008-2-19

**/
随着当代计算机硬件的发展,硬件功能越来越强大,价格越来越低,企业可以记录的数据也越来越多,这些因素就为数据挖掘的普及做了比较好的前提准备,树挖掘是未来信息处理的重要技术,而且就目前而言已经取得了决定性成功而且得到了比较广泛的应用。

数据挖掘中有很多领域,分类就是其中之一,什么是分类,
分类就是把一些新得数据项映射到给定类别的中的某一个类别,比如说当我们发表一篇文章的时候,就可以自动的把这篇文章划分到某一个文章类别,一般的过程是根据样本数据利用一定的分类算法得到分类规则,新的数据过来就依据该规则进行类别的划分。

分类在数据挖掘中是一项非常重要的任务,有很多用途,比如说预测,即从历史的样本数据推算出未来数据的趋向,有一个比较著名的预测的例子就是大豆学习。再比如说分析用户行为,我们常称之为受众分析,通过这种分类,我们可以得知某一商品的用户群,对销售来说有很大的帮助。

分类器的构造方法有统计方法,机器学习方法,神经网络方法等等。常见的统计方法有knn算法,基于事例的学习方法。机器学习方法包括决策树法和归纳法,上面讲到的受众分析可以使用决策树方法来实现。神经网络方法主要是bp算法,这个俺也不太了解。


文本分类, 所谓的文本分类就是把文本进行归类,不同的文章根据文章的内容应该属于不同的类别,文本分类离不开分词,要将一个文本进行分类,首先需要对该文本进行分词,利用分词之后的的项向量作为计算因子,再使用一定的算法和样本中的词汇进行计算,从而可以得出正确的分类结果。在这个例子中,我将使用庖丁分词器对文本进行分词。

下面这个例子将使用反余弦进行词汇单元进行匹配,
第一步,训练样本:
protected Map<String, Map<String, Integer>> getClassVector(List<Category> categoryList) throws Exception {
		
		if (categoryList == null || categoryList.size() == 0) {
			if (logger.isDebugEnabled()) {
				logger.debug("The list of new categoryList which should be classified is null or size = 0");
			}
			return Collections.emptyMap();
		}
		
		Map<String, Map<String, Integer>> categoryMap = new HashMap<String, Map<String, Integer>>();
		
		Directory ramDir = new RAMDirectory();
		IndexWriter writer = new IndexWriter(ramDir, new PaodingAnalyzer(), true);
		
		for (Category cRc : categoryList) {
			for (Article item : cRc.getArticleList()) {
				
				Document doc = new Document();
				doc.add(new Field("description", item.getContent(), Field.Store.NO,
						Field.Index.TOKENIZED, TermVector.YES));
				doc.add(new Field("category", cRc.getId().toString(), Field.Store.YES, Field.Index.NO));
				writer.addDocument(doc);
			}
		}
		
		if (logger.isDebugEnabled()) {
			logger.debug("Generate the index in the memory, the size of categoryList list is " + categoryList.size());
		}
		
		writer.close();
		
		buildContentVectors(ramDir, categoryMap, "category", "description");
		return categoryMap;
		
	}

第二步:对待分类的文章进行分词(原理和样本训练类似):
protected Map<String, Map<String, Integer>> getArticleVector(List<Article> articleList) throws Exception {
		if (articleList == null || articleList.size() == 0) {
			if (logger.isDebugEnabled()) {
				logger.debug("The list of articles which should be classified is null or size = 0");
			}
		}
		
		Map<String, Map<String, Integer>> articleMap = new HashMap<String, Map<String, Integer>>();
		
		Directory articleRamDir = new RAMDirectory();
//		IndexWriter writer = new IndexWriter(articleRamDir, new ChineseAnalyzer(), true);
		IndexWriter writer = new IndexWriter(articleRamDir, new PaodingAnalyzer(), true);
		
		for (Article article : articleList) {
			Document doc = new Document();
			doc.add(new Field("articleId", article.getId(),
					Field.Store.YES, Field.Index.NO));
			doc.add(new Field("description", article.getContent(), Field.Store.NO, Field.Index.TOKENIZED, TermVector.YES));
			writer.addDocument(doc);
		}
		
		writer.flush();
		writer.close();
		
		buildContentVectors(articleRamDir, articleMap, "articleId", "description");
		return articleMap;
	}

分类的核心算法(下面这段代码的原理来自于lucene in action):
public double caculateVectorSpace(Map<String, Integer> articleVectorMap, Map<String, Integer> classVectorMap) {
		if (articleVectorMap == null || classVectorMap == null) {
			if (logger.isDebugEnabled()) {
				logger.debug("itemVectorMap or classVectorMap is null");
			}
			
			return 20;
		}
		
		int dotItem = 0;
		double denominatorOne = 0;
		double denominatorTwo = 0;
		
		
		for (Entry<String, Integer> entry : articleVectorMap.entrySet()) {
			String word = entry.getKey();
			double categoryWordFreq = 0;
			double articleWordFreq = 0;
			
			if (classVectorMap.containsKey(word)) {
				categoryWordFreq = classVectorMap.get(word).intValue() / classVectorMap.size();
				articleWordFreq = entry.getValue().intValue() / articleVectorMap.size();
			}
			
			dotItem += categoryWordFreq * articleWordFreq;
			denominatorOne += categoryWordFreq * categoryWordFreq;
			denominatorTwo += articleWordFreq * articleWordFreq;
		}
		
		double denominator = Math.sqrt(denominatorOne) * Math.sqrt(denominatorTwo);
		
		double ratio =  dotItem / denominator;
		
		return Math.acos(ratio);
	}

效果:
测试数据:
public static List<Category> prepareCategoryList() {
		List<Category> categoryList = new ArrayList<Category>();
		List<Article> articleList = new ArrayList<Article>();
		
		Category c = new Category();
		c.setArticleList(articleList);
		c.setId("1");
		categoryList.add(c);
		
		Article a1 = new Article();
		a1.setId("1");
		a1.setTitle("Hibernate初探");
		a1.setContent("开始看Hibernate reference,运行hibernate的test中的代码。 Environment是一个非常重要的类。它定义了很多常量,最重要的是hibernate的入口在这里。");
		
		Article a2 = new Article();
		a2.setId("2");
		a2.setTitle("Hibernate SQL方言");
		a2.setContent("PO的数据类型设置 int 还是Integer Integer 允许为 null Hibernate 既可以访问Field也可以访问Property");
		
		Article a3 = new Article();
		a3.setId("3");
		a3.setTitle("Hibernate 杂烩");
		a3.setContent("Hibernate 中聚合函数的使用 Criteria接口的Projections类主要用于帮助Criteria接口完成数据的分组查询和统计功能:");
		
		Article a4 = new Article();
		a4.setId("4");
		a4.setTitle("Hibernate映射类型");
		a4.setContent("Hibernate映射类型Hibernate映射类型,对应的基本类型及对应的标准SQL类型");
		
		
		articleList.add(a1);
		articleList.add(a2);
		articleList.add(a3);
		articleList.add(a4);
		
		return categoryList;
	}
	
	public static List<Article> prepareArticleList() {
		List<Article> articleList = new ArrayList<Article>();
		Article a1 = new Article();
		a1.setId("1");
		a1.setTitle("Hibernate学习笔记(一)");
		a1.setContent("本笔记的内容: 分层体系结构 ORM介绍 Hibernate简介 Hibernate开发步骤 Hibernate核心API ");
		
		Article a2 = new Article();
		a2.setId("2");
		a2.setTitle("Hibernate的性能问题");
		a2.setContent("各位老大,使用hibernate做企业级别的应用,会不会有性能问题啊?比如大数据量的搜索或者客户端同时大量的请求,会不会严重影响性能啊?有没有什么好的解决办法? 谢了先!");
		
		Article a3 = new Article();
		a3.setId("3");
		a3.setTitle("Spring2.5全面支持JEE5的实现");
		a3.setContent("Spring 2.5 发布已经有一段时间了,一直没有时间研究一下,只是听说有很多方面的提升。有一点十分重要的就是全面支持JEE5风格的annotation。");
		
		Article a4 = new Article();
		a4.setId("4");
		a4.setTitle("谈谈Spring的SqlMapClientTemplate对SqlMapClientCallback");
		a4.setContent("谈谈Spring的SqlMapClientTemplate对SqlMapClientCallback的使用 ■记得以前在看SqlMapClientTemplate的源代码的时候,下面的这两段代码硬是没看懂当时我很疑惑:真的有必要用到内部匿名类这样诡异的手法么?");
		
		Article a5 = new Article();
		a5.setId("5");
		a5.setTitle("spring 2.0 学习笔记");
		a5.setContent("前几天学习hibernate!在mysql下都能正常跑出来.! 但是我一换成oracle就出现下面这种情况: 小弟不解呀..google了很多次也解决不了此问题::.希望老大门帮忙看一下哈.!!! 环境:MyEclipse5.5,hibernate2.0,spring2.0");
		
		articleList.add(a1);
		articleList.add(a2);
		articleList.add(a3);
		articleList.add(a4);
		articleList.add(a5);
		
		return articleList;
	}

以上测试代码中的数据来源于javaeye的文章。
输出:
2008-02-19 11:05:42,031 DEBUG ArticleClassifierImpl:74 - articleId=2---------acos value=1.412016112149136
2008-02-19 11:05:42,031 DEBUG ArticleClassifierImpl:74 - articleId=1---------acos value=1.3258176636680326
2008-02-19 11:05:42,031 DEBUG ArticleClassifierImpl:74 - articleId=5---------acos value=1.4244090675006476

有此可见文章id号为1,2,5的文章符合hibernate分类,事实上我们还要更进一步,假设我们有两个分类,hibernate,spring,各有5各样本,那么最后的结果应该再次作最小符合判断,acos值最小的则认为该article属于该分类,同学们可以自己做一下实验。

文本分类中有很多注意点,比如说噪音词去除(上面的代码中并包括最简单的噪音词去除功能)等,接下来我会使用knn算法改造以上代码,并使用相同的测试数据并比对测试结果。
   发表时间:2008-02-19  
建议看Lucene In Action,或者Google的数学之美系列-余弦定理和新闻的分类
0 请登录后投票
   发表时间:2008-02-19  
fyting 写道
建议看Lucene In Action,或者Google的数学之美系列-余弦定理和新闻的分类

你对数据挖掘可能还不是很了解,lucene in action我当然看过,看过多次,可是lucene in action并不是描述数据挖掘的书,里面只有几页纸的内容描写到分类,但是分类是一门很大的学问,涉及很多方法,很多算法,如果你对数据挖掘有兴趣建议你到圈子里看看我推荐的书
0 请登录后投票
   发表时间:2008-02-19  
knn算法是很简单的分类算法了。至于分类,不仅仅是数据挖掘,在很多领域都有应用的。

这样光贴代码不整算法原理对于真正的学习原理用处不大。
0 请登录后投票
   发表时间:2008-02-19  
mochow 写道
knn算法是很简单的分类算法了。至于分类,不仅仅是数据挖掘,在很多领域都有应用的。

这样光贴代码不整算法原理对于真正的学习原理用处不大。

据我所知,分类是数据挖掘的一种技术而已,很多领域都有应用就表明很多领域都有应用数据挖掘,而且虽然是很多应用都有应用,但是比例还是非常之少。

这里并没有什么特殊的算法原理,如果算有的话就是反余弦匹配。

再讲细一点:
在一个二维空间里,每个类别都有自己的项向量,而新的文章也有自己的项向量,每篇新文章都和类别进行匹配,夹角最小的那个即为该文章的类别。

不同的分类场景使用的不同的算法,这个我想你应该没有异议,本文的例子建立在文本分类上,所以在改进这个例子的时候第一个想到的就是kNN算法,虽然简单但是效果未必不好。这篇文章只不过是开场,下面的文章中我自然会介绍分类技术中常用的算法。

ps:文章有大段代码,但是有一半代码都是测试数据,而不是真正有用的代码。

原理嘛看这张图

  • 大小: 64.7 KB
0 请登录后投票
   发表时间:2008-02-19  
。我可以很负责的告诉你,你的回复真的很搞笑。你认为用分类用的很少那些领域,只是因为你无知而已撒,不可能因为你不知道它们就不存在。
0 请登录后投票
   发表时间:2008-02-19  
早在数据挖掘这个东东出现之前,分类就已经很广泛的运用在很多领域了。
0 请登录后投票
   发表时间:2008-02-19  
mochow 写道
。我可以很负责的告诉你,你的回复真的很搞笑。你认为用分类用的很少那些领域,只是因为你无知而已撒,不可能因为你不知道它们就不存在。

哦,你好像没有仔细看我的帖子,我说的是占总应用的比例较少,而不是说它数量少,比如说中国有13亿人口,某一个民族只占百分之5,那么它的总数有6500w,这么说你能理解吧。

当然确实也有可能是我无知,因为我做的项目里,分类的技术占项目总数的很小比例,所以我认为它比例较小,如果说是这样,我不得不承认我的无知,因为我所取的样本太少,只是我自己,所以才作出了有误差的判断。

不过我也在想是不是我们理解的分类的概念不一致导致的,我理解的分类是数据挖掘中的分类,就如概念所讲,你说的分类是指什么,会不会指比如china-pub的图书进行手工分类也叫分类?

0 请登录后投票
   发表时间:2008-02-19  
 
0 请登录后投票
   发表时间:2008-02-19  
mochow 写道
 

呵,有意见可以说出来,不用这样,这样只不过能说明你真的是一个女人,而不是马甲。

分类现在在任何资料中都归类到数据挖掘中了,不要用老观点看问题了

而且我不认为我们有必要为了争“分类应用是否多”这个问题而在这里相互贬低,当然至少我没有贬低你
1 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics