书单

书名 日期 作者 状态
三体 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

搜索引擎的查询意图识别

文章来源自搜索引擎的查询意图识别, 本文是在原文基础上做出一些结构调整和内容补充.


搜索分类

搜索大致可以分为两类: 通用搜索和垂直搜索

搜索类型 特点 案例
通用搜索 抓取互联网上一切有价值的页面, 根据网页内容建立索引, 以关键字匹配为基本检索方式, 以网页title和summary为展现方式 google, 百度, 搜狗, 搜搜, 有道
垂直搜索 以一特定类别为主题, 只抓取与主题相关信息, 根据主题特点有针对性的建立相应的索引检索方式, 筛选方式, 以及展现方式 机票搜索 ,地图搜索, 购物搜索

# 意图识别

意图搜索的难点:
1. 输入不规范
– 输入方法多样化
– 非常不规范
– 有堆砌关键词
– 自然语言查询
– 甚至非标准自然语言

  1. 多意图
    如: 仙剑奇侠传
    游戏?–> 游戏软件?
    电视剧?–> 电视剧下载?相关新闻?
    电影?–> 电影下载?查看影评?剧情介绍?
    音乐?–> 歌曲下载?在线听歌?歌词下载?
    小说?–> 小说下载?在线观看?

  2. 意图强度
    如: 荷塘月色
    荷塘月色歌曲 –> 歌曲下载: 50%
    荷塘月色小区 –> 房产需求: 20%
    荷塘月色菜 –> 菜谱需求: 10%

  3. 结果可靠性
    供我们获取搜索结果的这些垂直站点往往是一些中小型的网站, 我们需要保证搜索结果的准确性和相关性
    如: 遥控汽车
    预期结果: 返回所有遥控汽车的相关结果
    实际返回:
    遥控汽车–> 没有遥控汽车相关结果
    遥控–> 返回遥控器, 遥控飞机等于原意图无关的结果
    汽车–> 返回汽车模型, 汽车配件等于原意图无关的结果
    (比如京东就是这么拆搜索词的)

  4. 时效性
    如: iPhone5 7月1日上市销售
    6月30日的查询意图: 新闻90%, 百科10%
    7月1日的查询意图: 新闻70%, 购买25%, 百科5%
    8月1日的查询意图: 购买50%, 资讯40%, 其他10%
    5年以后的查询意图: 百科100%

解决方案

词表穷举法

最简单直接的方法, 通过词表的直接匹配来获取查询意图, 也可加入适用于较为简单且查询较为集中的类别, 比如电视台节目查询, 节假日查询, 餐馆查询等

如: 北京的天气怎么样啊
(停用词替换) –> [北京][天气][怎么样]
(查询词归一) –> {城市][关键词][疑问词]
(顺序无关) –> {[城市], [关键词], [疑问词]}
给出白名单:

规则解析法

适用于一些查询虽然不集中但非常符合规则的类别, 通过规则解析查询来做意图识别和关键信息提取的, 比如汇率查询, 计算器, 度量衡等
如: 236.2美金能换多少RMB?
[236.2][美金][今天]能换多少[人民币]?
[数字][货币单位][日期]能换多少[货币单位]?
– 查询改写
通过规则或知识图谱, 将相似相近的概念词替换/对应/归一为统一的概念词.
解析:
数量: 236.2
源货币: 美元(将’美金’替换为标准词’美元’)
目的货币: 人民币
– 自定义语言模型
配合自己建立的一些语言模型, 可以比较好的解决召回率比较低的问题. 模型训练的比较好的话, 相对召回也很不错. 但是比如购物啊什么的, 是无法做这种信息模型的

统计模型分类法: (最常用)

统计模型分类 概念 流程
查询词分类 基于查询词本身的分类, 也就是建立基于字面意思的统计分类模型 查询词–>查询纠错, 规则化, 知识词表–>Uni-gram, Bi-gram, CRF, 语料分类模型–>搜索结果验证, 垂直搜索结果验证–>查询扩展分类结果
查询词扩展分类 基于查询词的扩展信息的分类, 也就是基于真实社会知识的分离, 通常是搜索结果扩展, 比如“家常菜”居然是个电视剧. 查询词–>搜索结果1,2,3,4–>标题分类、摘要分类、网站分类–>结果分类1,2,3,4–>查询扩展分类结果(针对每个搜索结果, 验证一下查询意图强度和类别)

需要配合持续更新的语料, 就可以通过流程自动更新, 比较可行的方法如: 先到软件下载站, 把排行榜的TOP 100拖下来(这些都有软件下载的查询需求), 搜索一遍, 然后每个取前50个搜过结果, 作为一个5000大小的语料, 可以训练, 可以持续、自动更新.

