文本挖掘是一个对具有丰富语义的文本进行分析,从而理解其所包含的内容和意义的过程。文本挖掘包含分词、文本表示、文本特征选择、文本分类、文本聚类、文档自动摘要等方面的内容。文本挖掘的具体流程图可下图所示:
我的项目是以复旦大学中文语料库和路透社英文语料库为数据集的,都是有类别的两层目录文本集。
不管你要做什么,你首先都要先读取文本,为了方便后面的操作,我写了几个工具类。
一、文本信息类Text
利用该类来存储文本的文件路径、类别ID、进行分类或聚类后所属的类别ID、文本词向量、文本长度,方便我们设置或获取需要用到的信息。
package util;
import java.util.Map;
/**
* 文本信息类,包含文本的文件路径,类别,词向量等
* @author Angela
*/
public class Text {
/**文本路径**/
private String path;
/**文本类别ID**/
private int originLabelID;
/**文本分类或聚类类别ID**/
private int judegeLabelID;
/**文本词-权重**/
private Map<String,Double> words;
/**文本长度**/
private double length;
/**
* @return the path
*/
public String getPath() {
return path;
}
/**
* @param path the path to set
*/
public void setPath(String path) {
this.path = path;
}
/**
* @return the words
*/
public Map<String,Double> getWords() {
return words;
}
/**
* @param words the words to set
*/
public void setWords(Map<String,Double> words) {
this.words = words;
}
/**
* @return the length
*/
public double getLength() {
return length;
}
/**
* @param length the length to set
*/
public void setLength(double length) {
this.length = length;
}
/**
* @return the originLabelID
*/
public int getOriginLabelID() {
return originLabelID;
}
/**
* @param originLabelID the originLabelID to set
*/
public void setOriginLabelID(int originLabelID) {
this.originLabelID = originLabelID;
}
/**
* @return the judegeLabelID
*/
public int getJudegeLabelID() {
return judegeLabelID;
}
/**
* @param judegeLabelID the judegeLabelID to set
*/
public void setJudegeLabelID(int judegeLabelID) {
this.judegeLabelID = judegeLabelID;
}
}
二、Map操作类MapUtil
因为在项目中有很多地方,需要对Map进行排序,打印,截取等操作,所以这里把这些操作单独出来,成为这个类。
package util;
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;
/**
* Map操作类,包括排序,打印,截取
* @author Angela
*/
public class MapUtil {
/**对Map按键值升序排序**/
public static <K, V extends Comparable<? super V>>
Map<K, V> asc( 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> desc( 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> between(
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){
temp.put(me.getKey(), value);
}
}
return temp;
}
/**
* 返回键值大于最小阈值的map子集
* @param map
* @param minThreshold 最小阈值
* @return
*/
public static <K, V extends Comparable<? super V>> Map<K,V> range(
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){
temp.put(me.getKey(), value);
}
}
return temp;
}
/**
* 选前num的特征集合
* @param map 特征-权重集
* @param num 个数
* @return 前num的特征子集
*/
public static <K, V extends Comparable<? super V>> Map<K,V> sub(
Map<K,V> map,int num){
Map<K,V> temp=new HashMap<K,V>();
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;
}
/**
* 打印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>> set = map.entrySet();
Iterator<Map.Entry<K,V>> it = set.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
* @param map 特征-权重集
*/
public static <K, V extends Comparable<? super V>> void print(Map<K,V> map){
for(Map.Entry<K, V> me: map.entrySet()){
System.out.println(me.getKey()+" "+me.getValue());
}
}
}
三、TXT文本读取类ReadTXT
我们需要读取原始文本内容,读取分词后的文本内容,读取TF集,读取TFIDF集,读取文本集信息。
package util;
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;
/**
* TXT读取类
* @author Angela
*/
public class ReadTXT {
/**
* 获取一篇文本的编码格式,注:所有文本的默认编码是“utf-8”
* @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(ReadTXT.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(ReadTXT.class.getName()).log(Level.SEVERE, null, ex);
}
return charset;
}
/**
* 读取一篇文本的全部内容
* @param filePath 还未分词的文本
* @return 无换行的文本内容,读取的内容用于后面的分词
*/
public static String read(String filePath){
StringBuilder sb=new StringBuilder();
String charset=getCharset(filePath);
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream(filePath),charset));
String s;
while((s=br.readLine())!=null){
sb.append(s);
}
br.close();
}catch (IOException ex) {
Logger.getLogger(ReadTXT.class.getName()).log(Level.SEVERE, null, ex);
}
return sb.toString();
}
/**
* 一行一个词地读取一篇文本,得到特征集
* @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(ReadTXT.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(ReadTXT.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(ReadTXT.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(ReadTXT.class.getName()).log(Level.SEVERE, null, ex);
}
return map;
}
/**
* 获取文本集的TFIDF集
* @param filePath
* @return
*/
public static List<Text> readText(String filePath){
List<Text> textList=new ArrayList<Text>();
File path=new File(filePath);
File[] files=path.listFiles();//类别
int labelID=0;
for(File file: files){
File[] texts=file.listFiles();//文本
for(File text: texts){
String textPath=text.getAbsolutePath();
Text txt=new Text();
txt.setPath(textPath);//文本路径
txt.setOriginLabelID(labelID);//文本类别
txt.setWords(ReadTXT.toDoubleMap(textPath));//文本词向量
textList.add(txt);
}
labelID++;
}
return textList;
}
}
四、TXT写入类WriteTXT
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package util;
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;
/**
* 数据写入TXT类
* @author Angela
*/
public class WriteTXT {
/**
* 将字符串写入文本
* @param str 分词字符串
* @param tarPath 保存路径
*/
public static void write(String str,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
bw.write(str);
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(WriteTXT.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 传入一篇文本分词后的特征表List,将List的内容一行一个特征地写入tarPath文件中(有重复)
* @param list 一篇文本分词后的结果:特征列表List
* @param tarPath 保存路径
*/
public static <K> void writeList(List<K> list,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(K s: list){
bw.write(s.toString());
bw.newLine();
}
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(WriteTXT.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 传入一篇文本分词后的特征集Set,将Set的内容一行一个特征地写入tarPath文件中(无重复的)
* @param set 特征集Set
* @param tarPath 保存路径
*/
public static <K> void writeSet(Set<K> set,String tarPath){
try{
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
new FileOutputStream(tarPath)));
for(K s: set){
bw.write(s.toString());
bw.newLine();
}
bw.flush();
bw.close();
} catch (IOException ex) {
Logger.getLogger(WriteTXT.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 传入一篇文本分词后的特征集Map,将Map的内容一行一个地写入tarPath文件中(无重复的)
* @param map 特征集Map
* @param tarPath 保存路径,将特征-特征值Map内容保存在tarPath文件中
*/
public static <K, V> void writeMap(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(WriteTXT.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
* 得到所有数据集中所有不重复特征的文档频,一行一行地将特征-DF结果保存到tarPath中
* @param filePath 数据集路径,包含有所有文本的目录路径
* @param tarPath DF结果的保存路径
* @return 数据集的文本总数
*/
public static int saveDF(String filePath,String tarPath){
int sum=0;
Map<String,Integer> df=new HashMap<String,Integer>();
File dataSet=new File(filePath);
File[] classes=dataSet.listFiles();
for(File c: classes){//类别
File[] files=c.listFiles();
sum+=files.length;
for(File file: files){//文本
Map<String,Integer> tf=ReadTXT.toIntMap(file.getAbsolutePath());
for(Map.Entry<String, Integer> me: tf.entrySet()){
String f=me.getKey();
if(df.containsKey(f)){
df.put(f, df.get(f)+1);
}else{
df.put(f, 1);
}
}
}
}
//保存特征及其DF值
WriteTXT.writeMap(MapUtil.desc(df),tarPath);
return sum;
}
/**
* 读取DF结果文件,计算每个特征的IDF值,保存特征-IDF值到tarPath文件中
* @param filePath DF结果的文件路径
* @param tarPath IDF结果的保存路径
* @param n 总的文本数
*/
public static void saveIDF(String filePath,String tarPath,int n){
Map<String,Integer> df=ReadTXT.toIntMap(filePath);
Map<String,Double> idf=new HashMap<String,Double>();
for(Map.Entry<String, Integer> me: df.entrySet()){
idf.put(me.getKey(), Math.log(n*1.0/me.getValue()));
}
//保存特征及其IDF值
WriteTXT.writeMap(MapUtil.desc(idf),tarPath);
}
/**
* 主函数,保存分词后的DF、IDF结果
* @param args
*/
public static void main(String args[]){
//第一个参数为TF集路径,第二个参数为DF的保存路径,n为文本集文本总数
int n=saveDF("data\\trainTF","data\\trainDF.txt");
//System.out.println(n);
//第一个参数为DF文本,第二个参数为IDF的保存路径,n为文本集文本总数
saveIDF("data\\trainDF.txt","data\\trainIDF.txt",n);
}
}
文本挖掘(一)——准备文本读写及对Map操作的工具类&spm=1001.2101.3001.5002&articleId=50998503&d=1&t=3&u=b3d99aa75b2b413996b6b97cda28ce38)
6282

被折叠的 条评论
为什么被折叠?



