新闻中完整性对象的识别

2018-08-27  本文已影响73人  艾剪疏

1 完整性对象概念
2 抽取算法思想
3 代码实现

1 完整性词概念

完整性词是在特定学科领域用来表示概念的称谓的集合。完整性词可以是词,也可以是词组,用来正确标记生产技术、科学、艺术、社会生活等各个专门领域中的事物、现象、特性、关系和过程。

例如,如下语料:

如“ Android/x  系统 /n  平台 /n _/x 7/v  英寸 /q Android/x  系统 /n  触控 /n MID/x  蓝 /a  魔 /ng W9/x  评测 /vn _/x  中
关村 /ns  在线 /vn Android/x  系统 /n  平台 /n W9/x  采用 /v660 MHz ARM9/x  内核 /n  处理器 /n ……”

可以抽取出:“ Android/x 系统 /n ”、“系统 /n 平台 /n ”、“ Android/x 系统 /n 平台 /n ”等。 而2 次出现的“ Android/x 系统 /n ”后面的第 1 个词均为“平台”,所以,此评价对象不是右完整; 2 次出现的“系统 /n 平台 /n ”前面的词均为“ Android ”,所以,此评价对象不是左完整; 2 次出现的“ Android/x 系统 /n 平台 /n ”左右词均不相同,所以,此对象具有完整性是完整性词。

2 抽取算法思想

2.1 候选对象抽取

下面是当时总结的油气行业的词性规则(前20组)

image.png

2.2 非完整性对象的过滤

2.3 非稳定性完整对象的过滤

稳定性对象是指:组成完整性对象各个词之间的紧密耦合程度。举例说明。

如“刻录 /n 盘 /qv ”候选对象是由“刻录”和“盘”2 个词组成的,假设在文章中:“刻录 /n 盘 /qv ”一起在文本中出现了 2 次,“刻录”这个词单独出现 2 次( 它始终和“盘”在一起出现 ),“盘”出现了 3 次 ( 它除了与“刻录”在一起出现,还在其他位置出现 ) 。则可以通过对上面参数的计算,统计出“刻录”、“盘”这两个词在是一起出现可能性比分开出现的可能性大。即“刻录 /n 盘 /qv ”的稳定性。

公式如下:

image.png

假设Object(完整性词) = Item1(基词) + Item2 + Item3 + .... + ItemN。

根据s(Object)的结果,设定阈值X来确定Object是不是完整性对象。

2.4 置信度计算

对经过上面两次完整性和稳定性的过滤之后,最后计算剩下候选对象计算置信度。置信度越大,则认为是完整性对象的可能性越大。置信度通过两个方法评价。

(1)特征 1:与某类短语规则同现

利用上面抽取词性规则的方法,抽取出修饰网站性对象的词语组合。例如:“刻录 /n 盘 /qv ”,前面可能会出现:好/d 精致的/a,很/d有用的/a,类似这样的修饰词,对这些修饰词进行统计、排序选取出靠前的。使用修饰词词性规则与出现完整性词的句子进行匹配,看是否同现(co = 1(同现) OR co = 0)。

(2)特征 2: 完整性对象出现频率

假设给定 N 篇文档,共有d(1≤d≤N)篇文档包含评价对象O,第k(1≤k≤d)篇文档中共有S个词,O在第k篇文档中出现 n (1≤n≤S) 次,则词频tf(O)和df(O)的计算方式和之前说的一样。
然后,将其套用至下面的公式中,计算出f(O)。


image.png

f(Object)表示结果值,此值越大, Object 是评价对象的可能性越大。

(3)置信度计算及排序(重点)

综合上述的 2 个特征值,对两个特征值进行整合排序,计算出最终的结果。

f(Object)的值越大时,候选评价对象 Object 是正确结果的可能性大,此时,有如下情况: (1) co为 1,f(Object)很小; (2) co为 0,f(Object)很大。
为了判断这 2 种情况的置信度,将 2 个特征的值,用二维坐标系表示,特征值的坐标表示如图(方法值得学习):