搜索意图识别未来

  • 无类别概念的意图识别
  • 基于垂直搜索的分类模型, 而非基于类别的分类模型
    帮助用户获取想要的内容而不限定类别. 比如将 类别 和 网站 本身建立联系, 直接在网站内部的数据库中搜索.
  • 个性化意图上下文分析
    根据用户特征建立个性化的信息, 获取用户的短期兴趣和长期兴趣, 对准性的优化意图识别
  • 精准意图理解
    更加精准的意图理解, 所有价值信息的解析, 目前的展现多为整体展现, 可以再进一步来生成个性展现
  • 语言应用的意图理解
    针对语言类应用的特点优化, 比如语言纠错, 个性信息的辅助意图识别等

Blob 分析

Blob分析(Blob Analysis)是对图像中相同像素的连通域进行分析,该连通域称为Blob。Blob分析可为机器视觉应用提供图像中的斑点的数量、位置、形状和方向,还可以提供相关斑点间的拓扑结构。

Blob翻译成中文,是“一滴”,“一抹”,“一团”,“弄脏”,“弄错”的意思。在计算机视觉中的Blob是指图像中的具有相似颜色、纹理等特征所组成的一块连通区域。显然,Blob分析其实就是将图像进行二值化,分割得到前景和背景,然后进行连通区域检测,从而得到Blob快的过程。简单来说,blob分析就是在一块“光滑”区域内,将出现“灰度突变”的小区域寻找出来。举例来说,假如现在有一块刚生产出来的玻璃,表面非常光滑,平整。如果这块玻璃上面没有瑕疵,那么,我们是检测不到“灰度突变”的;相反,如果在玻璃生产线上,由于种种原因,造成了玻璃上面有一个凸起的小泡、有一块黑斑、有一点裂缝。。。那么,我们就能在这块玻璃上面检测到纹理,颜色发生突变的部分,而这些部分,就是生产过程中造成的瑕疵,而这个过程,就是blob分析。显然,纺织品的瑕疵检测,玻璃的瑕疵检测,机械零件表面缺陷检测,可乐瓶缺陷检测,药品胶囊缺陷检测等很多场合都会用到blob分析。

Blob分析主要适用于以下图像:
1. 二维目标图像
2. 高对比度图像
3. 存在/缺席检测
4. 数量范围和旋转不变性需求
并不适用于以下图像:
1. 低对比度图像
2. 必要的图像特征不能用2个灰度级描述
3. 按照模版检测

(1)图像分割(Image Segmentation)
因为 Blob分析是一种对闭合目标形状进行分析处理的基本方法。在进行Blob分析以前,必须把图像分割为构成斑点(Blob)和局部背景的像素集合。B l o b分析一般从场景的灰度图像着手进行分析。在Blob分析以前,图像中的每一像素必须被指定为目标像素或背景像素。典型的目标像素被赋值为1,背景像素被 赋值为0。有多种技术可将图像分割为目标像素和背景像素。这些技术包括:二元阈值(Binary Thresholding)、空间量化误差(Spatial~ mtization
Error)、软件二元阈值和像素加权(SoftBinary Thresholding and Pixel Weighting)、相关阈值(Relative Thresholds)、阈值图像(Threshold Image)。

(2)连通性分析(Connectivity Analysis)当图像被分割为目标像素和背景像素后,必须进行连通性分析,以便将目标图像聚合为目标像素或斑点的连接体。
连通性分析的三种类型如下:

·全图像连通性分析(Whole Image ConnectivityAnalysis)在全图像连通性分析中,被分割图像的所有的目标像素均被视为构成单一斑点的像素。即使斑点像素彼此并不相连,为了进行Blob分析,它们仍被视为单一的斑点。所有的Blob统计和测量均通过图像中的目标像素进行计算;

·连接Blob分析(Connected Blob analysis) 连接Blob分析通过连通性标准,将图像中目标像素聚合为离散的斑点连接体。一般情况下,连接性分析通过连接所有邻近的目标像素构成斑点。不邻近的目标像素则不被视为是斑点的一部分;
·标注连通性分析(Labeled Connectivity Analysis) 在 机器视觉应用中, 由于所进行的图像处理过程不同,可能需对某些已被分割的图像进行Blob分析,而这些图像并未被分割为目标像素和背景像素。例如:图像可能被分为四个不同 像素集合,每一集合代表不同的像素值范围。这类分割称为标注连通性分析。当对标注分割的图像进行连通性分析时,将连接所有具有同一标注的图像。标注连通分 析不再有目标和背景的概念。
(3)Blob工具Blob 工具是用来从背景中分离出目标,并测量任意形状目标物的形态参数。这个处理过程,Blob并不是分析单个的像素,而是对图形的行进行操作。图像的每一行都 用游程长度编码(RLE)来表示相邻的目标范围。这种方法与基于象素的算法相比,处理速度能够加快。为了适应各种不同的需求,Blob提供了很多过滤和分 类模式来定义测量参数,而且有较好的操作性能。
https://blog.csdn.net/tercel_zhang/article/details/51227431

