关于nlp:NLP-开源形近字算法之相似字列表番外篇

48次阅读

共计 3082 个字符,预计需要花费 8 分钟才能阅读完成。

创作目标

国内对于文本的类似度计算,开源的工具是比拟丰盛的。

然而对于两个汉字之间的类似度计算,国内根本一片空白。国内的参考的材料少的可怜,国外相干文档也是如此。

本我的项目旨在抛砖引玉,实现一个根本的类似度计算工具,为汉字 NLP 奉献一点绵薄之力。

举荐浏览:

NLP 中文形近字类似度计算思路

中文形近字类似度算法实现,为汉字 NLP 尽一点绵薄之力

当代中国最贵的汉字是什么?

NLP 开源形近字算法补完打算(完结篇)

NLP 开源形近字算法之形近字列表(番外篇)

开源我的项目在线化 中文繁简体转换 / 敏感词 / 拼音 / 分词 / 汉字类似度 /markdown 目录

需要

有时候咱们并不是须要返回两个字的类似,而是须要返回一个汉字的类似列表。

实现思路

咱们能够别离计算所有的汉字之间的类似度,而后保留最大的前 100 个,放在字典中。

而后实时查问这个字典即可。

实现形式

bihuashu_2w.txt 中咱们次要须要的是对应的 2W 常见汉字。

hanzi_similar_list.txt 用来寄存汉字和类似字的映射关系。

数据初始化

public static void main(String[] args) {
    final String path = "D:\\code\\coin\\nlp-hanzi-similar\\src\\main\\resources\\hanzi_similar_list.txt";
    // 读取列表
    List<String> lines = FileUtil.readAllLines("D:\\code\\coin\\nlp-hanzi-similar\\src\\main\\resources\\nlp\\bihuashu_2w.txt");
    // 所有的单词
    Set<String> allWordSet = new HashSet<>();
    for(String line : lines) {String word = line.split(" ")[0];
        allWordSet.add(word);
    }
    // 循环比照
    for(String word : allWordSet) {List<String> list = getSimilarListData(word, allWordSet);
        String line = word +"" + StringUtil.join(list,"");
        FileUtil.append(path, line);
    }
}
  • 优先级队列取前 100 个

咱们通过优先级队列存储:

private static List<String> getSimilarListData(String word, Set<String> wordSet) {PriorityQueue<SimilarListDataItem> items = new PriorityQueue<>(new Comparator<SimilarListDataItem>() {
        @Override
        public int compare(SimilarListDataItem o1, SimilarListDataItem o2) {
            // 类似度大的放在后面
            return -o1.getRate().compareTo(o2.getRate());
        }
    });
    for(String other : wordSet) {if(word.equals(other)) {continue;}
        // 比照
        double rate = HanziSimilarHelper.similar(word.charAt(0), other.charAt(0));
        SimilarListDataItem item = new SimilarListDataItem(other, rate);
        items.add(item);
    }
    final int limit = 100;
    List<String> wordList = new ArrayList<>();
    for(SimilarListDataItem item : items) {wordList.add(item.getWord());
        if(wordList.size() >= limit) {break;}
    }
    return wordList;
}

类似字的获取

初始化好数据之后,所有就变得非常简单:

  • 接口定义
/**
 * 数据接口 - 类似列表
 * @author binbin.hou
 * @since 1.3.0
 */
public interface IHanziSimilarListData {

    /**
     * 返回数据信息
     * @param word 单词
     * @return 后果
     * @since 1.3.0
     */
    List<String> similarList(String word);

}
  • 数据获取
public class HanziSimilarListData implements IHanziSimilarListData {private static volatile Map<String, List<String>> map = Guavas.newHashMap();


    @Override
    public List<String> similarList(String word) {if(MapUtil.isEmpty(map)) {initDataMap();
        }

        return map.get(word);
    }

    private void initDataMap() {if(MapUtil.isNotEmpty(map)) {return;}

        //DLC
        synchronized (map) {if(MapUtil.isEmpty(map)) {List<String> lines = StreamUtil.readAllLines("/hanzi_similar_list.txt");

                for(String line : lines) {String[] words = line.split(" ");
                    // 前面的 100 个相近词
                    List<String> list = StringUtil.toCharStringList(words[1]);
                    map.put(words[0], list);
                }
            }
        }
    }

}

便利性

为了用户使用方便,咱们在 HanziSimilarHelper 中增加 2 个工具类办法:

/**
 * 类似的列表
 * @param hanziOne 汉字一
 * @param limit 大小
 * @return 后果
 * @since 1.3.0
 */
public static List<String> similarList(char hanziOne, int limit) {return HanziSimilarBs.newInstance().similarList(hanziOne, limit);
}
/**
 * 类似的列表
 * @param hanziOne 汉字一
 * @return 后果
 * @since 1.3.0
 */
public static List<String> similarList(char hanziOne) {return similarList(hanziOne, 10);
}

测试成果

咱们应用看一下成果:

咱们来看一下【爱】的形近字。

List<String> list = HanziSimilarHelper.similarList('爱');
Assert.assertEquals("[ 爰, 爯, 受, 爭, 妥, 憂, 李, 爳, 叐, 雙]", list.toString());

开源地址

为了便于大家应用学习,我的项目已开源。

https://github.com/houbb/nlp-hanzi-similar

小结

一个字的形近字能够做很多乏味的事件,这个要看大家的想象力。

实现形式也不难,最外围的还是类似度的计算。

我是老马,期待与你的下次重逢。

正文完
 0