image.png

将Object中co为 0 的f(Object)值标注在y轴上,并令其最大值为 n , co 为 1 的f(Object)值标注在直线L上,并令其最小值为 p 。通过实验取得 L 上的点 m ,使得 m 和 n 的置信度相同,由 m 和 n 做直线 L 1 ,过点 p 做 L 1 的平行线 L 2 交 y 轴与点 q 。

令任意 2 点 (0, y 1)( q ≤ y 1 ≤ n ) , (1, y 2)( p ≤ y 2 ≤ m ) ,过y 1 做 L 1 的平行线交 L 于点 z ,若 z > y 2 ,则 y 1 > y 2 ;若 z ≤ y 2 ,则 y 1 ≤ y 2 。

大于 m 的 Object 置信度最高,并按f(Object)值排序,q 、 n 、 p 、 m 之间的 Object 置信度次之,并按照 y 1 和 y 2的比较方法排序,小于 q 的 Object 置信度最低。这样得到最终的置信度排序,按置信度前 80 %作为结果提交。

2.5 评价对象的扩充(学习思想)

对于置信度不高的后 20 %且标注为“ n ”或“ x ”的评价对象,采用扩充规则来提高准确率和召回率。在对评价对象过滤和置信度排序后使用扩充规则,而不是在抽取候选评价对象时使用,是为了减缓整个评价对象识别的复杂度和运算量。

3 代码实现

全局变量

private static Map<String,Integer> keyMap = null;//某词出现次数
private static Map<String,Double> wordCount_txts = new HashMap<>();//某词在所有文章中出现的次数
private static Map<String,Double> wordCount_txt = new HashMap<>();//某词在某篇文章中出现的次数
private static List<String> contained = new ArrayList<>();//去除所有文本中的重复词语
private static Map<String,Double> noave_Object = new HashMap<>();//每个词未平均的object值
private static double ave_confidence_0 = 0,ave_confidence_1 = 0;//置信区间的平均置信点

候选对象抽取

