当前位置:   article > 正文

Java---利用互信息方式进特征选择,用于文本分类_互信息 java

互信息 java

Java—利用互信息方式进特征选择

任务定义

原始材料:多个类别文件,每个文件包含若干样本
目标:从每个类别文件中提取若干词语,这些词具有类区分度,即在类A中常出现,在类B中不常出现。
方法:使用互信息方式进行词语提取。

步骤
  1. 构建字典:Map<词语,出现的该词的文档数>
    1)构建两种字典:大字典—所有文本;小字典—单个类别文件。
    2)逐个读取文件夹内的每个类别文件,每个文件中包含有若干行样本。对每行文本进行分词,过滤,去除重复词。
    3)根据返回的词集合,更新小字典,大字典。
    4)得到若干个类别字典和一个大字典

  2. 计算互信息值
    计算公式请看:互信息公式
    其中: (以下为个人理解,不敢保证为公式所定义的)
    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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200

所使用的分词依赖:(可尝试多种分词方式,会带来不同结果)

<dependency>
    <groupId>org.ansj</groupId>
    <artifactId>ansj_seg</artifactId>
    <version>5.1.3</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
完!
  • 1
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/花生_TL007/article/detail/239105
推荐阅读
相关标签
  

闽ICP备14008679号