当谈中文分词时,我们谈些什么?
中文分词 · 综述
明确这一点后,读者们也许发现了不同语言在这一问题上的差别。西方拼音语言(英、法等),词与词之间有着明确的分隔,使得这类语言可以直接进行统计和使用语言模型。但一些亚洲语言(中、日、泰等),词之间没有明确的分界符,我们无法从长文本中直接提取词语。所以,对于此类语言,想要应用语言模型或者进行其他处理工作,需要先一步对文本“分词”,简单来说,就是人为在文本中加入分隔,其目的是将句子、段落、文章这种长文本分解为“词”单位,方便后续的处理的分析。作为一切自然语言处理工作的前提基础,“分词”工作的地位显而易见,分词方案的选择直接影响到后续工作的好坏。
目前分词算法已经基本发展完善,不少分词器都在实际应用中都取得的很好的效果。一直以来,对于分词的研究,从来都不是针对某一特定语言,因此这些分词算法以及分词器产品对于各种语言都是通用的。本文将以中文分词为例,谈谈中文分词工作的难点、相关算法、发展现状以及展望。
需要特别说明的一点是,不少人会认为分词技术只是针对亚洲语言的,在西方拼音语言中不存在这个问题。实际上不然,即使像英语这种自带空格分隔的语言,在句法分析中涉及到“找词组”的过程,与中文分词问题无异。另外在英文手写体识别中,单词与单词之间的空格不明显时,分词算法同样会派上用场。
中文分词 · 难点
一、中文分词规范问题
一直以来,“词”的概念是汉语语言学界纠缠不清而又挥之不去的问题。“词是什么”(词的抽象定义)及“什么是词”(词的具体界定),这两个基本问题有点飘忽不定,迄今拿不出一个公认的、具有权威性的词表来。主要困难出自两个方面:一方面是单字词与词素之间的划界,另一方面是词与短语(词组)的划界。
并且,不仅是语言学家们对划分词的标准不统一,普通人对于词的切分看法差异也比我们想象的要大的多。例如“华为公司”,有的人认为这是一个词,即指特定的一家中国公司;也有人认为这是一个词组,应当分为两个词“华为/公司”,“华为”是修饰“公司”的定语,不拆开无法体现内部的修饰关系。而这实际上涉及到对词粒度的理解了。
早在上世纪,学者们就意识到这一问题,并试图制定统一标准来解决。1992年国家标准局颁布了作为国家标准的《信息处理用现代汉语分词规范》,该规范大部分规定都是通过举例和定性描述来体现的。例如,规范4.2规定:“二字或三字词,以及结合紧密、使用稳定的二字或三字词组,一律为分词单位。”——“紧密”“稳定”的评判标准实际上仍然引入了人的主观因素,使得分词标准依旧模糊。后续的很多规定中都对分词单位有“结合紧密、使用稳定”的要求。这种规定的操作尺度很难把握,无法量化的规范更让分词结果难以标准化。因而使得《规范》没能统一人们对汉语词的认识,哪怕只是在信息处理界。最后规范问题也一直存在于中文分词技术的发展过程中。
图 1 《信息处理用现代汉语分词规范》首页
二、歧义切分问题
语言的歧义性伴随着语言的发展,困扰了学者们上千年。在中国古代,断句和说文解字从根本上讲,就是消除歧义性,而不同学者之间的看法也显然不相同。各种春秋的正义(一种经注兼释的注释)或者对论语的注释,就是各家按照自己的理解消除歧义性。
在中文分词研究中,歧义切分问题是一个不可避免的阻碍。20世纪90年代以前,海内外不少学者试图用一些文法规则来解决分词的歧义问题,但不都是很成功。后来人们意识到在分词过程中统计信息的作用,运用统计语言模型成功解决来分词的歧义问题,将分词错误降低了一个数量级。本质上,解决歧义问题最好的方式还是联系上下文。而如今随着神经网络的发展,结合LSTM+CRF序列标注的分词算法,使得分词工作在歧义问题处理上表现得更加出色。
三、未登录词问题
未登录词指已有的词表中没有收录的词,或是已有的训练语料中未曾出现过的词,也称集外词(out of vocabulary, OOV)。未登录词可以大致划分为以下几种类型:
(1)新出现的普通词汇
主要是一些网络热词,并且随着网络环境的发展,这些词寿命更短,换代速度更快。
(2)命名实体
(3)专业名词与研究领域名称
特定领域的专业名词和新出现的研究领域名称也是造成生词的原因之一。
(4)其他专用名词
主要是一些新的产品名,如电影、歌曲、书籍等名称。
中文分词 · 算法
一、基于词典的方法
这种方法的本质是字符串的匹配,将待分词的中文文本根据一定规则切分和调整,然后跟词典中的词语进行匹配,匹配成功则按照词典的词分词,匹配失败通过调整或者重新选择,如此反复循环即可。代表方法有基于正向最大匹配和基于逆向最大匹配及双向匹配法。
可以看出,这种分词方法是比较机械的,算法的侧重点在于对搜索过程的优化,例如构造如图2的字典树(trie树)。
图 2 trie树
字典树是一种哈希树的变种,有很高的查找效率。但实际的使用效果上,却不尽人意。在图2所示的字典树中,对例句“他说的确实在理”进行分词,逆向匹配结果为:“他/说/的/确实/在理”,分词正确;正向最大匹配结果为“他说/的确/实在/理”,显然不是我们想要的分词结果。
所以,即使此类方法可以在O(n)时间对句子进行分词,但它毕竟太简单了,面对稍微复杂一点的问题就无能为力,因此在实际情况中基本不使用此种方法。
二、基于统计的分词方法
在介绍中文分词难点时,我们提到了统计信息在解决歧义问题中发挥的作用。随着统计方法的迅速发展,人们提出了诸多基于统计的分词模型,以及规则方法与统计方法相结合的分词技术,使汉语分词问题得到了更加深入的研究。
下面列举了一些性能较好的分词方法:N-最短路径方法、基于词的n元语法模型的分词方法、由字构词的汉语分词方法、基于词感知机算法的汉语分词方法、基于字的生成式模型和区分式模型相结合的汉语分词方法。
本文在《统计自然语言处理》(宗成庆)一书的基础上简略介绍前两种方法,有意了解这部分详细算法的可以参考此书7.2节“汉语分词方法”的内容。
1.N-最短路径方法
上文介绍了中文分词的三大难点,其中,中文分词规范问题虽然一直难以处理,但对于分词效果的影响远不如歧义切分与未登录词问题。因此在早期,人们有意将这部分难点拿出来单独研究。于是,有专家将分词工作分为两个阶段:一是将采用切分算法对句子词语进行初步切分,得到一个相对较好的粗分结果;二是进行歧义排除和未登录词识别。
针对第一阶段,有学者提出了旨在提高召回率并兼顾准确率的词语粗分模型——基于N-最短路径方法的汉语词语粗分模型。这一模型的基本思想是:根据词典,找出字串中所有可能的词,构造词语切分有向无环图。每个词对应图中的一条有向边,并赋给相应的边长(权值)。然后针对该切分图,在起点到终点的所有路径中,求出长度值按严格升序排列(任何两个不同位置上的值一定不等,下同)依次为第1、第2、…、第i、…、第N(N≥1)的路径集合作为相应的粗分结果集。
这种方法的过程可以简单概括为两步。一是根据字串中所有可能的词构建有向无环图;二是根据最短路径算法,求出此图的前N个最短路径集合。
下面介绍构建有向无环图的过程:设待分字串S=c_1c_2...c_n,其中,c_i(i=1,2,…,n)为单个的汉字,n为字串的长度,n≥1。建立一个结点数为n+1的切分有向无环图G,各结点编号依次为V0,V1,...,Vn,通过以下两步建立G所有可能的词边:
(1)相邻结点Vk-1,Vk(1≤k≤n)之间建立有向边Vk-1,Vk,边的长度值为Lk,边对应的词默认为c_k(k=1,2,…,n)。
(2)如果w=c_i c_i+1...c_j(0<i<j≤n)是词表中的词,则结点Vi-1,Vi之间建立有向边Vi-1,Vj,边的长度值为Lw,边对应的词为w。
这样,待分字串S中包含的所有词与切分有向无环图G中的边一一对应,如图3所示。
图 3 切分有向无环图
根据所构建的有向无环图边上权重的不同,此方法还分为非统计粗分模型和统计粗分模型两种。非统计粗分模型即假定切分有向无环图所有词的权重都是对等的,即每个词对应的边长均设为1。
接下来是求解有向无环图的前N个最短路径集合,具体的求解算法基于求解单源最短路径问题的Dijkstra算法,改进之处在于:每个结点处记录N个最短路径值,并记录相应路径上当前结点的前驱。如果同一长度对应多条路径,必须同时记录这些路径上当前结点的前驱,最后通过回溯即可求出最短路径集合。现仍以“他说的确实在理”为例,选择非统计粗分模型构建有向无环图,说明求解N-最短路径集合的过程(N=3):
图 4 句子“他说的确实在理”的求解过程(N=3)
图4中,虚线是回溯出的是第一条最短路径,对应的粗分结果为:“他/说/的/确实/在理/”,Table(2),Table(3)… Table(7)分别为结点2、3、…、7对应的信息记录表,Table(0)、Table(1)的信息记录表没有给出。每个结点的信息记录表里的编号为路径不同长度的编号,按由小到大的顺序排列,编号最大不超过N。如Table(5)表示从结点0出发到达结点5有两条长度为4的路径(分别为0-1-2-4-5和0-1-2-3-5)和一条长度为5的路径(0-1-2-3-4-5)。前驱(i, j)表示沿着当前路径到达当前结点的最后一条边的出发结点为i,即当前结点的前一个结点为i,相应的边为结点i的信息记录表中编号为j的路径。如果j=0,表示没有其他候选的路径。如结点7对应的信息记录表Table(7)中编号为1的路径前驱(5,1)表示前一条边为结点5的信息表中第1条路径。类似地,Table(5)中的前驱(3,1)表示前驱为结点3的信息记录表中的第1条路径。Table(3)中的(2,0)表示前驱边的出发点为结点2,没有其他候选路径。信息记录表为系统回溯找出所有可选路径提供了依据。
上例采用的是非统计粗分模型,边长的权重都为1。但随着字串长度n和最短路径数N的增大,长度相同的路径数急剧增加,同时粗切分结果数量必然上升,此时就失去了分词的意义。下面介绍的统计粗分模型,为每条边设置了不同的权值,就能够避免这种情况,得到更好的分词效果。
假定一个词串W经过信道传送,由于噪声干扰而丢失了词界的切分标志,到输出端便成了汉字串C。N-最短路径方法词语粗分模型可以相应地改进为:求N个候选切分W,使概率P(W|C)为前N个最大值:
其中,P(C)汉字串的概率,它是一个常数,不必考虑。从词串恢复到汉字串的概率P(C|W)=1(只有唯一的一种方式)。因此,粗分的目标就是确定P(W)最大的N种切分结果。为了简化计算,张华平等人采用一元统计模型。假设W=w_1w_2...w_m是字串S=c_1c_2...c_n的一种切分结果。wi是一个词,P(wi)表示词wi出现的概率,在大规模语料训练的基础上通过最大似然估计方法求得。切分W的概率为:
为了处理方便,令:
这样,-InP(wi)就可以看作是词在切分有向无环图中对应的边长(做适当的数据平滑处理)。
针对修改了边长后的切分有向无环图,直接使用非统计粗分模型的求解算法,就可以获得问题的最终解。
2.基于词的n元语法模型的分词方法
回到我们介绍的第一类方法中所举的例子,对于分词结果“他/说/的/确实/在理”(逆向匹配)“他说/的确/实在/理”(正向匹配),我们很容易判断出正向匹配的结果不是我们要的。大多数人判断的依据可能是:“他说/的确/实在/理”这种说法在日常生活中很少或是没有人用,毕竟这样的句子说出来太奇怪,也无法理解其中的意思。那么以分词算法的角度来看,对于某个句子的若干种分词结果,我们能否根据它们的出现概率来判断哪种结果是最合理的?例如:若P(“他/说/的/确实/在理”)>P(他说/的确/实在/理),那么分词结果就是“他/说/的/确实/在理”。
具体的做法是,首先根据词典(可以是从训练语料中抽取出来的词典,也可以是外部词典)对句子进行简单匹配,找出所有可能的词典词,然后,将它们和所有单个字作为结点,构造的n元的切分词图,图中的结点表示可能的词候选,边表示路径,边上的n元概率表示代价,最后利用相关搜索算法(如Viterbi算法)从图中找到代价最小的路径作为最后的分词结果。
《统计自然语言处理》中以“研究生物学”为例,给出了基于二元文法的切分词图如图5所示。
图 5 基于词的生成式模型的二元文法切分词图
三、基于机器学习的分词方法
我们可以用{B:begin, M:middle, E:end, S:single}这4个类别来标注一个分词样本中每个字所属的类别,其中B代表该字是词语中的起始字,M代表是词语中的中间字,E代表是词语中的结束字,S则代表是单字成词。例如“他说的确实在理”,我们可以标注成“他/S说/S的/S确/B实/E在/B理/E”;“研究生物学”,可以标注成“研/B究/E生/B物/M学/E”。这样,中文分词问题就转化为一个序列标注问题,即一个考虑上下文的字分类问题。我们可以先通过带标签的分词语料来训练一个序列标注模型,再用这个模型对无标签的语料进行分词。以下介绍几种有代表性的模型。
1.隐马尔可夫模型(HMM)
下面是《统计学习方法》(李航)对隐马尔可夫模型对定义:
隐马尔可夫模型是关于时序的概率模型,描述由一个隐藏的马尔可夫链随机生成不可观测的状态随机序列,再由各个状态生成一个观测从而产生观测随机序列的过程。隐藏的马尔可夫链随机生成的状态的序列,称为状态序列( state sequence ) ;每个状态生成一个观测,而由此产生的观测的随机序列,称为观测序列( observation sequence )。序列的每个位置又可以看作是一个时刻。
仍以“他说的确实在理”为例,“他说的确实在理”是我们能够直接看到到序列,即是观测序列;而此例的标注“SSSBEBE”,是我们无法之间看到的,即状态序列。HMM模型的作用就是完成观测序列到状态序列的转换。
将待处理的文本记作λ=λ_1λ_2...λ_n,n代表句子长度,表示字。将输出的标签记作о=о_1о_2...о_n。此时我们理想的输出为P(о|λ),通过贝叶斯公式可得:
λ为给定的输入,因此P(λ)计算为常数,可以忽略,因此最大化P(о|λ)等价于最大化 P(λ|о)P(о)。
为了简化上式子的计算,人们引入两个假说:
(1)观测独立性假设:每个字的输出仅仅与当前字有关,即每个λ的值只依赖于其对应的о值,即:
(2)齐次马尔可夫假设:每个输出仅仅与上一个输出有关,即оi的值只依赖于оi-1,即:
综合以上式子,我们可得:
在HMM中,将称为观测概率P(λ_k|о_k),P(о_k|о_k-1)称为转移概率。通过设置某些P(о_k|о_k-1)=0 ,可以排除类似BBB、EM等不合理的组合。
最后,求解最大化 P(λ|о)P(о)的常用方法是Veterbi算法。它是一种动态规划方法,核心思想是:如果最终的最优路径经过某个о_k,那么从初始节点到о_k-1,点的路径必然也是一个最优路径。
2.条件随机场 (CRF)
在一个隐马尔可夫模型中,以x_1,x_2,...,x_n表示观测序列,以y_1,y_2,...,y_n表示隐含的状态序列,那么x_i只取决于产生它的状态y_i,和前后状态y_i-1,y_i+1都无关,如图6所示。
图 6 在HMM模型中,输出只与状态有关
但显然很多应用里观察值可能和前后的状态都有关,如果把x_i和y_i-1,y_i,y_i+1都考虑进来,对应的模型如图7所示。
图 7 一个普遍意义的条件随机场
这个模型就是条件随机场。
CRF是一个概率无向图模型,它和HMM很类似,但是CRF没有隐变量,并且是一个判别模型。使用CRF计算序列中的每个字位x_i对应的分词标签y_i时,都可以看做是一次考虑上下文依赖关系的分类。
隐马模型存在假设输出独立性的缺点,导致其不能将上下文纳入特征设计,大大限制了特征的可用范围。CRF则没有这个限制,它不对单独的节点进行归一化,而是对所有特征进行全局归一化,进而全局的最优值。因此,在分词问题上,显然作为判别式模型的CRF相比HMM更具优越性。
CRF通过定义条件概率P(Y∣X) 来描述模型。
Z(x)就是概率图模型中的配分函数,目的就是提供一个归一化因子,将各个类别的值求和,为计算每个类别的概率提供一个分母。k为设计的特征(函数)的数量,w_k为每个特征函数待学习的权重。
与HMM一样,训练CRF中的参数依然是通过极大似然估计,具体算法形式如梯度下降法、IIS、拟牛顿法等。训练好CRF分词模型后,可以通过Viterbi算法来进行全局的推理,从而得到最优的分词序列。
3.神经网络分词算法
对于序列标注任务,公认效果最好的模型是BiLSTM+CRF。
前文我们提到,解决中文分词歧义切分问题最好的途径就是考虑上下文信息,基于词的n元语法模型的分词方法就是用到了这种思想。但n-gram语言模型也只能考虑一定范围内的上下文信息。为了得到更好的解决歧义方案,我们应当尽可能多的利用上下文信息,而LSTM(长短期记忆模型)能够很好的做到这一点。
长短期记忆(Long short-term memory, LSTM)是一种特殊的RNN(循环神经网络),主要是为了解决长序列训练过程中的梯度消失和梯度爆炸问题。简单来说,就是相比普通的RNN,LSTM能够在更长的序列中有更好的表现。LSTM结构和普通RNN的主要输入输出区别如图8所示。
图 8 LSTM和普通RNN的输入输出区别
相比RNN只有一个传递状态h_t,LSTM有两个传输状态,一个c_t(cell state),和一个h_t(hidden state)。(注:RNN中的h_t对于LSTM中的c_t) 其中对于传递下去的c_t改变得很慢,通常输出的是上一个状态传过来的c_t-1加上一些数值。而h_t则在不同节点下往往会有很大的区别。
LSTM中对当前输入x_t和上一个状态传递下来的h_t-1拼接训练得到四个状态:
其中z_f,z_i,z_o是由拼接向量乘以权重矩阵之后,再通过一个sigmoid激活函数转换成0到1之间的数值,来作为一种门控状态。而z则是将结果通过一个tanh激活函数将转换成-1到1之间的值(这里使用tanh是因为这里是将其做为输入数据,而不是门控信号)。
图9是这四个状态在LSTM内部的使用。
图 9 LSTM内部的计算
其中⊙表示操作矩阵中对应的元素相乘,因此要求两个相乘矩阵是同型的。⊕则代表进行矩阵加法。
然后LSTM内部主要有三个阶段:
(1)忘记阶段。这个阶段主要是对上一个节点传进来的输入进行选择性忘记。简单来说就是会 “忘记不重要的,记住重要的”。具体来说是通过计算得到的z_f来作为忘记门控,来控制上一个状态的c_t-1哪些需要留哪些需要忘。
(2)选择记忆阶段。这个阶段将这个阶段的输入x_t有选择性地进行“记忆”。主要是会对输入进行选择记忆。哪些重要则着重记录下来,哪些不重要,则少记一些。当前的输入内容由前面计算得到的z表示。而选择的门控信号则是由z_i来进行控制。
(3)输出阶段。这个阶段将决定哪些将会被当成当前状态的输出。主要是通过z_o来进行控制的。并且还对上一阶段得到的c_o进行了放缩(通过一个tanh激活函数进行变化)。与普通RNN类似,输出y_t往往最终也是通过h_t变化得到。
以上,就是LSTM的内部结构。通过门控状态来控制传输状态,记住需要长时间记忆的,忘记不重要的信息,而不像普通的RNN仅有一种记忆叠加方式。在很多需要“长期记忆”的任务中有很好的效果,因此在中文分词任务中也表现出色。
LSTM是有方向的,为了让每个位置的字分类时既能考虑全部历史信息(左边的所有的字),又能考虑全部未来信息(右边所有的字),我们可以使用双向LSTM(Bi-LSTM)来充当序列标注的骨架模型,如图10所示。
图 10 BiLSTM在时间上的展开
依赖于神经网络强大的非线性拟合能力,理论上我们已经似乎能够学习出不错的模型。但是,上述模型只考虑了标签上的上下文信息。对于序列标注任务来说,当前位置的标签与前一个位置、后一个位置都有潜在的关系。而由分词的标注规则可知,B标签后只能接M和E,仅仅通过BiLSTM+softmax模型,可能会得到“BB”这种错误标注情况。因此人们提出在模型后接一层CRF层,用于在整个序列上学习最优的标签序列。添加CRF层的模型如图11所示。
图 11 BiLSTM+CRF模型图
现状 · 展望
一、分词现状
“中文分词以统计语言模型为基础,经过几十年的发展和完善,今天基本上可以看作是一个解决的问题。当然不同的人做的分词器有好有坏,这里面的差别主要在于数据的使用和工程实现的精度。”
———《数学之美》吴军
在将统计语言模型用于分词以前,分词的准确率较低,可以提升的空间非常大。但当统计语言模型被广泛应用后,不同的分词器产生的结果差异实际上已经远小于不同人之间看法的差异。而后一些结合机器学习的算法在分词方法中应用,更使得分词技术已经日趋完善。
但这并不表明所有的分词器效果都是一样的,更不能忽略对分词方案的选择。针对具体的应用领域,会存在一种分词方案优于另一种方案的情况,此时我们应当根据实际环境选定合适的分词技术。举例来说,在中文分词中我们会面对词粒度规范的选择问题:应当选择多大的粒度进行分词?这时就应该针对具体应用领域来分析选定方案。例如,在机器翻译中,粒度大的方案要更好一些:“联想公司”作为一个整体,很容易找出对应的英文翻译“Lenovo”,若分为“联想/公司”,会首先是“联想”的意思,可能翻译失败;在网页搜索中,粒度小的方案要更好一些:“清华大学”如果作为一个词时,用户查询“清华”时,是找不到“清华大学”的。
另外,目前常见的分词器都是使用机器学习算法和词典相结合的方式,这也是主流的做法。一方面,先进的算法能够提高分词准确率;另一方面,特定领域的字典能够改善领域适应性,减少OOV问题对分词结果的影响。
二、展望
随着深度学习时代数据量和算力的爆炸式增长,自然语言处理的很多传统方法被颠覆。《Is Word Segmentation Necessary for Deep Learning of Chinese Representations》这篇论文就试图探讨“基于深度学习神经网络框架下的NLP任务中,到底是“字”好还是“词”好?分词是否还有存在的必要?”的问题。这篇文章通过四个中文NLP任务实验(语言建模、机器翻译、文本分类和句子匹配),验证了在效果上“字”级别模型普遍优于“词”级别模型。通过分析,同时作者认为“词”级别模型的欠佳表现可以归结为数据稀疏、OOV问题、过拟合与数据集迁移能力缺乏等原因。
有兴趣的读者可以阅读论文原文(https://arxiv.org/pdf/1905.05526.pdf),
或是参考相关的中文博客介绍(https://zhuanlan.zhihu.com/p/65865071)
中文分词 · 工具
根据 GitHub 上的 star 数:
1.jieba分词:https://github.com/fxsjy/jieba
2.HanLP:https://github.com/hankcs/HanLP
3.Stanford CoreNLP:
https://github.com/stanfordnlp/CoreNLP
4.Ansj中文分词:
https://github.com/NLPchina/ansj_seg
5.pkuseg:
https://github.com/lancopku/pkuseg-python
6.SnowNLP:https://github.com/isnowfy/snownlp
7.LTP:https://github.com/HIT-SCIR/ltp
8.THULAC:https://github.com/thunlp/THULAC-Python
参考文献
[1]统计学习方法[M].清华大学出版社,2012.
[2]统计自然语言处理(第2版)[M].清华大学出版社,2013:570.
[3]数学之美[M].人民邮电出版社,2014:312.
[4]Huang Z, Xu W, Yu K. Bidirectional LSTM-CRF Models for Sequence Tagging[J]. Computer Science, 2015.
参考资料
[1]https://juejin.im/post/6844903721281781767#heading-1
[2]https://blog.csdn.net/hecongqing/article/details/104548816
[3]https://www.jianshu.com/p/5fea8f42caa9
[4]https://zhuanlan.zhihu.com/p/32085405
[5]https://cloud.tencent.com/developer/article/1437821
[6]https://easyai.tech/ai-definition/tokenization/
[7]https://zhuanlan.zhihu.com/p/65865071
插图来源
图1 源自《信息处理用现代汉语分词规范》
图2 源自
https://juejin.im/post/6844903721281781767#heading-1
图3 源自《统计自然语言处理》
图4 源自《统计自然语言处理》
图5 源自《统计自然语言处理》
图6 源自《数学之美》
图7 源自《数学之美》
图8 源自
https://zhuanlan.zhihu.com/p/32085405
图9 源自
https://zhuanlan.zhihu.com/p/32085405
图10源自
https://www.jianshu.com/p/5fea8f42caa9
图11源自
https://www.jianshu.com/p/5fea8f42caa9