文本挖掘——准备文本读写及对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操作的工具类的主要内容,如果未能解决你的问题,请参考以下文章

R从网页抓取到文本分析全教程:影评的获取与分析

R从网页抓取到文本分析全教程:影评的获取与分析

文本挖掘到底是什么鬼?

用python进行精细中文分句(基于正则表达式),HarvestText:文本挖掘和预处理工具

使用R做文本挖掘学习笔记:准备工作

☀️ 学会编程入门必备 C# 最基础知识介绍—— C# 高级文件操作(文本文件的读写二进制文件的读写Windows 文件系统的操作)