【项目总结】自然语言处理在现实生活中运用

【项目总结】自然语言处理在现实生活中运用

作者 白宁超

2015年11月9日23:27:51

摘要:自然语言处理或者是文本挖掘以及数据挖掘,近来一直是研究的热点。很多人相想数据挖掘,或者自然语言处理,就有一种莫名的距离感。其实,走进去你会发现它的美,它在现实生活中解决难题的应用之美,跟它相结合的数学之美,还有它与统计学的自然融合。语言只是一种实现工具,真正难度的是模型的理解和对模型的构建。本文结合自然语言处理的基本方法,完成对2002--2010年17套GET真题的核心单词抽取。麻雀虽小,也算五脏俱全,包含整个数据处理过程,比较简单。中等开发的程序员都可以实现,其中包括数据清洗,停用词处理,分词,词频统计,排序等常用方法。(本文原创,分享供于学习,转载标明出处:【项目总结】自然语言处理在现实生活中运用

1 需求分析与描述:

首先谈下这款软件的来源和用途吧,本科至今没有挂科记录,很不幸第一次《英语学位英语考试<GET>》挂科了。于是,笔者开始疯狂的做题和背单词,对于GET真题很多单词不认识,抱着有道词典,逐字翻译耗时耗力。再说历来10余年试题考试单词范围是一定的,把出现频率高的单词,所谓核心单词掌握了不就事倍功半了?问题来了,不像四六级词汇或者考研词汇市场有专门卖的。当时就开始设想,如果我收集10余年真题,然后去除所有非单词结构(真题算是结构化数据,有一定规则,比较容易处理。此过程其实就是数据清洗过程)最后把所有单词集中汇总,再去除如:a/an/of/on/frist等停用词(中文文本处理也需要对停用词处理,诸如:的,地,是等)。处理好的单词进行去重和词频统计,最后再利用网络工具对英语翻译。然后根据词频排序。 基于以上思路,结合笔者前不久对数据挖掘中分类实现的经验和暑假学习的统计学知识最终上周末(10.31—11.1)花了2天时间搞定,这些自然语言处理的基础方法在分类,聚类等数据挖掘和本体领域构建中都有使用。最后我将其核心方法进行梳理,下面咱们具体展开。

2 自然语言处理结果预览:

前面提到本算法是对自然语言中常规英文试卷的处理,那么开始收集原始数据吧。

1 历年(2002—2010年)GET考试真题,文档格式不一,包括txt/pdf/word等如下图:

2 对所有格式不一的文档进行统计处理成txt文档,格式化(去除汉字/标点/空格等非英文单词)和去除停用词(去除891个停用词)处理后结果如下:【17套试卷原始单词(含重复)82158个,数据清洗处理后32011个】

3 对清洗后的单词进行去重和词频统计:【去重后7895个单词尺寸】

4 显示这10余年考试的词汇量还是很大的,加上停用词,考查词汇量在9000左右,那么常考的应该没那么多。试想下17套试卷中,去除停用词后出现频率大于5的和小于25次【1674个单词】的数据应该是合理的,那么我就指定阈值提取。

5 最后一步,中英文翻译(目前通过google工具快速查询,然后合并)。最终效果如下:(处理的最终txt结果和自己word整理的结果)

3 算法思想和解决方案:

算法思想:

1历年(2002—2010年)GET考试真题,文档格式不一。网上收集

2 对所有格式不一的文档进行统计处理成txt文档,格式化(去除汉字/标点/空格等非英文单词)和去除停用词(去除891个停用词)处理。

利用正则表达式去除非英文单词的字符,通过规则的空格分离,停用词表网上一大堆,通过将其与单词比对,不在停用词表的追加存储

3 对清洗后的单词进行去重和词频统计

通过Map统计词频,实体存储:单词-词频。(数组也可以,只是面对特别大的数据,数组存在越界问题)。排序:根据词频或者字母

4 提取核心词汇,大于5的和小于25次的数据,可以自己制定阈值。

遍历list<实体>列表时候,通过获取实体的词频属性控制选取词汇表尺寸。

5 最后一步,中英文翻译。

将批量单词通过google翻译,可以获取常用意思,对于发音,词义,词性等没有处理。这里也是可以改进地方,其实也很简单,后面详解,最后自己讲结果在word里面排版。

4 Java语言对需求实现详解:

1 文件保存路径定义

    public static final  String stopWordTable ="./getFile/partStopWord.txt";       //停用词词表文件地址
    public static final  String    srcfilepath="./srcFile";                           //待处理的源文件地址
    public static final  String    stopfilepath="./getFile/temp.txt";                 //待处理的源文件地址
    public static final  String    tarfilepath="./getFile/getcoreword.txt";           //源文件和目标文件地址

2 对原始文件数据清理以及停用词处理

    //对文本文件预处理
    public static void dataCleanFile(String srcfilepath,String stopfilepath){
        String reg = "[^a-zA-Z]";                          //去除噪音,获取英文单词开始的内容
        String sb=CommontMethod.readStrFiles(srcfilepath, " ").toLowerCase().replaceAll(reg, " ").replaceAll(" +"," ").trim();   //接收清洗后的数据
        String[] srcWordsList =sb.split(" ");              //按照规则,将单词放在数组里面
        System.out.println("2002至2010年GET試卷原始单词數:【"+srcWordsList.length+"】個。");
        System.out.println("正在對如:on,of,a等停用詞處理,大約需要30秒,請等候...");

        StringBuffer stopWordSb=new StringBuffer();         //存放去除停用词后的
        for(int i=0;i<srcWordsList.length;i++){
            if(IsStopWord(srcWordsList[i])==false)
                stopWordSb.append(srcWordsList[i].toString().trim()+"\n");  //不是停用词,则追加字符串
        }
        String[] stopWordsList =stopWordSb.toString().split("\n");
        System.out.println("對單詞集停用詞處理結束,核心單詞共計:【"+stopWordsList.length+"】個。已經保存至./getFile/temp.txt下,請查閱!");
        CommontMethod.writeStrFile(stopWordSb.toString(), stopfilepath, "\n"); //将预处理后并标注的数据,指定位置保存
    } 

3 处理后的数据进行核心单词汇总和词频统计

   //统计词频
      public static void countWordNums(String stopfilepath,String tarfilepath){
        //统计GET试卷核心单词以及词频
          Map<String,Integer> shlMap=new HashMap<String,Integer>(); //去重計數

          //整個詞彙表
          StringBuffer WordsTable=new StringBuffer();
          List<Word> wordsList = new ArrayList<Word>();             //統計詞頻排序

          StringBuffer tarWordSb=new StringBuffer();                //存放去除停用词后的,詞頻指定的單詞;
          List<Word> wordList = new ArrayList<Word>();              //統計詞頻排序
          int sum=0;//計算非重複單詞個數。
          int setnum=10; //設定保存詞頻條件
          shlMap=CommontMethod.countWords(shlMap, stopfilepath.trim(), " ");
          int count=0;
          for (Map.Entry<String, Integer> entry : shlMap.entrySet()) {
              if(entry.getValue()>0){
                  wordsList.add(new Word(entry.getKey(), entry.getValue()));//統計頻率詞彙表
                  count++;
                  if(entry.getValue()>setnum){
                        wordList.add(new Word(entry.getKey(), entry.getValue()));//統計指定頻率詞彙表
                        sum++;
                    }
            }
          }

          //詞彙表大小
          StringBuffer EglChindSb=new StringBuffer();   //存放中英对照词表;
          String[] freWords= CommontMethod.wordsFre(wordsList,WordsTable).split("\n"); //根據詞頻結果排序,並進行保存
          String[] Tranlation=CommontMethod.readStrFile("./getFile/Translation.txt", "\n").split("\n");//中文翻译
          for(int i=0;i<Tranlation.length&&i<freWords.length;i++){
              EglChindSb.append(freWords[i]+"\t"+Tranlation[i]+"\n");
          }
          CommontMethod.writeStrFile(EglChindSb.toString(),"./getFile/worstable.txt","\n");
          System.out.println("整個詞彙表為:【"+count+"】個。已經保存至./getFile/wordstable.txt下,請查閱!");

          //根據詞頻結果排序,並進行保存
          String fWords= CommontMethod.wordsFre(wordList,tarWordSb);
          CommontMethod.writeStrFile(fWords.toString(), tarfilepath,"\n");
          System.out.println("篩選出現"+setnum+"次以上的單詞:【"+sum+"】個。已經保存至./getFile/getcoreword.txt下,請查閱!");
          //根据字母有序打印
          //CommontMethod.init(shlMap);
      } 

4 运行结果分析

1 程序处理核心代码,其中第一个类存放公共方法(小面小结有),第二个类主函数,如上代码。第三个方法实体类统计词频,这样设计,应对大数据,数据小数组即可。

2 处理后得到的结果,核心单词,数据清洗结果,停用词,翻译,最终结果等。

3 原始试卷共计82158个单词

4 数据清洗和停用词处理后剩下32011个单词

5 去重后总共7895个单词的考察范围

6 提取10次以上核心单词623个,即便5次以上不过1500个单词

7 性能方面运行25秒是稳定的,这个主要是对7895个单词排序问题耗时比较多

5 自然语言常用方法小结(JAVA实现,C#类似):

1 实体的基本使用

/**
 *
 */
package com.baiboy.bnc;

/**
 * @author 白宁超
 *
 */
public class Word {
    private String words;
    private int frequence;

    public Word(String words, int frequence) {
        this.words = words;
        this.frequence = frequence;
    }
    public String getWords() {
        return words;
    }
    public void setWords(String words) {
        this.words = words;
    }
    public int getFrequence() {
        return frequence;
    }
    public void setFrequence(int frequence) {
        this.frequence = frequence;
    }
    public String print(){
        return "["+this.frequence+"] "+this.words;
    }
}

2 批量读取目录下的文件

    /**
     * 对单个文件的读取,并将整个以字符串形式返回
     * @param srcfilepath 读取文件的地址
     * @param separ   逐行读取的分隔符号,如:" ", "\t", ","等
     * @return  sb 字符串
     */
    public static String readStrFiles(String fileDirPath,String separ){
        StringBuffer sb=new StringBuffer();
        BufferedReader srcFileBr=null;
        File dir=new File(fileDirPath);
        if(dir.exists()&&dir.isDirectory()){
            File[] files=dir.listFiles();  //获取所有文件
            try{
                for(File file:files){//遍历训练集文件
                    srcFileBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(file.toString())),"UTF-8"));//读取原文件
                    String line = null;
                    while((line=srcFileBr.readLine())!=null){
                        if(line.length()>0)
                        sb.append(line.trim()+separ);
                    }
                }
                srcFileBr.close();
            }
            catch(Exception ex){
                System.out.println(ex.getMessage());
            }
        }
        else
            System.out.println("你选择的不是目录文件");
        return sb.toString().trim();
    }

