`
AngelAndAngel
  • 浏览: 234309 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
    昨天实现了一个基于贝叶斯定理的的文本分类,贝叶斯定理假设特征属性(在文本中就是词汇)对待分类项的影响都是独立的,道理比较简单,在中文分类系统中,分类的准确性与分词系统的好坏有很大的关系,这段代码也是试验不同分词系统才顺手写的一个。
    试验数据用的sogou实验室的文本分类样本,一共分为9个类别,每个类别文件夹下大约有2000篇文章。由于文本数据量确实较大,所以得想办法让每次训练的结果都能保存起来,以便于下次直接使用,我这里使用序列化的方式保存在硬盘。
  训练代码如下:
/**
 * 训练器
 * 
 * @author duyf
 * 
 */
class Train implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public final static String SERIALIZABLE_PATH = "D:\\workspace\\Test\\SogouC.mini\\Sample\\Train.ser";
	// 训练集的位置
	private String trainPath = "D:\\workspace\\Test\\SogouC.mini\\Sample";

	// 类别序号对应的实际名称
	private Map<String, String> classMap = new HashMap<String, String>();

	// 类别对应的txt文本数
	private Map<String, Integer> classP = new ConcurrentHashMap<String, Integer>();

	// 所有文本数
	private AtomicInteger actCount = new AtomicInteger(0);

	

	// 每个类别对应的词典和频数
	private Map<String, Map<String, Double>> classWordMap = new ConcurrentHashMap<String, Map<String, Double>>();

	// 分词器
	private transient Participle participle;

	private static Train trainInstance = new Train();

	public static Train getInstance() {
		trainInstance = new Train();

		// 读取序列化在硬盘的本类对象
		FileInputStream fis;
		try {
			File f = new File(SERIALIZABLE_PATH);
			if (f.length() != 0) {
				fis = new FileInputStream(SERIALIZABLE_PATH);
				ObjectInputStream oos = new ObjectInputStream(fis);
				trainInstance = (Train) oos.readObject();
				trainInstance.participle = new IkParticiple();
			} else {
				trainInstance = new Train();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

		return trainInstance;
	}

	private Train() {
		this.participle = new IkParticiple();
	}

	public String readtxt(String path) {
		BufferedReader br = null;
		StringBuilder str = null;
		try {
			br = new BufferedReader(new FileReader(path));

			str = new StringBuilder();

			String r = br.readLine();

			while (r != null) {
				str.append(r);
				r = br.readLine();

			}

			return str.toString();
		} catch (IOException ex) {
			ex.printStackTrace();
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			str = null;
			br = null;
		}

		return "";
	}

	/**
	 * 训练数据
	 */
	public void realTrain() {
		// 初始化
		classMap = new HashMap<String, String>();
		classP = new HashMap<String, Integer>();
		actCount.set(0);
		classWordMap = new HashMap<String, Map<String, Double>>();

		// classMap.put("C000007", "汽车");
		classMap.put("C000008", "财经");
		classMap.put("C000010", "IT");
		classMap.put("C000013", "健康");
		classMap.put("C000014", "体育");
		classMap.put("C000016", "旅游");
		classMap.put("C000020", "教育");
		classMap.put("C000022", "招聘");
		classMap.put("C000023", "文化");
		classMap.put("C000024", "军事");

		// 计算各个类别的样本数
		Set<String> keySet = classMap.keySet();

		// 所有词汇的集合,是为了计算每个单词在多少篇文章中出现,用于后面计算df
		final Set<String> allWords = new HashSet<String>();

		// 存放每个类别的文件词汇内容
		final Map<String, List<String[]>> classContentMap = new ConcurrentHashMap<String, List<String[]>>();

		for (String classKey : keySet) {

			Participle participle = new IkParticiple();
			Map<String, Double> wordMap = new HashMap<String, Double>();
			File f = new File(trainPath + File.separator + classKey);
			File[] files = f.listFiles(new FileFilter() {

				@Override
				public boolean accept(File pathname) {
					if (pathname.getName().endsWith(".txt")) {
						return true;
					}
					return false;
				}

			});

			// 存储每个类别的文件词汇向量
			List<String[]> fileContent = new ArrayList<String[]>();
			if (files != null) {
				for (File txt : files) {
					String content = readtxt(txt.getAbsolutePath());
					// 分词
					String[] word_arr = participle.participle(content, false);
					fileContent.add(word_arr);
					// 统计每个词出现的个数
					for (String word : word_arr) {
						if (wordMap.containsKey(word)) {
							Double wordCount = wordMap.get(word);
							wordMap.put(word, wordCount + 1);
						} else {
							wordMap.put(word, 1.0);
						}
						
					}
				}
			}

			// 每个类别对应的词典和频数
			classWordMap.put(classKey, wordMap);

			// 每个类别的文章数目
			classP.put(classKey, files.length);
			actCount.addAndGet(files.length);
			classContentMap.put(classKey, fileContent);

		}

		

		

		// 把训练好的训练器对象序列化到本地 (空间换时间)
		FileOutputStream fos;
		try {
			fos = new FileOutputStream(SERIALIZABLE_PATH);
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(this);
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * 分类
	 * 
	 * @param text
	 * @return 返回各个类别的概率大小
	 */
	public Map<String, Double> classify(String text) {
		// 分词,并且去重
		String[] text_words = participle.participle(text, false);

		Map<String, Double> frequencyOfType = new HashMap<String, Double>();
		Set<String> keySet = classMap.keySet();
		for (String classKey : keySet) {
			double typeOfThis = 1.0;
			Map<String, Double> wordMap = classWordMap.get(classKey);
			for (String word : text_words) {
				Double wordCount = wordMap.get(word);
				int articleCount = classP.get(classKey);

				/*
				 * Double wordidf = idfMap.get(word); if(wordidf==null){
				 * wordidf=0.001; }else{ wordidf = Math.log(actCount / wordidf); }
				 */

				// 假如这个词在类别下的所有文章中木有,那么给定个极小的值 不影响计算
				double term_frequency = (wordCount == null) ? ((double) 1 / (articleCount + 1))
						: (wordCount / articleCount);

				// 文本在类别的概率 在这里按照特征向量独立统计,即概率=词汇1/文章数 * 词汇2/文章数 。。。
				// 当double无限小的时候会归为0,为了避免 *10

				typeOfThis = typeOfThis * term_frequency * 10;
				typeOfThis = ((typeOfThis == 0.0) ? Double.MIN_VALUE
						: typeOfThis);
				// System.out.println(typeOfThis+" : "+term_frequency+" :
				// "+actCount);
			}

			typeOfThis = ((typeOfThis == 1.0) ? 0.0 : typeOfThis);

			// 此类别文章出现的概率
			double classOfAll = classP.get(classKey) / actCount.doubleValue();

			// 根据贝叶斯公式 $(A|B)=S(B|A)*S(A)/S(B),由于$(B)是常数,在这里不做计算,不影响分类结果
			frequencyOfType.put(classKey, typeOfThis * classOfAll);
		}

		return frequencyOfType;
	}

	public void pringAll() {
		Set<Entry<String, Map<String, Double>>> classWordEntry = classWordMap
				.entrySet();
		for (Entry<String, Map<String, Double>> ent : classWordEntry) {
			System.out.println("类别: " + ent.getKey());
			Map<String, Double> wordMap = ent.getValue();
			Set<Entry<String, Double>> wordMapSet = wordMap.entrySet();
			for (Entry<String, Double> wordEnt : wordMapSet) {
				System.out.println(wordEnt.getKey() + ":" + wordEnt.getValue());
			}
		}
	}

	public Map<String, String> getClassMap() {
		return classMap;
	}

	public void setClassMap(Map<String, String> classMap) {
		this.classMap = classMap;
	}

}

在试验过程中,发觉某篇文章的分类不太准,某篇IT文章分到招聘类别下了,在仔细对比了训练数据后,发觉这是由于招聘类别每篇文章下面都带有“搜狗”的标志,而待分类的这篇IT文章里面充斥这搜狗这类词汇,结果招聘类下的概率比较大。由此想到,在除了做常规的贝叶斯计算时,需要把不同文本中出现次数多的词汇权重降低甚至删除(好比关键词搜索中的tf-idf),通俗点讲就是,在所有训练文本中某词汇(如的,地,得)出现的次数越多,这个词越不重要,比如IT文章中“软件”和“应用”这两个词汇,“应用”应该是很多文章类别下都有的,反而不太重要,但是“软件”这个词汇大多只出现在IT文章里,出现在大量文章的概率并不大。 我这里原本打算计算每个词的idf,然后给定一个阀值来判断是否需要纳入计算,但是由于词汇太多,计算量较大(等待结果时间较长),所以暂时注释掉了。

By 阿飞哥 转载请说明
腾讯微博:http://t.qq.com/duyunfeiRoom
新浪微博:http://weibo.com/u/1766094735
分享到:
评论
3 楼 njthnet 2016-06-07  
Participle 和 IkParticiple 这2个类找不到,能给个提示吗?
2 楼 u010402518 2015-10-15  
分类还是可行的,如果学习的在多一点那就会更准了。
给大家一个调用的例子
Train train = Train.getInstance();
// 训练,训练好模型之后序列化到磁盘就不用再次训练了
//train.realTrain();
Map<String, Double> resultMap = train.classify("胡润研究院今日发布《胡润百富榜》,61岁的王健林及其家族以2200亿财富超过马云,第二次成为中国首富,财富比去年增长52%。大陆十亿美金富豪人数首度超越美国,达596位。51岁的马云及其家族以1450亿元退居第二,财富比去年减少3%");

train.pringAll();
1 楼 u010402518 2015-10-15  
文章写的不错,思路很清晰,终于找到了一篇可以用的文章 。

相关推荐

    朴素贝叶斯文本分类器(java实现)

    朴素贝叶斯文本分类器是一种广泛应用的机器学习算法,尤其在自然语言处理领域,用于将文本数据归类到预定义的类别中。本程序的Java实现深入探讨了这一概念,并提供了完整的工具集,包括源代码、实验报告、可执行程序...

    朴素贝叶斯算法文本分类JAVA实现

    在Java环境下实现朴素贝叶斯分类器,我们可以分为以下几个步骤: 1. 数据预处理: 在文本分类任务中,首先需要对文本数据进行预处理,包括分词、去除停用词(如“的”、“是”等常见无实际意义的词语)、词干提取...

    基于Java和mapreduce实现的贝叶斯文本分类器设计.zip

    本项目为一个Hadoop课程设计,使用Java语言和map/reduce实现贝叶斯文本分类器。项目的具体内容如下:1:用MapReduce算法实现贝叶斯分类器的训练过程,并输出训练模型; 2:用输出的模型对测试集文档进行分类测试。...

    贝叶斯分类器实现的文本分类(Java实现)

    本项目通过Java编程语言实现了一个贝叶斯分类器,用于对文本数据进行分类。接下来,我们将深入探讨贝叶斯分类器的工作原理以及如何在Java中实现它。 贝叶斯分类器基于概率论中的贝叶斯定理,该定理描述了在已知某些...

    java语言实现的贝叶斯文本分类器

    Java语言实现的贝叶斯文本分类器是一种基于统计学理论的机器学习算法,主要用于处理文本数据的分类问题。贝叶斯定理是概率论中的一个基础概念,它为预测未知类别的文本提供了一种有效的方法。在Java中,我们可以利用...

    贝叶斯文本分类

    本教程将深入探讨“贝叶斯文本分类”,并围绕朴素贝叶斯理论及其在文本分类中的应用进行详细阐述。 **朴素贝叶斯分类器** 朴素贝叶斯分类器是基于概率论的贝叶斯定理,该定理表明,给定一个事件的先验概率,我们...

    java实现朴素贝叶斯分类算法

    在Java中实现朴素贝叶斯分类器,我们需要理解以下几个关键知识点: 1. **贝叶斯定理**:贝叶斯定理是概率论中的一个公式,它描述了在已知某些条件下,事件A发生的条件概率P(A|B)如何根据先验概率P(A)和证据B的概率P...

    贝叶斯文本分类器JAVA

    贝叶斯文本分类器在Java中的实现是一种广泛应用的自然语言处理技术,主要用于对文本数据进行自动分类。这种分类器基于托马斯·贝叶斯的统计理论,它假设特征之间是独立的,并通过学习已有的训练数据来预测新文本的...

    Hadoop课程设计-基于Java和mapreduce实现的贝叶斯文本分类器设计

    在本Hadoop课程设计中,我们将探讨如何使用Java编程语言和MapReduce框架来实现一个贝叶斯文本分类器。这个项目旨在让学生理解大数据处理的基本原理,以及如何利用Hadoop生态系统来解决实际问题,特别是文本分类任务...

    java贝叶斯分类器

    Java贝叶斯分类器是一种基于概率统计的机器学习方法,主要利用贝叶斯定理进行文本分类。在Java编程环境中,这种分类器被广泛应用于自然语言处理、信息检索、垃圾邮件过滤等领域。以下是对这个主题的详细阐述: 一、...

    贝叶斯分类算法的JAVA实现

    **JAVA实现贝叶斯分类** 在JAVA中,我们可以使用开源库如Weka或JavaBayes来实现贝叶斯分类。Weka是一个强大的数据挖掘工具,提供了多种分类和聚类算法,包括朴素贝叶斯。JavaBayes则是一个专门为贝叶斯网络设计的...

    朴素贝叶斯文本分类

    朴素贝叶斯文本分类是一种广泛应用于自然语言处理领域的机器学习方法,主要用于文本数据的分类。它的核心思想是基于贝叶斯定理,并假设各特征之间相互独立,因此得名“朴素”。在这个项目中,我们将使用Java语言来...

    朴素贝叶斯实际应用java实现

    3. **Java实现**:在Java中,可以使用诸如Weka这样的机器学习库来实现朴素贝叶斯分类器。Weka提供了丰富的机器学习算法接口,可以方便地进行数据预处理、模型训练和评估。另外,也可以手动编写代码,实现朴素贝叶斯...

    文本分类java 实现

    在本文中,我们将深入探讨如何使用Java来实现文本分类,特别是在网络新闻文本的自动化处理中。文本分类是一种机器学习任务,其目标是根据文本内容将其分配到预定义的类别中。我们将关注两种常用的方法:朴素贝叶斯...

    朴素贝叶斯 文本分类

    通过深入研究这个Java项目,我们可以掌握朴素贝叶斯文本分类的基本概念,并学习如何将理论应用于实践中。这个项目不仅提供了理论知识,还有实际的代码示例,是学习和应用朴素贝叶斯算法的好资源。

    朴素贝叶斯算法实现分类问题(Java实现)

    在这个Java实现的案例中,我们将深入探讨如何利用朴素贝叶斯进行分类,并通过读取txt文件来处理数据。 首先,朴素贝叶斯的核心思想是,给定一个新实例,我们计算其属于每个类别的概率,并将其分配到概率最高的类别...

    朴素贝叶斯算法java实现

    在Java中实现朴素贝叶斯分类器,我们可以利用其简单高效的特点,适用于文本分类、垃圾邮件过滤、情感分析等多种场景。 首先,我们需要理解朴素贝叶斯的基本原理。朴素贝叶斯模型假设每个特征对类别条件概率的影响是...

    朴素贝叶斯对于文本分类

    朴素贝叶斯(Naive Bayes)是一种基于概率论的机器学习算法,尤其...这些文件可能一起提供了朴素贝叶斯算法在文本分类中的实现细节和示例。通过阅读和理解这些文件,可以深入掌握如何在实际项目中运用朴素贝叶斯方法。

    Naive Bays朴素贝叶斯算法在JAVA中的实现

    朴素贝叶斯(Naive Bayes)算法是一种基于概率理论的分类方法,它在机器学习领域广泛应用,尤其在文本分类、垃圾邮件过滤等方面表现出色。该算法基于贝叶斯定理,假设特征之间相互独立,因此得名“朴素”。在Java中...

Global site tag (gtag.js) - Google Analytics