文本挖掘——准备文本读写及对Map操作的工具类
Posted Fighting_No1
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文本挖掘——准备文本读写及对Map操作的工具类相关的知识,希望对你有一定的参考价值。
文本挖掘是一个对具有丰富语义的文本进行分析,从而理解其所包含的内容和意义的过程。文本挖掘包含分词、文本表示、文本特征选择、文本分类、文本聚类、文档自动摘要等方面的内容。文本挖掘的具体流程图可下图所示:
我的项目是以复旦大学中文语料库和路透社英文语料库为数据集的,都是有类别的两层目录文本集。
不管你要做什么,你首先都要先读取文本,为了方便后面的操作,我写了几个工具类,这里先将文本读取Reader类、文本写入Writer类和对Map的各种操作MapUtil类。
Reader
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Angela
*/
public class Reader {
/**
* 获取一篇文本的编码格式,注:有时不准
* @param filePath文本文件路径
* @return 文本文件的编码格式
*/
public static String getCharset(String filePath){
String charset = null;
try{
BufferedInputStream bin = new BufferedInputStream(
new FileInputStream(filePath));
int p = (bin.read() << 8) + bin.read();
switch (p) {
case 0xefbb:
charset = "UTF-8";
break;
case 0xfffe:
charset = "Unicode";
break;
case 0xfeff:
charset = "UTF-16BE";
break;
default:
charset = "GBK";
}
} catch (FileNotFoundException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return charset;
}
/**
* 读取一篇文本的全部内容
* @param filePath 还未分词的文本
* @return 无换行的文本内容,读取的内容用于后面的分词
*/
public static String read(String filePath){
String content="";
//String charset=getCharset(filePath);
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"gb2312"));
String s;
while((s=br.readLine())!=null){
content+=s;
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return content;
}
/**
* 一行一个词地读取一篇文本,得到特征集
* @param filePath
* @return 读取分词后的文本,得到出现在文本中的所有不重复的特征Set
*/
public static Set<String> toSet(String filePath){
Set<String> set=new HashSet<String>();
//String charset=getCharset(filePath);
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"utf-8"));
String s;
while((s=br.readLine())!=null){
set.add(s);
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return set;
}
/**
* 一行一个词地读取一篇文本,得到特征列表,有重复的
* @param filePath
* @return 读取分词后的文本,得到出现在文本中的所有特征(有重复的)List
*/
public static List<String> toList(String filePath){
List<String> list=new ArrayList<String>();
//String charset=getCharset(filePath);
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"utf-8"));
String s;
while((s=br.readLine())!=null){
list.add(s);
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return list;
}
/**
* 读取文件内容,返回一个特征-权重的Map
* @param filePath
* @return
*/
public static Map<String,Integer> toIntMap(String filePath){
Map<String,Integer> map=new HashMap<String,Integer>();
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"utf-8"));
String str;
while((str=br.readLine())!=null){//特征
String[] s=str.split(",");
String key=s[0];//特征
int value=Integer.parseInt(s[1]);//特征值
map.put(key, value);
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
return map;
}
/**
* 读取文件内容,返回一个特征-权重的Map
* @param filePath
* @return
*/
public static Map<String,Double> toDoubleMap(String filePath){
Map<String,Double> map=new HashMap<String,Double>();
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"utf-8"));
String str;
while((str=br.readLine())!=null){//特征
String[] s=str.split(",");
String key=s[0];//特征
double value=Double.parseDouble(s[1]);//特征值
map.put(key, value);
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Reader.class.getName()).log(Level.SEVERE, null, ex);
}
//return map;
return MapUtil.descend(map);
}
/**
* 获取分词后的文本集
* @param filePath
* @return
*/
public static Map<String,Set<String>> readDataSet(String filePath){
Map<String,Set<String>> map=new HashMap<String,Set<String>>();
File path=new File(filePath);
File[] files=path.listFiles();//类别
for(File file: files){
String label=file.getName();
File[] texts=file.listFiles();//文本
for(File text: texts){
map.put(label+File.separator+text.getName(),
toSet(text.getAbsolutePath()));
}
}
return map;
}
/**
* 获取文本集的TFIDF集
* @param filePath
* @return
*/
public static Map<String,Map<String,Double>> readTFIDF(String filePath){
Map<String,Map<String,Double>> map=new HashMap<String,Map<String,Double>>();
File path=new File(filePath);
File[] files=path.listFiles();//类别
for(File file: files){
String label=file.getName();
File[] texts=file.listFiles();//文本
for(File text: texts){
map.put(label+File.separator+text.getName(),
toDoubleMap(text.getAbsolutePath()));
}
}
return map;
}
}
Writer类
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Angela
*/
public class Writer {
/**
* 传入一篇文本分词后的特征表List,将List的内容一行一个特征地写入
* tarPath文件中(有重复)
* @param list 一篇文本分词后的结果:特征列表List
* @param tarPath 保存路径
*/
public static void saveList(List<String> list,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(String s: list){
bw.write(s);
bw.newLine();
}
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 传入一篇文本分词后的特征集Set,将Set的内容一行一个特征地
* 写入tarPath文件中(无重复的)
* @param set 特征集Set
* @param tarPath 保存路径
*/
public static void saveSet(Set<String> set,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(String s: set){
bw.write(s);
bw.newLine();
}
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 传入一篇文本分词后的特征集Map,将Map的内容一行一个地写入
* tarPath文件中(无重复的)
* @param map 特征集Map
* @param tarPath 保存路径,将特征-特征值Map内容保存在tarPath文件中
*/
public static <K, V extends Number> void saveMap(Map<K, V> map,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(Map.Entry<K,V> me: map.entrySet()){
bw.write(me.getKey()+","+me.getValue());
bw.newLine();
}
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 读取分词后的文本集,保存其TF结果,整个文本集的DF和IDF结果
* 同时计算总文本数,总词数,文本平均词数
* @param segmentPath 分词后的文本集路径
* @param savePath TF保存路径
* @param DFSavePath DF保存路径
* @param IDFSavePath IDF保存路径
*/
public static void saveTFDFIDF(String segmentPath,String savePath,
String DFSavePath,String IDFSavePath){
File path=new File(savePath);
if(!path.exists()) path.mkdir();
File file=new File(segmentPath);
File[] labels=file.listFiles();//类别
int textNum=0;//总文本数
long wordNum=0;//文本集的总词数
Map<String,Integer> DF=new HashMap<String,Integer>();
for(File label: labels){
String labelName=label.getName();
String tarLabel=savePath+File.separator+labelName;
File labelpath=new File(tarLabel);
if(!labelpath.exists()) labelpath.mkdir();
File[] texts=label.listFiles();//文本
textNum+=texts.length;
for(File text: texts){
String tarPath=tarLabel+File.separator+text.getName();
//每篇文本的TF集合
Map<String,Integer> TF=new HashMap<String,Integer>();
List<String> words=Reader.toList(text.getAbsolutePath());
for(String word: words){
//计算TF
if(TF.containsKey(word)) TF.put(word, TF.get(word)+1);
else TF.put(word, 1);
}
TF=MapUtil.descend(TF);
saveMap(TF,tarPath);
for(Map.Entry<String,Integer> me: TF.entrySet()){
String f=me.getKey();
wordNum+=me.getValue();
//计算DF
if(DF.containsKey(f)) DF.put(f, DF.get(f)+1);
else DF.put(f, 1);
}
}
}
DF=MapUtil.descend(DF);//对DF进行降序排序
saveMap(DF,DFSavePath);//保存DF结果
System.out.println("总文本数:"+textNum);
System.out.println("总词数:"+wordNum);
System.out.println("文本平均词数:"+wordNum*1.0/textNum);
Map<String,Double> IDF=new HashMap<String,Double>();
for(Map.Entry<String,Integer> me: DF.entrySet()){
IDF.put(me.getKey(), Math.log(textNum*1.0/me.getValue()));
}
saveMap(IDF,IDFSavePath);
}
/**
* 根据arff文件要求的格式,把数据写入tarPath这个arff文件
* 方便进行weka测试
* @param TFIDF TFIDF数据集
* @param featureSet 特征列表
* @param labelList 类别集
* @param tarPath 保存路径
*/
public static void saveAsArff(Map<String,Map<String,Double>> TFIDF,
Set<String> featureSet,String[] labelList,String tarPath){
//保存的文件名
String fileName=tarPath.substring(tarPath.lastIndexOf(File.separator)+1);
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
bw.write("@relation "+fileName);//relation需与文件名保存一致
bw.newLine();
for(String feature: featureSet){
//将class改成class1
if(feature.equals("class")){
feature="class1";
}
bw.write("@attribute "+feature+" real");//特征
bw.newLine();
}
int k=labelList.length;
bw.write("@attribute class {");//类别
for(int i=0;i<k-1;i++){
bw.write(labelList[i]+",");
}
bw.write(labelList[k-1]+"}");
bw.newLine();
bw.write("@data");//每一篇文本的对应特征的TFIDF权重
bw.newLine();
for(Map.Entry<String,Map<String,Double>> me: TFIDF.entrySet()){
String path=me.getKey();
String label=path.substring(0,path.lastIndexOf(File.separator));
Map<String,Double> weight=me.getValue();
for(String f: featureSet){
if(weight.containsKey(f)){
bw.write(weight.get(f)+",");
}else{
bw.write(0+",");
}
}
bw.write(label);
bw.newLine();
}
bw.flush();
bw.close();
}catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 根据csv文件要求的格式,把数据写入tarPath这个csv文件
* @param TFIDF TFIDF数据集
* @param featureSet 特征列表
* @param tarPath 保存路径
*/
public static void saveAsCSV(Map<String,Map<String,Double>> TFIDF,
Set<String> featureSet,String tarPath){
//将class改成class1
if(featureSet.contains("class")){
featureSet.remove("class");
featureSet.add("class1");
}
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(String feature: featureSet){
bw.write(feature+",");//特征
}
bw.write("class");//类别
bw.newLine();
for(Map.Entry<String,Map<String,Double>> me: TFIDF.entrySet()){
String path=me.getKey();
String label=path.substring(0,path.lastIndexOf(File.separator));
Map<String,Double> weight=me.getValue();
for(String f: featureSet){
if(weight.containsKey(f)){
bw.write(weight.get(f)+",");
}else{
bw.write(0+",");
}
}
bw.write(label);
bw.newLine();
}
bw.flush();
bw.close();
}catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 读取已经进行词干提取并去掉停用词的英文语料库,将文本保存在其相应类别下
* @param filePath 语料库txt路径
* @param tarDir 保存目录
*/
public static void saveFile(String filePath,String tarDir){
File path=new File(tarDir);
if(!path.exists()) path.mkdir();
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),"utf-8"));
String s;
int count=1;
while((s=br.readLine())!=null){
String[] content=s.split("[\\s]");
String tarLabel=tarDir+File.separator+content[0];
File label=new File(tarLabel);
if(!label.exists()) label.mkdir();
String tarPath=tarLabel+File.separator+count+".txt";
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
int len=content.length;
for(int i=1;i<len;i++){
bw.write(content[i]);
bw.newLine();
}
bw.flush();
bw.close();
count++;
}
br.close();
}catch (IOException ex) {
Logger.getLogger(Writer.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 主函数,保存分词后的DF、IDF结果
* @param args
*/
public static void main(String args[]){
String segmentPath="data\\r8-train-stemmed";
String TFPath="data\\r8trainTF";
String DFSavePath="data\\r8trainDF.txt";
String IDFSavePath="data\\r8trainIDF.txt";
saveTFDFIDF(segmentPath,TFPath,DFSavePath,IDFSavePath);
/*String filePath="data\\r8-test-stemmed.txt";
String tarDir="data\\r8-test-stemmed";
saveFile(filePath,tarDir);*/
}
}
MapUtil类
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
import java.util.Set;
/**
*
* @author Angela
*/
public class MapUtil {
/**对Map按键值升序排序**/
public static <K, V extends Comparable<? super V>>
Map<K, V> ascend( Map<K, V> map){
//将map.entrySet()转换成list
LinkedList<Map.Entry<K, V>> list =
new LinkedList<Map.Entry<K, V>>( map.entrySet() );
//然后通过比较器来实现排序
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
//升序排序
public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2 ){
return (o1.getValue()).compareTo( o2.getValue() );
}
} );
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put( entry.getKey(), entry.getValue() );
}
return result;
}
/**对Map按键值降序排序**/
public static <K, V extends Comparable<? super V>>
Map<K, V> descend( Map<K, V> map){
//将map.entrySet()转换成list
LinkedList<Map.Entry<K, V>> list =
new LinkedList<Map.Entry<K, V>>( map.entrySet() );
//然后通过比较器来实现排序
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
//降序排序
public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2 ){
return (o2.getValue()).compareTo( o1.getValue() );
}
} );
Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put( entry.getKey(), entry.getValue() );
}
return result;
}
/**
* 取键值大于最小阈值并且小于最大阈值的map子集
* @param map
* @param minThreshold 最小阈值
* @param maxThreshold 最大阈值
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
Map<K,V> map,V minThreshold,V maxThreshold){
Map<K,V> temp=new HashMap<K,V>();
for(Map.Entry<K, V> me: map.entrySet()){
V value=me.getValue();
if(value.compareTo(minThreshold)>=0
&&value.compareTo(maxThreshold)<=0){
map.put(me.getKey(), value);
}
}
return map;
}
/**
* 返回键值大于最小阈值的map子集
* @param map
* @param minThreshold 最小阈值
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
Map<K,V> map,V minThreshold){
Map<K,V> temp=new HashMap<K,V>();
for(Map.Entry<K, V> me: map.entrySet()){
V value=me.getValue();
if(value.compareTo(minThreshold)>=0){
map.put(me.getKey(), value);
}
}
return map;
}
/**
* 降序排序,选前num的特征集合
* @param map 特征-权重集
* @param num 个数
* @return 降序排序后前num的特征子集
*/
public static <K, V extends Comparable<? super V>> Map<K,V> getSubMap(
Map<K,V> map,int num){
Map<K,V> temp=new HashMap<K,V>();
map=descend(map);
Set<Map.Entry<K,V>> set = map.entrySet();
Iterator<Map.Entry<K,V>> it = set.iterator();
int count=0;
while(count<num&&it.hasNext()){
Map.Entry<K,V> me = it.next();
V value=me.getValue();
temp.put(me.getKey(), value);
count++;
}
return temp;
}
/**
* 降序排序,选前percent的特征集合
* @param map 特征-权重集
* @param percent 百分比
* @return 降序排序后前percent的特征子集
*/
public static <K, V extends Comparable<? super V>> Map<K,V> getPercentMap(
Map<K,V> map,double percent){
if(percent>1||percent<0){
System.out.println("请输入0~1之间的小数");
System.exit(0);
}
int num=(int)(map.size()*percent);
return getSubMap(map,num);
}
/**
* 打印map的前num个数据
* @param map 排序后的特征-权重集
* @param num 个数
*/
public static <K, V extends Comparable<? super V>>
void print(Map<K,V> map,int num){
Set<Map.Entry<K,V>> temp = map.entrySet();
Iterator<Map.Entry<K,V>> it = temp.iterator();
int count=0;
while(it.hasNext()&&count<num){
Map.Entry<K,V> me = it.next();
System.out.println(me.getKey()+" "+me.getValue());
count++;
}
}
}
以上是关于文本挖掘——准备文本读写及对Map操作的工具类的主要内容,如果未能解决你的问题,请参考以下文章
用python进行精细中文分句(基于正则表达式),HarvestText:文本挖掘和预处理工具
☀️ 学会编程入门必备 C# 最基础知识介绍—— C# 高级文件操作(文本文件的读写二进制文件的读写Windows 文件系统的操作)