3 读取单个文件

    /**
     * 对单个文件的读取,并将整个以字符串形式返回
     * @param srcfilepath 读取文件的地址
     * @param separ   逐行读取的分隔符号,如:" ", "\t", ","等
     * @return  sb 字符串
     */
    public static String readStrFile(String srcfilepath,String separ){
        StringBuffer sb=new StringBuffer();
        try{
            BufferedReader srcFileBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(srcfilepath)),"UTF-8"));//读取原文件
            String line = null;
            while((line=srcFileBr.readLine())!=null){
                if(line.length()>0)
                sb.append(line.trim()+separ);
            }
            srcFileBr.close();
        }
        catch(Exception ex){
            System.out.println(ex.getMessage());
        }
        return sb.toString().trim();
    }

4 文件预处理,并以字符串结果返回

    /**
     * 对文件的读取,并将整个以字符串形式返回
     * @param shlMap 传入的map集合
     * @param tarfilepath 读取文件的地址
     * @param separ   逐行读取的分隔符号,如:" ", "\t", ","等
     * @return  sb 字符串
     */
    public static Map<String,Integer> countWords(Map<String,Integer> tarMap,String tarfilepath,String separ){
        StringBuffer sb=new StringBuffer();
          try{
              //读取原文件
              BufferedReader srcFileBr = new BufferedReader(new InputStreamReader(new FileInputStream(new File(tarfilepath)),"UTF-8"));
               //对读入的文本进行预处理
              String paragraph = null;
              while((paragraph=srcFileBr.readLine())!=null&&paragraph.length()>0){
                  String[] words = paragraph.split(separ);
                //遍历所有单词
                for(String word:words){
                    if(tarMap.containsKey(word))
                        tarMap.put(word, tarMap.get(word)+1);
                    else
                        tarMap.put(word, 1);
                }
              }
              srcFileBr.close();
          }
          catch(Exception ex){
              System.out.println(ex.getMessage());
          }
        return tarMap;
    }