Blob在机器视觉中是指图像中的具有相似颜色、纹理等特征所组成的一块连通区域。Blob分析就是对这一块连通区域进行几何分析得到一些重要的几何特征,例如:区域的面积、中心点坐标、质心坐标、最小外接矩形、主轴等。

         Blob分析的一般步骤:

(1)图像分割:分离出前景和背景

(2)连通性分析:根据目标的连通性对目标区域进行标记,或者叫拓扑性分析

(3)特征量计算:描述了区域的几何特征,这些几何特征不依赖与灰度值

        一个很简单的例子:

         1.图像分割

             将图像分离为目标像素和背景像素,初始分割之后一般需要进行形态学处理才能满足使用要求。常用分割方法:直接输入;硬阈值分割;软阈值分割。常用形态学处理包括:连通、膨胀、腐蚀、开操作、闭操作、顶帽变换、击中与不击中变换、交集、差异、骨架、边界等。

阈值分割又包括:

1)简单阈值分割threshold

适用范围:目标与背景之间存在灰度差(如果环境稳定,阈值可以在离线状态下一次确定)

2)动态阈值分割dyn_threshold

适用范围:背景不均一无法确定全局阈值、目标经常表现为比背景局部亮一些或者暗一些。这时候需要通过其领域来找到一个合适的阈值进行分割。确定其领域的方法是:通过一些平滑滤波算子来确定领域,例如mean_image或者binomial_filter

3)自动全局阈值方法bin_threshold

4)watersheds_threshold

          2.特征量计算常用

area_center,区域面积Area和中心(Row,Column)

area_center_gray,区域面积Area和灰度中心(Row,Column)

smallest_rectangle1最小外接矩形

smallest_rectangle2最小外接仿射矩形,

compactness,紧凑度

elliptic_axis,计算region区域中的椭圆参数

intensity,计算region区域的灰度平均值和偏差

min_max_gray,最小最大灰度值


作者:那珈落
来源:CSDN
原文:https://blog.csdn.net/zhougynui/article/details/51767974
版权声明:本文为博主原创文章,转载请附上博文链接!

Random Walk 随机游走

Introduction

Random Walk
Random Walk with Restart
Fast Random Walk

What’s Random Walk ?

Quoting from 重启随机游走算法(RWR)

随机游走算法的基本思想是,从一个或一系列顶点开始遍历一张图。在任意一个顶点,遍历者将以概率1-a游走到这个顶点的邻居顶点,以概率a随机跳跃到图中的任何一个顶点,称a为跳转发生概率,每次游走后得出一个概率分布,该概率分布刻画了图中每一个顶点被访问到的概率。用这个概率分布作为下一次游走的输入并反复迭代这一过程。当满足一定前提条件时,这个概率分布会趋于收敛。收敛后,即可以得到一个平稳的概率分布。

What’s Random Walk with Restart(RWR) ?

Let’s have some brief about RWR at first.
Quoting from What is Random Walk with Restart (RWR)?, it says :

RWR is a algorithm originally proposed for image segmentation. It iteratively explores the global structure of the network to estimate the proximity (affinity score) between two nodes. Starting at a node, the walker faces two choices at each step: either moving to a randomly chosen neighbor, or jumping back to the starting node. This algorithm only contains one fixed parameter r called ‘the restarting probability’ (with 1 − r for the probability of moving to a neighbor). After iteratively reaching stability, the steady probability vector contains the affinity score of all nodes in the network to the starting node. This steady probability vector can be viewed as the ‘influential impact’ over the network imposed by the starting node.

In addition to a single starting node, RWR can be extended to a set of starting nodes. In this context, the resulting steady probability vector can also be considered as the ‘influential impact’ over the network, but collectively imposed by a set of starting nodes.

The steady probability vector for a set of starting nodes can be calculated according to the steady probability vector for single starting nodes. For this reason, it is useful to pre-compute affinity matrix for nodes in the graph with respect to each starting node as a seed (by looping over every node in the graph). The motivation behind this is that this pre-computed affinity matrix can be extensively reused for obtaining affinity scores between any combinations of nodes. For instance, such a strategy can dramatically relieve the computational burden involved in sampling a large number of random node combinations. Therefore, this pre-computation does permit some flexibility in the downstream use, in particular for statistical testing.

