(4)文本挖掘(一)——准备文本读写及对Map操作的工具类

文本挖掘是一个对具有丰富语义的文本进行分析,从而理解其所包含的内容和意义的过程。文本挖掘包含分词、文本表示、文本特征选择、文本分类、文本聚类、文档自动摘要等方面的内容。文本挖掘的具体流程图可下图所示:
这里写图片描述
我的项目是以复旦大学中文语料库和路透社英文语料库为数据集的,都是有类别的两层目录文本集。
不管你要做什么,你首先都要先读取文本,为了方便后面的操作,我写了几个工具类。

一、文本信息类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); 
    }

}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值