5 指定保存文件

    /**
     * 将字符串写到指定文件中
     * @param str          待写入的字符串
     * @param tarfilepath  目标文件路径
     * @param separ        逐行读取的分隔符号,如:" ", "\t", ","等
     */
     public static void writeStrFile(String str,String tarfilepath,String separ){
        try{
            OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(tarfilepath)), "UTF-8");// 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
            writer.append(str+separ);// 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
            writer.close();//关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
        }
        catch(Exception ex){
            System.out.println(ex.getMessage());
        }
    }

6 词频排序(中英文通用)

     /**
      * 根據單詞詞頻排序
      * @param wordList   存放單詞和詞頻
      * @param tarWordSb  存放排序后的結果
      * @return
      */
     public static String wordsFre(List<Word> wordList,StringBuffer tarWordSb){
         Collections.sort(wordList, new Comparator<Word>() {
                @Override
                public int compare(Word word1, Word word2) {
                    if(word1.getFrequence()>word2.getFrequence())
                        return -1;
                    else if(word1.getFrequence()<word2.getFrequence())
                        return 1;
                    else
                        return 0;
                }
              });
              for (Word word : wordList) {
                  tarWordSb.append(word.print()).append("\n");
            }
              return tarWordSb.toString();
     }

7 根据字符有序排列

     /**
      * 根据字符有序排列
      * @param shlMap
      */
     public static void init(Map<String,Integer> shlMap){
          List<Map.Entry<String, Integer>> mHashMapEntryList=new ArrayList<Map.Entry<String,Integer>>(shlMap.entrySet());
        System.out.println("-----> 排序前的顺序");
        for (int i = 0; i < mHashMapEntryList.size(); i++) {
           System.out.println(mHashMapEntryList.get(i));
        }
        Collections.sort(mHashMapEntryList, new Comparator<Map.Entry<String,Integer>>() {
          @Override
          public int compare(Map.Entry<String,Integer> firstMapEntry, Map.Entry<String,Integer> secondMapEntry) {
            return firstMapEntry.getKey().compareTo(secondMapEntry.getKey());
          }
        });

        System.out.println("-----> 排序后的顺序");
        for (int i = 0; i < mHashMapEntryList.size(); i++) {
            System.out.println(mHashMapEntryList.get(i));
         }
      }