Some features can be extracted from this quoting.
At first , RWR was first proposed for image sementation. Automatic Multimedia Cross-modal Correlation Discovery. It was proposed to solve the problem about proximity of two node in graph. Second, only one parmeter r ( restarting probability) and two choices (1.jumping batch to the starting node 2. move to a randomly chosen neighbor). After iteratively reaching stablility, the steady probability vector contains affinity score of all nodes in the graph to the starting node. That means in intuition, the more far away node from the starting node ,the less influence it has to the starting node.

重启随机游走算法是在随机游走算法的基础的改进。从图中的某一个节点出发,每一步面临两个选择,随机选择相邻节点,或者返回开始节点。算法包含一个参数a为重启概率,1-a表示移动到相邻节点的概率,经过迭代到达平稳,平稳后得到的概率分布可被看作是受开始节点影响的分布。重启随机游走可以捕捉两个节点之间多方面的关系,捕捉图的整体结构信息。

Words

affinity n. 类似, 近似, 密切关系.
burden n. 负担, 包袱, 责任 vt. 使烦恼, 劳累.
flexibility n. 柔度, 灵活性.

Head First Statistics

1. 信息图形化

概念整理:
统计
信息和数据的区别?
饼图 + 条形图/水平条形图/堆积条形图/分段条形图 + 直方图

标度 : 百分数标度 + 频数标度

要点:
频数是一种统计方法, 用于描述一个类别中有多少个项.

集中趋势的量度

均值和平均数的区别
均值的两个表达式(全统计和频数统计) 和 符号 μ

异常值 : 和其他数据格格不入的极高或极低的数值.
偏斜数据 :

  1. 均值和中位数的区别?
    在数据存在偏斜的情况下, 中位数更能很好的表现数据分布.
    大多数情况系, 均值远优于中位数, 尤其对抽样数据来说.

P62

怎么判断数据倾斜发现?
尾巴往哪儿甩 就是哪倾斜, 而不是数据头部在哪里倾斜在哪里.

众数也是平均数的一种

如果有两个众数, 则是双峰数据.

众数组: 具有最高频数的组.

众数在众数较多时最没用.

众数必须存在数据集中.
众数是唯一能用于类别数据的平均数.

P78值得记录.

P83 第三章

全距: 数据的扩展范围. 也叫极差.
用数据集中最大值减去最小值, 最大值叫上界, 最小值叫下界.

全距仅描述了数据的范围, 并没有描述数据在上,下界之间的分布形态.

全距很容易受异常值的影响.

四分位数: 将整个数据一分为四的几个数值.

上四分位数, 下四分位数, 中位数,

四分位距 = 上四分位数 – 下四分位数

四分位距和全距相比, 较少受到异常值的影响.

Chapter 4. 概率

样本空间

维恩图
对立事件

互斥事件 : 如果两个事件是互斥事件, 则只有其中一个事件会发生. ( 如果两个事件中只有一个会发生, 能不能说这两个事件是互斥事件?)
相交事件 : 如果两个事件相交, 则这两个事件有可能同时发生.

如果P149, 则说A和B穷举.

条件概率

概率树

全概率公式

贝叶斯定理

Chapter 5. 离散概率分布的运用

\$\sigma\$

WishList

  1. CS231N 2017 李飞飞视觉课程
  2. GAN实现
  3. Transformer实现
  4. Encoder-Decoder 实现
  5. Attention机制了解
  6. TransE 等系列实现
  7. PRA 等系列实现
  8. 遗传,退火算法实现
  9. 线性代数复习 + 习题册练习
  10. 统计复习 + 习题册联系
  11. 传统机器学习相关知识整理
    12. Coursera上的deeplearning.ai课程 在网易云课堂上有 可以先上这个 然后去Coursera上拿个证书. 不过这个需要尽快 节省费用.
  12. 和阿木组队参加的DC比赛, 目标Top10
  13. CSDN 皮果提的博客写的很好 可以浏览一遍
  14. 选择一个数据集, 尝试使用各种模型比较一遍 CIF10.
  15. 整理下各个数据集 FashionMNIST.
  16. 复习老算法 例如红黑树 B+树等 图的遍历等 树的遍历等
  17. 强化学习实践
    19. 对话管理

Viterbi
Gibbs Sampling
RNN
CNN
CRF
Trie

浙大 概率论与数理统计 四-八章学习 习题