赞
踩
原始材料:多个类别文件,每个文件包含若干样本
目标:从每个类别文件中提取若干词语,这些词具有类区分度,即在类A中常出现,在类B中不常出现。
方法:使用互信息方式进行词语提取。
构建字典:Map<词语,出现的该词的文档数>
1)构建两种字典:大字典—所有文本;小字典—单个类别文件。
2)逐个读取文件夹内的每个类别文件,每个文件中包含有若干行样本。对每行文本进行分词,过滤,去除重复词。
3)根据返回的词集合,更新小字典,大字典。
4)得到若干个类别字典和一个大字典
计算互信息值
计算公式请看:互信息公式
其中: (以下为个人理解,不敢保证为公式所定义的)
N11:为在该类中,该词出现的样本数
N01:为在该类中,该词未出现的样本数
N10:为除该类外,该词出现的样本数
N00:为除该类外,该词未出现的样本数
N:为总的样本数
N1.:为在大字典中该词出现的样本数
N0.:为在大字典中该词未出现的样本数
N.1:为该类别的样本数
N.0:为其他类别的样本数
import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileWriter; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.HashMap; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.ansj.domain.Result; import org.ansj.domain.Term; import org.ansj.recognition.impl.StopRecognition; import org.ansj.splitWord.analysis.ToAnalysis; public class mutual_info { //存放所有的大词典 private static Map<String, Double> bigMap = new HashMap<String, Double>(); // 存放每个知识点文件中的样本数 private static Map<String, Double> classNum = new HashMap<String, Double>(); // 样本总数 private static Double samplesum = 0.0; public static void main(String[] args) throws Exception { // Analyzer analyzer = new AnsjAnalyzer(TYPE.index_ansj); System.out.println("Begin:"); // 知识点文件夹路径 String path = "xxxxx/"; //互信息值文件夹保存路径 String savepath = "xxxxx/"; String[] filename = new File(path).list(); System.out.println("Building Map..."); // 用于存放各个小词典 Map<String, Map<String, Double>> allMap = new HashMap<String, Map<String, Double>>(); for (String file : filename) { System.out.println(file); allMap.put(file.replace(".txt", ""), buildMap(path + file, file.replace(".txt", ""))); } System.out.println("Saving..."); // 计算互信息值,每个知识点文件对应一个互信息文件,包含知识点内每个词汇的互信息值 for (int i = 0; i < filename.length; i++) { // 保存互信息 String temp = filename[i].replace(".txt", ""); System.out.println(temp); saveMutualInfo(allMap.get(temp), savepath + filename[i], classNum.get(temp)); } //测试单个词语于单个类别当中的互信息值 // String className = "电磁学-传感器"; // String word = "用气"; // Double value = getMutualInfo(word, allMap.get(className).get(word), classNum.get(className)); // System.out.println(value); System.out.println("End."); } /** * 将属于该知识点内词汇的互信息值保存 * @param sMap * @param savepath */ public static void saveMutualInfo(Map<String, Double> sMap, String savepath, Double num) throws Exception { // 打开写入文件 FileWriter fw = new FileWriter(savepath, true); PrintWriter out = new PrintWriter(fw); Double value = 0.0; out.write("key" + "\t" + "value"); out.println(); for (Map.Entry<String, Double> entry : sMap.entrySet()) { // 计算互信息值 value = getMutualInfo(entry.getKey(), entry.getValue(), num); // 写入数据 out.write(entry.getKey() + "\t" + String.valueOf(value)); out.println(); } // 关闭文件 fw.close(); out.close(); } /** * * @param word * 该词 * @param fre * 该词在文档中出现的数量 * @param num * 该文档的样本总数 * @return */ public static double getMutualInfo(String word, Double fre, Double num) { // 在总样本数上,该词出现的样本数与未出现的样本数 Double N1 = bigMap.get(word); Double N0 = samplesum - N1; Double N11 = fre; //在该类中,该词出现的样本数 Double N01 = num - fre; //在该类中,该词未出现的样本数 Double N10 = N1 - fre + 1; // 加 1 防止NaN的出现,除该类外,该词出现的样本数 Double N00 = samplesum - num - N10;// 除该类外,该词未出现的样本数 return ((N11 * Math.log((samplesum * N11) / (N1 * num)) / Math.log(2.0)) + (N01 * Math.log((samplesum * N01) / (N0 * num)) / Math.log(2.0)) + (N10 * Math.log((samplesum * N10) / (N1 * (samplesum - num))) / Math.log(2.0)) + (N00 * Math.log((samplesum * N00) / (N0 * (samplesum - num))) / Math.log(2.0))); } /** * 根据文件名,构建该知识点的map;同时,对大词典进行更新 * * @param filepath * 文件名 * @return */ public static Map<String, Double> buildMap(String filepath, String className) throws Exception { // 专属该知识点的 小词典 Map<String, Double> result = new HashMap<String, Double>(); // 打开文件 FileInputStream fis = new FileInputStream(filepath); BufferedReader br = new BufferedReader(new InputStreamReader(fis, "UTF-8")); String line = ""; Double count = 0.0; while ((line = br.readLine()) != null) { // 更新小词典 updateSmallMap(result, wordAnalyzer(line)); // 更新大词典 updateBigMap(wordAnalyzer(line)); count++; } // 关闭文件 br.close(); fis.close(); // 保存该文件内的文本数量 classNum.put(className, count); samplesum += count; return result; } /** * 对大字典进行更新 * * @param words */ public static void updateBigMap(Set<String> words) { // 具有某个词的文档数 Double count; for (String string : words) { count = bigMap.get(string); if (count == null) { bigMap.put(string, 1.0); } else { bigMap.put(string, count + 1); } } } /** * 对单个字典进行更新 * @param sMap * @param words * @return */ public static Map<String, Double> updateSmallMap(Map<String, Double> sMap, Set<String> words) { // 某个词出现的频次 Double count; for (String string : words) { count = sMap.get(string); if (count == null) { sMap.put(string, 1.0); } else { sMap.put(string, count + 1); } } return sMap; } /** * 对单行文本进行分词,分词后每个词以空格相隔开 * @param line * @return */ public static Set<String> wordAnalyzer(String line) { Set<String> result = new TreeSet<String>(); StopRecognition filter = new StopRecognition(); filter.insertStopNatures("w"); // 过滤标点 filter.insertStopNatures("null"); // 过滤空格 filter.insertStopNatures("m"); //过滤数词,会将 半数 该词当做是数词进行过滤 filter.insertStopWords("的"); // 过滤单个词 Result fliterContent = ToAnalysis.parse(line).recognition(filter); for (Term term : fliterContent) { if (!result.contains(term.getName())&&(term.getName().length()!=1)) { result.add(term.getName()); } } return result; } }
所使用的分词依赖:(可尝试多种分词方式,会带来不同结果)
<dependency>
<groupId>org.ansj</groupId>
<artifactId>ansj_seg</artifactId>
<version>5.1.3</version>
</dependency>
完!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。