8 停用词处理如何判断?

    // 停用词处理器
    public static boolean IsStopWord(String word)
    {
         String sb2=CommontMethod.readStrFile(stopWordTable, "\n");
         String[] stopWordsList =sb2.split("\n");
         for(int i=0;i<stopWordsList.length;i++){
             if(word.equalsIgnoreCase(stopWordsList[i]))
                 return true;
         }
         return false;
     }

6 扩展改进与移植展望:

本项目由于实际需求,对其做了初步完善。基本自然语言处理方法和流程都包含了,诸如词频统计,停用词处理,单词统计,还有文件的基本操作,再结合数学模型或者统计模型可以做复杂的自然语言或者文本处理。比如朴素贝叶斯分类,首先弄明白贝叶斯分类模型,其实就是对贝叶斯公式的理解和推导。之后结合本项目词频统计文件操作,数据清洗,中文分词,停用词处理就做出来了。再如,本体构建,也是需要对数据清洗,词频统计,结果发射概率和转移概率,文本标注等实现,后面我会陆续发布相关文章。

至于本算法改进,可以对翻译部分改进,一种基于词库的检索,包括词性,词义,词标等匹配。另外一种是对英文词组的分词处理,利用英文分词解决。移植方面,可以利用C#语言在窗体上开发,最后打包应用软件。实际上我本科至于对窗体一直很热衷。也可以做成领域下核心词汇分析提取。诸如历年考研真题,高考真题,中考真题,软件开发某一方向词汇,建筑学词汇等多重应用。做成多个APP,移植到移动软件方面。

时间: 2024-08-10 15:13:33

【项目总结】自然语言处理在现实生活中运用的相关文章

我在现实生活中遇到了电视剧中的神奇人物

一个人读过书和没读书的有区别,读书多少质量也有区别.对面坐了一个三本的男孩子,心里只有钱,眼里嘴里不是吃就是喝,再不然就是睡,喜欢和一堆女生窝在一起叽叽喳喳炮轰一个他不喜欢的人.用公司的电脑会狠命的砸键盘,还扬言又不是我的电脑.一起团建出游时,会把坚果皮在酒店里扔的到处都是,还说会有服务生来打扫.这些都是从他和其他女生的对话中看到的,遇到这种情况,我只能笑而不语.我不太理解pahf招聘条件明明写的是本科以上,为何会招这样神奇的人进来,更让我惊讶的是周围人的学历普遍都不是很高.这和刚进这家企业,看

将github上的项目源码导入到eclipse中

1.注册github帐号 在github上注册一个自己的帐号. 2.安装git插件egit 在eclipse中安装git插件egit,安装方法可以参考这篇文章: http://www.cnblogs.com/machanghai/p/4945991.html 3.创建github练级库 首先,使用Eclipse自带的工具来生成github需要的密钥,window->preference,然后具体操作如下图: 关于申请密钥参考这篇文章:http://blog.csdn.net/chinaonlyq

程序开发--在现实生活中寻找可利用的资源

