书单

书名 日期 作者 状态
三体 2018-12 刘慈欣 已读
大空头 2018-12 在读

pyhanlp重载自定义词典

在使用hanlp的过程中可能会遇到需要重新加载词典的方法,
在HanLP的Git Issue中有相关问题的解答
如何在程序中重新加载自定义的词典
hanlp 能否加入一个远程词典更新的功能

hanlp 能否加入一个远程词典更新的功能中提到了一个接口 自定义词典支持热更新

CustomDictionary.java提供了一个reload方法,

    /**
     * 热更新(重新加载)<br>
     * 集群环境(或其他IOAdapter)需要自行删除缓存文件(路径 = HanLP.Config.CustomDictionaryPath[0] + Predefine.BIN_EXT)
     * @return 是否加载成功
     */
    public static boolean reload()
    {
        String path[] = HanLP.Config.CustomDictionaryPath; // Tips : 读取HanLP的配置文件中CustomDIctionaryPath
        if (path == null || path.length == 0) return false;
        new File(path[0] + Predefine.BIN_EXT).delete(); // 删掉缓存
        return loadMainDictionary(path[0]);
    }

其中调用了loadMainDictionary方法.

private static boolean loadMainDictionary(String mainPath)
     {
         logger.info("自定义词典开始加载:" + mainPath);
         if (loadDat(mainPath)) return true;
         dat = new DoubleArrayTrie<CoreDictionary.Attribute>();
         TreeMap<String, CoreDictionary.Attribute> map = new TreeMap<String, CoreDictionary.Attribute>();
        LinkedHashSet<Nature> customNatureCollector = new LinkedHashSet<Nature>();
        try
        {
            String path[] = HanLP.Config.CustomDictionaryPath;
            for (String p : path)
            {
                Nature defaultNature = Nature.n;
                 int cut = p.indexOf(' ');
                 if (cut > 0)
                 {
                     // 有默认词性
                     String nature = p.substring(cut + 1);
                     p = p.substring(0, cut);
                     try
                     {
                         defaultNature = LexiconUtility.convertStringToNature(nature, customNatureCollector);
                     }
                     catch (Exception e)
                     {
                         logger.severe("配置文件【" + p + "】写错了!" + e);
                         continue;
                     }
                 }
                 logger.info("以默认词性[" + defaultNature + "]加载自定义词典" + p + "中……");
                 boolean success = load(p, defaultNature, map, customNatureCollector);
                 if (!success) logger.warning("失败:" + p);
             }
             if (map.size() == 0)
             {
                 logger.warning("没有加载到任何词条");
                 map.put(Predefine.TAG_OTHER, null);     // 当作空白占位符
             }
             logger.info("正在构建DoubleArrayTrie……");
             dat.build(map);
             // 缓存成dat文件,下次加载会快很多
             logger.info("正在缓存词典为dat文件……");
             // 缓存值文件
             List<CoreDictionary.Attribute> attributeList = new LinkedList<CoreDictionary.Attribute>();
             for (Map.Entry<String, CoreDictionary.Attribute> entry : map.entrySet())
             {
                 attributeList.add(entry.getValue());
             }
             DataOutputStream out = new DataOutputStream(IOUtil.newOutputStream(mainPath + Predefine.BIN_EXT));
             // 缓存用户词性
             IOUtil.writeCustomNature(out, customNatureCollector);
             // 缓存正文
             out.writeInt(attributeList.size());
             for (CoreDictionary.Attribute attribute : attributeList)
             {
                 attribute.save(out);
             }
             dat.save(out);
             out.close();
         }
         catch (FileNotFoundException e)
         {
             logger.severe("自定义词典" + mainPath + "不存在!" + e);
             return false;
         }
         catch (IOException e)
         {
             logger.severe("自定义词典" + mainPath + "读取错误!" + e);
             return false;
         }
         catch (Exception e)
         {
             logger.warning("自定义词典" + mainPath + "缓存失败!\n" + TextUtility.exceptionToString(e));
         }
         return true;
     }

其中loadDat

/**
      * 从磁盘加载双数组
      *
      * @param path
      * @return
      */