/**
     * 按照规则,抽取单个文件的候选集
     * @param rulesPath 规则的路径
     * @param sourcePath 分词之后的文件路径
     * @param outputPath 抽取之后的保存路径
     * @return
     */
    public static void singleTextWordsSet(String rulesPath,String sourcePath,String outputPath){
        try {
            String result = "";
            List<String> rulesList = getRules(rulesPath);
            String sourceString = StringUtils.getContent(sourcePath);
            for(String rule : rulesList){
                result += StringUtils.getContentUseRegex(rule, sourceString, "");
            }
            StringUtils.string2File(result, outputPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取评价对象抽取的规则
     * @param inputPath 规则的完整路径
     * @return
     * xx/n
     */
    public static List<String> getRules(String inputPath){
        List<String> result = new ArrayList<String>();
        File file = new File(inputPath); 
        FileReader fr = null;
        BufferedReader br = null;
        String regex = "[\u4e00-\u9fa5a-zA-Z0-9]*";
        try {
            fr = new FileReader(file);
            br = new BufferedReader(fr);
            String temp = "";
            while((temp=br.readLine()) != null){
                String[] temps = temp.split(ConstantParams.SINGLE_BLANK);
                String str = "";
                for(String rule : temps){
                    str += (regex+"/"+rule+"(.?)"+ConstantParams.SINGLE_BLANK);
                }
                result.add(str);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            try {
                if(br != null){
                    br.close();
                }
                if(fr != null){
                    fr.close();
                }
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        return result;
    }

/**
     * @Description: 词典处理:去除词性标注,抽取关键词之和
     * @return:
     * @date: 2017-10-15  
     */
    public static void genInteDic(String sourcePath,String outputPath){
        BufferedReader br = null;
        String result = "";
        String line = "";
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(sourcePath)),FileUtils.getFileEncode(sourcePath)));
            while((line = br.readLine())!=null){
                String []bStr = line.split(ConstantParams.SINGLE_BLANK);
                String s = "";
                for(String w : bStr){
                    if(w.contains("/")){
                        s+= w.substring(0, w.indexOf("/"));
                    }
                }
                result+=s+ConstantParams.CHENG_LINE;
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }       
        StringUtils.string2File(result, outputPath);
    }

非完整性对象的过滤

/**
     * 过滤特殊词(单子动词,特殊符号... ...)
     * @param intputPath
     * @param outputPath
     */
    public static void filterWords(String inputPath,String outputPath){
        try {
            String result = "";
            File file = new File(inputPath);
            InputStream is = new FileInputStream(file);
            InputStreamReader isr = new InputStreamReader(is,FileUtils.getFileEncode(inputPath));
            BufferedReader br = new BufferedReader(isr);
            String temp = "";
            while((temp=br.readLine()) != null){
                String[] temps = temp.split(ConstantParams.SINGLE_BLANK);
                if(temps.length > 1){
                    result += temp+ConstantParams.CHENG_LINE;
                }else{
                    String[] wordsTemps = temps[0].split("/");
                    if(wordsTemps[0].length() != 1){
                        result += temp+ConstantParams.CHENG_LINE;
                    }
                }
            }
            br.close();
            StringUtils.string2File(result, outputPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

/**
     * 去除重复的候选词
     * @param inputPath
     * @param outputPath
     */
    public static void delRepWords(String inputPath,String outputPath){
        try {
            List<String> list = new ArrayList<String>();
            String result = "";
            BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(new File(inputPath)),FileUtils.getFileEncode(inputPath)));
            String temp = "";
            while((temp=br.readLine()) != null){
                if(!list.contains(temp)){
                    list.add(temp);
                    result += temp+ConstantParams.CHENG_LINE;
                }
            }
            br.close();
            StringUtils.string2File(result,outputPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

左右完整性词的计算

/**
     * 非完整性过滤
     * @param inputPath : 已去重完毕的词;   sourcePath:splitWords中的词;
     * @param outputPath
     * @return 满足条件的完整性词
     */
    public static List<String> filterInteWords(String inputPath,String sourcePath,String outputPath){
        List<String> inteWords = new ArrayList<String>();
        try {
            String rawResult = "";
            List<String> wordsList = StringUtils.getContentFromPath(inputPath);
            for(String word : wordsList){                   
                //读分词之后的源文件
                String sourceWord = StringUtils.getContent(sourcePath);
                String[] sourceWords = sourceWord.split(ConstantParams.SINGLE_BLANK);
                String[] words = word.split(ConstantParams.SINGLE_BLANK);
                Set<String> leftSet = new HashSet<String>();
                Set<String> rightSet = new HashSet<String>();

                //是0的时候,表示完整;1的时候表示不完整
                int left = 0;
                int right = 0;

                int leftFirst = 1;
                int rightLast = 1;
                if(words.length == 1){
                    for(int i=0;i<sourceWords.length;i++){
                        if(words[0].equals(sourceWords[i])){
                            if(i == 0){
                                leftFirst = 0;//左完整
                                rightSet.add(sourceWords[i+1]);
                            }else if(i == sourceWords.length-1){
                                rightLast = 0;//右完整
                                leftSet.add(sourceWords[i-1]);
                            }else{
                                leftSet.add(sourceWords[i-1]);
                                rightSet.add(sourceWords[i+1]);
                            }

                        }
                        if(leftFirst == 0){
                            left = 0;
                        }else{
                            if(leftSet.size() == 1){
                                left = 1;
                            }else{
                                left = 0;
                            }
                        }                       
                        if(rightLast == 0){
                            right = 0;
                        }else{
                            if(rightSet.size() == 1){
                                right = 1;
                            }else{
                                right = 0;
                            }
                        }
                    }
                }else if(words.length == 2){                    
                    for(int i=0;i<sourceWords.length-1;i++){
                        if(words[0].equals(sourceWords[i]) && words[1].equals(sourceWords[i+1])){
                            if(i == 0){
                                leftFirst = 0;//
                                rightSet.add(sourceWords[i+2]);
                            }else if(i == sourceWords.length-1){
                                rightLast = 0;
                                leftSet.add(sourceWords[i-1]);
                            }else{
                                leftSet.add(sourceWords[i-1]);
                                rightSet.add(sourceWords[i+2]);
                            }

                        }
                        if(leftFirst == 0){
                            left = 0;
                        }else{
                            if(leftSet.size() == 1){
                                left = 1;
                            }else{
                                left = 0;
                            }
                        }

                        if(rightLast == 0){
                            right = 0;
                        }else{
                            if(rightSet.size() == 1){
                                right = 1;
                            }else{
                                right = 0;
                            }
                        }
                    }
                }else if(words.length == 3){
                    for(int i=0;i<sourceWords.length-2;i++){
                        if(words[0].equals(sourceWords[i]) && words[1].equals(sourceWords[i+1]) && words[2].equals(sourceWords[i+2])){
                            if(i == 0){
                                leftFirst = 0;
                                rightSet.add(sourceWords[i+3]);
                            }else if(i == sourceWords.length-1){
                                rightLast = 0;
                                leftSet.add(sourceWords[i-1]);
                            }else{
                                leftSet.add(sourceWords[i-1]);
                                rightSet.add(sourceWords[i+3]);
                            }

                        }
                        if(leftFirst == 0){
                            left = 0;
                        }else{
                            if(leftSet.size() == 1){
                                left = 1;
                            }else{
                                left = 0;
                            }
                        }
                        if(rightLast == 0){
                            right = 0;
                        }else{
                            if(rightSet.size() == 1){
                                right = 1;
                            }else{
                                right = 0;
                            }
                        }
                    }
                }
                rawResult += word+ConstantParams.TABLE+left+ConstantParams.TABLE+right+ConstantParams.CHENG_LINE;
                if(left == 0 && right == 0){
                    inteWords.add(word);
                    //                  result += word+ConstantParams.TABLE+left+ConstantParams.TABLE+right+ConstantParams.CHENG_LINE;
                }
            }
            StringUtils.string2File(rawResult, outputPath);//所有完整性词的展示
            //          StringUtils.string2File(result, outputPath);//仅是完整性词的展示
            return inteWords;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return inteWords;   
    }

非稳定性完整对象的计算

/**
     * @Description: 非稳定评价对象的过滤,并生成去除词性的stableWords,为后面计算做准备
     * @param: inputPath : fliterWords(未去重)   outPath:输出路径     inteWords:符合规则完整性词     stablePath
     * @return:
     * @date: 2017-10-13  
     */
    public static void getObject(String inputPath,String outPath,List inteWords,String stablePath){
        Map<String, Double> wordsObject = new HashMap<String, Double>();
        List<String> wordsList = StringUtils.getContentFromPath(inputPath);
        getKeyTimes(inputPath);
        try {
            double objectIndex = 0;
            for(String word : wordsList){
                if(!inteWords.contains(word)){
                    continue;
                }
                String[] words = word.split(ConstantParams.SINGLE_BLANK);
                if(words.length == 1){
                    wordsObject.put(word, 1.0);
                }
                else if(words.length == 2){
                    double aWordTimes = 0;
                    double bWordTimes = 0;
                    double objectTimes = 0;
                    double wordsNumber = 2;
                    if(keyMap.containsKey(word)){
                        objectTimes = keyMap.get(word); 
                    }
                    if(keyMap.containsKey(words[0]+ConstantParams.SINGLE_BLANK)){
                        aWordTimes = keyMap.get(words[0]+ConstantParams.SINGLE_BLANK);  
                    }
                    if(keyMap.containsKey(words[1]+ConstantParams.SINGLE_BLANK)){   
                        bWordTimes = keyMap.get(words[1]+ConstantParams.SINGLE_BLANK);  
                    }
                    objectIndex = objectTimes/((aWordTimes+bWordTimes)-(wordsNumber-1)*objectTimes);
                    if(Double.isInfinite(objectIndex)){
                        objectIndex = 0;
                    }
                    wordsObject.put(word, objectIndex);
                }
                else if(words.length == 3){
                    double aWordTimes = 0;
                    double bWordTimes = 0;
                    double cWordTimes = 0;
                    double objectTimes = 0;
                    double wordsNumber = 3;
                    if(keyMap.containsKey(word)){
                        objectTimes = keyMap.get(word); 
                    }       
                    if(keyMap.containsKey(words[0]+ConstantParams.SINGLE_BLANK)){
                        aWordTimes = keyMap.get(words[0]+ConstantParams.SINGLE_BLANK);  
                    }
                    if(keyMap.containsKey(words[1]+ConstantParams.SINGLE_BLANK)){   
                        bWordTimes = keyMap.get(words[1]+ConstantParams.SINGLE_BLANK);  
                    }
                    if(keyMap.containsKey(words[2]+ConstantParams.SINGLE_BLANK)){   
                        cWordTimes = keyMap.get(words[2]+ConstantParams.SINGLE_BLANK);  
                    }
                    objectIndex = objectTimes/((aWordTimes+bWordTimes+cWordTimes)-(wordsNumber-1)*objectTimes);
                    if(Double.isInfinite(objectIndex)){
                        objectIndex = 0;
                    }
                    wordsObject.put(word, objectIndex);
                }
            }
            Map resultMap = SortUtils.sortByValue(wordsObject);
            String str = "";
            //          String stable = "";
            Set<String> set = resultMap.keySet();
            Iterator<String> iter = set.iterator();
            while(iter.hasNext()){
                String key = iter.next();
                Double value = (Double)resultMap.get(key);      
                //              stable+=key+ConstantParams.SINGLE_BLANK+value+ConstantParams.CHENG_LINE;
                //稳定性>=0的数都可以存入最终的词典中
                if(value>=0){
                    str+=key+ConstantParams.CHENG_LINE; 
                }           
            }
            //stable
            clearSpeech(str, stablePath);
            //          StringUtils.string2File(str, stablePath);//稳定性词(删除)
            StringUtils.string2FileTrue(str, outPath);//生成第一层词典
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

计算特征 2:完整性对象出现频率,tf和idf的计算前面提到,不在赘述。

/**
     * @Description: 计算评价对象出现的概率:f-object
     * @return:
     * @date: 2017-10-30  
     */
    public static double calObject(String word){
        Double d = wordCount_txt.get(word);
        Double objectD = wordCount_txts.get(word);
        double result = 0.0;
        double X = 0.5;
        if(objectD == 1){
            result = X;
            return result;
        }
        else{
            result = d/objectD+1;
        }
        if(Double.isNaN(result)){
            result = 0.0;
        }
        return result;
    }

根据特征1和2,计算置信区间

/**
     * @Description: 计算置信区间的平均值
     * @param:
     * @return:
     * @date: 2017-12-18  
     */
    private static void calConfidence(Map<String,Double> ev0_word,Map<String,Double> ev1_word,String objectPath) {
        //根据分开的0和1,在对概率的分布值进行处理,求出其中的0和1的置信区间
        String content = StringUtils.getContent(objectPath);//f-object总排名,利用其计算置信度
        String[] content_split = content.split(ConstantParams.CHENG_LINE);
        double c_Confidence_0 = 0, l_Confidence_0 = 0;//0的置信区间范围
        double c_Confidence_1 = 0, l_Confidence_1 = 0;//1的置信区间范围
        double ave_0 = 0,ave_1 = 0;//均值
        double variance_0 = 0,variance_1 = 0;//方差
        //存基础数据
        List<Double> object_value_0 = new ArrayList<>();
        List<Double> object_value_1 = new ArrayList<>();
        double t = 2.807;//t分布,α=0.0025
        double count = 0;
        int N = content_split.length;//样本总个数    
        for(int i=0;i<content_split.length;i++){
            String[] word = content_split[i].split(ConstantParams.SINGLE_BLANK);            
            //计算出1和0  f-object的最大值
            /*
             * 求0部分和1部分f-object的值的置信区间
             * 
             * 1 均值     2 查表置信度数据    3 求S(方差/n-1)  4 求sqrt(n)
             * */
            if(ev0_word.containsKey(word[0])){
                if(ev0_word.get(word[0])!=null){
                    //写出                
                    //                  write_01(content_split[i]);
                    object_value_0.add(Double.valueOf(word[1]));
                    ave_0+= Double.valueOf(word[1]);
                }   
            }else if(ev1_word.containsKey(word[0])){
                if(ev1_word.get(word[0])!=null){
                    //写出                
                    //                  write_02(content_split[i]);
                    object_value_1.add(Double.valueOf(word[1]));
                    ave_1+= Double.valueOf(word[1]);
                }
            }
        }
        ave_0/=N; 
        ave_1/=N;
        //0的方差
        for(Double value : object_value_0){
            variance_0 +=Math.pow((value-ave_0), 2);
        }
        variance_0/=N-1;
        //1的方差
        for(Double value : object_value_1){
            variance_1 +=Math.pow((value-ave_1), 2);
        }
        variance_1/=N-1;
        //0的置信区间
        c_Confidence_0 = ave_0 - t*(N-1) * (variance_0/Math.sqrt(N)); 
        l_Confidence_0 = ave_0 + t*(N-1) * (variance_0/Math.sqrt(N)); 
        //1的置信区间
        c_Confidence_1 = ave_1 - t*(N-1) * (variance_1/Math.sqrt(N)); 
        l_Confidence_1 = ave_1 + t*(N-1) * (variance_1/Math.sqrt(N)); 


        for(double value :object_value_0){
            if(value>=c_Confidence_0 && value<=l_Confidence_0){
                count++;
                ave_confidence_0+=value;
            }
        }
        ave_confidence_0/=count;

        count = 0;
        for(double value :object_value_1){
            if(value>=c_Confidence_1 && value<=l_Confidence_1){
                count++;
                ave_confidence_1+=value;
            }
        }
        ave_confidence_1/=count;
        //      System.out.println(c_Confidence_0);
        //      System.out.println(l_Confidence_0);
        //      System.out.println("---------------");
        //      System.out.println(c_Confidence_1);
        //      System.out.println(l_Confidence_1);
        //      System.out.println("---------------");
        //      System.out.println(ave_confidence_0+"  "+ave_confidence_1);
    }

根据K值,求平行线另一点坐标,置信度排序

/**
     * @Description: 根据K值,求平行线另一点坐标
     * @param: K:斜率;X:X坐标值;ev0_word 评价值为0的词
     * @return:
     * @date: 2017-11-1  
     */
    public static void change0_1(double K,double X,Map<String,Double> ev0_word,Map<String,Double> ev1_word,String objectPath,String outputPath){
        Map<String,Double> allMap = new HashMap<String,Double>();
        //读取objectPath中的频率值
        String content = StringUtils.getContent(objectPath);
        String[] content_split = content.split(ConstantParams.CHENG_LINE);
        for(int i=0;i<content_split.length;i++){
            String[] word = content_split[i].split(ConstantParams.SINGLE_BLANK);
            String key = word[0];
            if(ev0_word.containsKey(key)){
                if(ev0_word.get(key)!=null){
                    double Y0 = Double.valueOf(word[1]);
                    double Y =  K*(X-0)-Y0;
                    allMap.put(key, Y); 
                }
            }
            else if(ev1_word.containsKey(key)){
                if(ev1_word.get(key)!=null){
                    double Y1 = Double.valueOf(word[1]);
                    allMap.put(key, Y1);    
                }
            }
        }
        List<Entry<String,Double>> sortMapByValue = StringUtils.sortMapByValue(allMap); 
        String fin_result = "";
        for(Map.Entry<String, Double> entry : sortMapByValue){
            fin_result+=entry.getKey() + ConstantParams.SINGLE_BLANK + entry.getValue() + ConstantParams.CHENG_LINE;
        }
        StringUtils.string2File(fin_result, outputPath);
    }
上一篇 下一篇

猜你喜欢

热点阅读