概述
Java—利用互信息方式进特征选择
任务定义
原始材料:多个类别文件,每个文件包含若干样本
目标:从每个类别文件中提取若干词语,这些词具有类区分度,即在类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>
完!
最后
以上就是粗暴白羊为你收集整理的Java---利用互信息方式进特征选择,用于文本分类的全部内容,希望文章能够帮你解决Java---利用互信息方式进特征选择,用于文本分类所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复