static boolean loadDat(String path)
     {
         try
         {
             ByteArray byteArray = ByteArray.createByteArray(path + Predefine.BIN_EXT);
             if (byteArray == null) return false;
             int size = byteArray.nextInt();
             if (size < 0)   // 一种兼容措施,当size小于零表示文件头部储存了-size个用户词性
             {
                 while (++size <= 0)
                 {
                     Nature.create(byteArray.nextString());
                 }
                 size = byteArray.nextInt();
             }
             CoreDictionary.Attribute[] attributes = new CoreDictionary.Attribute[size];
             final Nature[] natureIndexArray = Nature.values();
             for (int i = 0; i < size; ++i)
             {
                 // 第一个是全部频次,第二个是词性个数
                 int currentTotalFrequency = byteArray.nextInt();
                 int length = byteArray.nextInt();
                 attributes[i] = new CoreDictionary.Attribute(length);
                 attributes[i].totalFrequency = currentTotalFrequency;
                 for (int j = 0; j < length; ++j)
                 {
                     attributes[i].nature[j] = natureIndexArray[byteArray.nextInt()];
                     attributes[i].frequency[j] = byteArray.nextInt();
                 }
             }
             if (!dat.load(byteArray, attributes)) return false;
         }
         catch (Exception e)
         {
             logger.warning("读取失败,问题发生在" + TextUtility.exceptionToString(e));
             return false;
         }
         return true;
     }

可以看出 reload方法必须先删除bin文件, 再重新生成.

在Python中可以按照下面的方法进行重载

custom_dictionary = JClass('com.hankcs.hanlp.dictionary.CustomDictionary')
custom_dictionary.reload()

调用CustomDictionary类的reload方法可以重新按照properties中的设置重构一个bin文件.

同时也提供了直接添加自定义字典的方法, 但是看起来并不是很合适, 因为这样会

HanLP.Config. CustomDictionaryPath = ["dict.txt","dict2.txt"]
CustomDictionary.reload()

pyhanlp重加载词典中可能会遇到的问题

在进行重加载过程中发现一个可能存在的问题, 已经提交 reload生成自定义词典bin文件在重新载入时抛出异常ArrayIndexOutOfBoundsException
该问题主要表现为reload生成的bin文件在下次启动时不能被正常识别, 会抛出ArrayIndexOutOfBoundsException的问题.
原因是因为reload过程中, 静态类已经及存储了在这一次启动过程中识别过的自定义词性, 但是reload中没有写入这些词性, 导致在第二次启动过程中, 会发生越界.

矩阵的分解

矩阵分解 (decomposition, factorization)是将矩阵拆解为数个矩阵的乘积,可分为三角分解、满秩分解、QR分解、Jordan分解和SVD(奇异值)分解等,常见的有三种:1)三角分解法 (Triangular Factorization),2)QR 分解法 (QR Factorization),3)奇异值分解法 (Singular Value Decomposition)。

矩阵常见分解法:
1. LU factorization(LU分解法)
LU 分解法
2. QR factorization
3. Jordan factorization
4. SVD factorization

https://blog.csdn.net/bitcarmanlee/article/details/52662518

第十二章 随机过程及其统计描述

P 300 – 316 正文
P 317 – 318 习题

1. 随机过程的概念

随机过程的研究对象是随时间演变的随机现象, 对于这种现象, 不能用随机变量或者多维随机变量来合理的表达, 而需要用一族(无限多个)随机变量来描述.

随机过程
T 是一无限实数集, 将依赖于参数 t \in T的一族(无限多个)随机变量称为随机过程, 记为 \lbrace X(t), t \in T \rbrace.
每一个 t \in T, X(t)是一随机变量, T 叫做参数集.
常把 t 看做时间, 称 X(t) 为时刻 t 时过程的状态. 而 X(t_1)=x(实数)说成是 t=t_1时过程处于状态 x.
对于一切 t \in T, X(t) 所有可能取的一切值的全体称为随机过程的状态空间.

对随机过程XXX进行一次试验(即在T上进行一次全程观测), 其结果是t的函数, 称它为随机过程的一个样本函数或样本曲线.

伯努利过程伯努利随机序列
抛掷一颗筛子, 设 X_n 是第 n 次(n\ge1)抛掷的点数, 对于 n = 1, 2,\cdots 的不同值, X_n 是不同的随机变量, 因而 \lbrace X_n, ,n \ge 1\rbrace构成一随机过程, 称为 伯努利过程伯努利随机序列

2. 随机过程的统计描述

2.1 随机过程的分布函数族

一维分布函数
一维分布函数族

n维分布函数族
有限维分布函数族

2.2 随机过程的数字特征

均值函数

集平均 或 统计平均 (需和14章中的时间平均区分)

均方差函数 和 方差函数

标准差函数

自相关函数, 简称相关函数.

自相关函数和自协方差函数是刻画随机过程自身在两个不同时刻的状态之间统计依赖关机的数字特征.