经历了很多次软件开发之后,每个程序员是否都会体验到程序与我们的生活.工作密切相关.每次的程序要么应用到生活的某个娱乐.助理以及工作的各种场合,在进行开发之前,总会围绕着用它干什么,能给我带来什么效益开端. 那么,生命即将开始. 前期的规划是整个生命的重中之重,没有一个完美的应用采集,分析,架构,程序生命期会严重受到影响.甚至开始没用之前就已经奄奄一息了,围绕着实用性,效益性,安全性展开合理的生命旅程吧 ! 于是,生命已经开始了 . 设计完成之后,理论性分析完毕了,完全进入到一个问题性阶段.这个阶

人要怎样活在现实生活中

人要怎样活在现实生活中 2014-04-18 12:58薇儿7kbW搿 | 分类:夫妻 | 浏览4次人要怎样活在现实生活中才不会累我有更好的答案 分享到: 2014-04-18 19:58提问者采纳 人生不可能没有累这个字,只是你不会从累中去享受,不是要怎样活在现实中,是你已经活在现实中了,这是无法改变的事实.所以你要勇敢去面对,而不是埋怨现实的残酷. 人要怎样活在现实生活中,布布扣,bubuko.com

[转]使用Maven添加依赖项时(Add Dependency)时,没有提示项目可用,并且在Console中,输出: Unable to update index for central|http://repo1.maven.org/maven2 。

使用Maven添加依赖项时(Add Dependency)时,没有提示项目可用,并且在Console中,输出: Unable to update index for central|http://repo1.maven.org/maven2 . 解决方式如下: 1.通过其它方式下载如下两个文件: http://repo1.maven.org/maven2/.index/nexus-maven-repository-index.properties http://repo1.maven.org/m

Atitit.现实生活中最好使用的排序方法-----ati排序法总结

1. 现在的问题 1 2. 排序的类别::插入排序//交换排序//选择排序(每次最小/大排在相应的位置  )//归并排序//基数排序 1 3. 选择排序法  (垃圾...不好使用) 2 4. 堆排序-(雅十垃圾...不好用) 2 5. 希尔排序法 (雅十垃圾...不好用) 3 6. 冒泡排序法 (雅十垃圾...不好用) 3 7. 快速排序法 (雅十垃圾...不好用) 3 8. 归并排序法 (雅十垃圾...不好用) 3 9. 插入排序法 ( 勉强能使用,要是加个2分寻找走ok兰..) 3 10. 

计算机里比特位、字节位的左右顺序和我们现实生活中的数字写法的左右顺序的对比

此文仅适用我自己. 首先明确一个概念:bit是比特的意思:byte是字节的意思.bit没有比特位的意思,比特位的全称应该是bit position:而字节位则是byte position. 叫法:最高位比特.最高位字节.还有就是下标(index)和位(position)是两个概念(位的说法是高低,下标/下标值的说法是大小:位左边是最高,下标右边是最大). 正文: 现实生活中我们写数字一般都是从左到右是最高位到最低位:即210这个数字,2是最高位(百位),0是最低位(个位). 对于数组或List而

【弘瑞3D打印机厂家】桌面级3D打印机在现实生活中实用性

自3D打印机在中国打开市场后,备受政府的重视,在政府的大力支持及李克强总理关注3D打印技术是制造业的一大突破点后,国内3D打印技术热度的逐渐升温,3D打印机事业得到了空前发展,生产厂家数量日益增多,地域广泛,主要分布在广东.北京.江苏.河南等地,呈现良好的发展态势.国产3D打印机以开源技术为主,主要技术为FDM,目前还处于初级阶段,不乏有脱颖而出的桌面级3D打印机企业,影响力扩展到海外市场. 3D打印只要一台电脑和打印机,几个小时的时间,就能将零部件从设计图变成实实在在的产品,而且可以随时修改和

作为项目管理者如何避免项目的延期与执行过程中的加班问题

作为一个项目管理者,最担心的事情就是项目的不能够如期完成:作为一个项目实施者,最担心的是无休无止的加班.项目的不能够如期完成直接导致的是用户或者甲方对公司信誉.能力等各个方面的怀疑与否定,项目实施过程中的无休无止的加班导致的则是员工上班积极性.员工思维等哥哥方面的问题.可以说,这两个方面直接决定着该项目的成败,那么,作为一个项目管理者,应该如何去避免该类的事情发生或者尽可能的减少该事情的发生呢?下面我们分析一下. 1.计划不清 作为一个项目的管理者,项目执行时最怕的就是对该项目没有一个较好的规划