Commit d9a9cad2 by 20200519065

Initial commit

parents
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 第一次小作业: 机器学习中的优化\n",
"本次作业主要用来练习逻辑回归相关的优化问题。通过完成作业,你讲会学到: 1. 逻辑回归的梯度下降法推导 2. 如何判断逻辑回归目标函数为凸函数。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"假设我们有训练数据$D=\\{(\\mathbf{x}_1,y_1),...,(\\mathbf{x}_n,y_n)\\}$, 其中$(\\mathbf{x}_i,y_i)$为每一个样本,而且$\\mathbf{x}_i$是样本的特征并且$\\mathbf{x}_i\\in \\mathcal{R}^D$, $y_i$代表样本数据的标签(label), 取值为$0$或者$1$. 在逻辑回归中,模型的参数为$(\\mathbf{w},b)$。对于向量,我们一般用粗体来表达。 为了后续推导的方便,可以把b融入到参数w中。 这是参数$w$就变成 $w=(w_0, w_1, .., w_D)$,也就是前面多出了一个项$w_0$, 可以看作是b,这时候每一个$x_i$也需要稍作改变可以写成 $x_i = [1, x_i]$,前面加了一个1。稍做思考应该能看出为什么可以这么写。\n",
"\n",
"请回答以下问题。请用Markdown自带的Latex来编写。\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (a) ```编写逻辑回归的目标函数```\n",
"请写出目标函数(objective function), 也就是我们需要\"最小化\"的目标(也称之为损失函数或者loss function),不需要考虑正则。 把目标函数表示成最小化的形态,另外把$\\prod_{}^{}$转换成$\\log \\sum_{}^{}$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$L(w)=$ $argmin_{w,b}-\\sum_{i=1}^n y_i\\log \\sigma(w^{T}x_i+b)+(1-y_i)\\log[1-\\sigma(w^{T}x_i+b)]$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (b) ```求解对w的一阶导数```\n",
"为了做梯度下降法,我们需要对参数$w$求导,请把$L(w)$对$w$的梯度计算一下:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\frac{\\partial L(w)}{\\partial w}=$ $\\sum_{i=1}^n[\\sigma(w^{T}x_i+b)-y_i]x_i$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (c) ```求解对w的二阶导数```\n",
"在上面结果的基础上对$w$求解二阶导数,也就是再求一次导数。 这个过程需要回忆一下线性代数的部分 ^^。 参考: matrix cookbook: https://www.math.uwaterloo.ca/~hwolkowi/matrixcookbook.pdf, 还有 Hessian Matrix。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\frac{\\partial^2 L(w)}{\\partial^2 w}=$ $\\sum_{i=1}^n \\frac{x_{i,k}\\cdot x_{i,j}\\cdot e^{-w^{T}x_i}}{(1+e^{-w^{T}x_i})^2} = \\sum_{i=1}^n x_{i,k}\\cdot x_{i,j}\\cdot \\sigma_i(1-\\sigma_i)$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (d) ```证明逻辑回归目标函数是凸函数```\n",
"试着证明逻辑回归函数是凸函数。假设一个函数是凸函数,我们则可以得出局部最优解即为全局最优解,所以假设我们通过随机梯度下降法等手段找到最优解时我们就可以确认这个解就是全局最优解。证明凸函数的方法有很多种,在这里我们介绍一种方法,就是基于二次求导大于等于0。比如给定一个函数$f(x)=x^2-3x+3$,做两次\n",
"求导之后即可以得出$f''(x)=2 > 0$,所以这个函数就是凸函数。类似的,这种理论也应用于多元变量中的函数上。在多元函数上,只要证明二阶导数是posititive semidefinite即可以。 问题(c)的结果是一个矩阵。 为了证明这个矩阵(假设为H)为Positive Semidefinite,需要证明对于任意一个非零向量$v\\in \\mathcal{R}$, 需要得出$v^{T}Hv >=0$\n",
"请写出详细的推导过程:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO 请写下推导过程\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since $H_{i,j} = \\sum_{i=1}^n x_{i,k}\\cdot x_{i,j}\\cdot \\sigma_i(1-\\sigma_i)$ \n",
"Let X= $\\left[\\begin{array}{cccc}\n",
"x_{1,0} & x_{1,1} & \\dots & x_{1, D} \\\\\n",
"x_{2,0} & x_{2,1} & \\dots & x_{2, D} \\\\\n",
"\\dots & \\\\\n",
"x_{n, D} & x_{n, 1} & \\dots & x_{n, D}\n",
"\\end{array}\\right]$, $A = \\left[\\begin{array}{cccc}\n",
"\\sigma_{1}\\left(1-\\sigma_{1}\\right) & 0 & \\dots & 0 \\\\\n",
"0 & \\sigma_{2}\\left(1-\\sigma_{2}\\right) & \\dots & 0 \\\\\n",
"\\dots & & \\\\\n",
"0 & 0 & \\dots & \\sigma_{n}\\left(1-\\sigma_{n}\\right)\n",
"\\end{array}\\right]$, \n",
"then we have $H = X^{T}\\cdot A \\cdot X$\n",
"It follows that $v^{T}Hv = v^{T}X^{T}AXv = (Xv)^{T}A(Xv)$. \n",
"Let $P = Xv$, then we have $H = P^{T}AP$. \n",
"Since $\\sigma_{i}=\\frac{1}{1+e^{-\\mathbf{w}^{\\mathrm{T}} \\cdot \\mathbf{x}_{\\mathbf{i}}}}$, $A$ is obviously positive. Hence, matrix H is positive semidefinite. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 第一次小作业: 机器学习中的优化\n",
"本次作业主要用来练习逻辑回归相关的优化问题。通过完成作业,你讲会学到: 1. 逻辑回归的梯度下降法推导 2. 如何判断逻辑回归目标函数为凸函数。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"假设我们有训练数据$D=\\{(\\mathbf{x}_1,y_1),...,(\\mathbf{x}_n,y_n)\\}$, 其中$(\\mathbf{x}_i,y_i)$为每一个样本,而且$\\mathbf{x}_i$是样本的特征并且$\\mathbf{x}_i\\in \\mathcal{R}^D$, $y_i$代表样本数据的标签(label), 取值为$0$或者$1$. 在逻辑回归中,模型的参数为$(\\mathbf{w},b)$。对于向量,我们一般用粗体来表达。 为了后续推导的方便,可以把b融入到参数w中。 这是参数$w$就变成 $w=(w_0, w_1, .., w_D)$,也就是前面多出了一个项$w_0$, 可以看作是b,这时候每一个$x_i$也需要稍作改变可以写成 $x_i = [1, x_i]$,前面加了一个1。稍做思考应该能看出为什么可以这么写。\n",
"\n",
"请回答以下问题。请用Markdown自带的Latex来编写。\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (a) ```编写逻辑回归的目标函数```\n",
"请写出目标函数(objective function), 也就是我们需要\"最小化\"的目标(也称之为损失函数或者loss function),不需要考虑正则。 把目标函数表示成最小化的形态,另外把$\\prod_{}^{}$转换成$\\log \\sum_{}^{}$\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$L(w)=$ $argmin_{w,b}-\\sum_{i=1}^n y_i\\log \\sigma(w^{T}x_i+b)+(1-y_i)\\log[1-\\sigma(w^{T}x_i+b)]$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (b) ```求解对w的一阶导数```\n",
"为了做梯度下降法,我们需要对参数$w$求导,请把$L(w)$对$w$的梯度计算一下:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\frac{\\partial L(w)}{\\partial w}=$ $\\sum_{i=1}^n[\\sigma(w^{T}x_i+b)-y_i]x_i$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (c) ```求解对w的二阶导数```\n",
"在上面结果的基础上对$w$求解二阶导数,也就是再求一次导数。 这个过程需要回忆一下线性代数的部分 ^^。 参考: matrix cookbook: https://www.math.uwaterloo.ca/~hwolkowi/matrixcookbook.pdf, 还有 Hessian Matrix。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$\\frac{\\partial^2 L(w)}{\\partial^2 w}=$ $\\sum_{i=1}^n \\frac{x_{i,k}\\cdot x_{i,j}\\cdot e^{-w^{T}x_i}}{(1+e^{-w^{T}x_i})^2} = \\sum_{i=1}^n x_{i,k}\\cdot x_{i,j}\\cdot \\sigma_i(1-\\sigma_i)$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### (d) ```证明逻辑回归目标函数是凸函数```\n",
"试着证明逻辑回归函数是凸函数。假设一个函数是凸函数,我们则可以得出局部最优解即为全局最优解,所以假设我们通过随机梯度下降法等手段找到最优解时我们就可以确认这个解就是全局最优解。证明凸函数的方法有很多种,在这里我们介绍一种方法,就是基于二次求导大于等于0。比如给定一个函数$f(x)=x^2-3x+3$,做两次\n",
"求导之后即可以得出$f''(x)=2 > 0$,所以这个函数就是凸函数。类似的,这种理论也应用于多元变量中的函数上。在多元函数上,只要证明二阶导数是posititive semidefinite即可以。 问题(c)的结果是一个矩阵。 为了证明这个矩阵(假设为H)为Positive Semidefinite,需要证明对于任意一个非零向量$v\\in \\mathcal{R}$, 需要得出$v^{T}Hv >=0$\n",
"请写出详细的推导过程:"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO 请写下推导过程\n",
"\n",
"\n",
"\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Since $H_{i,j} = \\sum_{i=1}^n x_{i,k}\\cdot x_{i,j}\\cdot \\sigma_i(1-\\sigma_i)$ \n",
"Let X= $\\left[\\begin{array}{cccc}\n",
"x_{1,0} & x_{1,1} & \\dots & x_{1, D} \\\\\n",
"x_{2,0} & x_{2,1} & \\dots & x_{2, D} \\\\\n",
"\\dots & \\\\\n",
"x_{n, D} & x_{n, 1} & \\dots & x_{n, D}\n",
"\\end{array}\\right]$, $A = \\left[\\begin{array}{cccc}\n",
"\\sigma_{1}\\left(1-\\sigma_{1}\\right) & 0 & \\dots & 0 \\\\\n",
"0 & \\sigma_{2}\\left(1-\\sigma_{2}\\right) & \\dots & 0 \\\\\n",
"\\dots & & \\\\\n",
"0 & 0 & \\dots & \\sigma_{n}\\left(1-\\sigma_{n}\\right)\n",
"\\end{array}\\right]$, \n",
"then we have $H = X^{T}\\cdot A \\cdot X$\n",
"It follows that $v^{T}Hv = v^{T}X^{T}AXv = (Xv)^{T}A(Xv)$. \n",
"Let $P = Xv$, then we have $H = P^{T}AP$. \n",
"Since $\\sigma_{i}=\\frac{1}{1+e^{-\\mathbf{w}^{\\mathrm{T}} \\cdot \\mathbf{x}_{\\mathbf{i}}}}$, $A$ is obviously positive. Hence, matrix H is positive semidefinite. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 线性规划与Word Mover's Distance"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"WMD在文本分析领域算作是一个比较经典的算法,它可以用来计算两个文本之间的相似度。 比如问答系统中,可以判断一个用户的query跟哪一个知识库里的问题最相近。而且,计算两个文本之间的相似度这个问题是NLP的核心,这也是为什么文本相似度计算这么重要的原因。 \n",
"\n",
"背景: 在文本相似度匹配问题上如果使用tf-idf等模型,那这时候假如两个文本中没有出现共同的单词,则计算出来的相似度为0,但我们知道实际上很多时候单词可能不一样,但表示的内容确是类似的。 比如 ”People like this car“, \"Those guys enjoy driving that\", 虽然没有任何一样的单词,意思确是类似的。 这是WMD算法提出来的初衷。\n",
"\n",
"WMD作为文本相似度计算的一种方法,最早由Matt J. Kusner, Yu Sun, Nicholas I. Kolkin, Kilian Q. Weinberger等人提出。但实际上它的想法极其简单,可以认为是Transportation Problem用在了词向量上, 其核心是线性规划。 对于Transportation问题在课上已经讲过,仍不清楚的朋友可以回顾一下课程的内容。 \n",
"\n",
"在Section B里我们需要做两件事情: 1. 实现WMD算法来计算两个字符串之间的距离。 2. WMD的拓展方案"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1. WMD算法的实现\n",
"具体算法的实现是基于线性规划问题,细节请参考WMD的论文。 核心思想是把第一个句子转换成第二个句子过程中需要花费的最小cost。 \n",
"\n",
"<img src=\"picture1.png\" alt=\"drawing\" width=\"600\"/>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"线性规划问题即可以写成如下形式:\n",
"\n",
"<img src=\"picture2.png\" alt=\"drawing\" width=\"500\"/>\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里的参数是$T_{ij}$, 需要通过LP Solver去解决。$c(i,j)$指的是两个单词之间的距离, $c_{i,j}=||x_i-x_j||_2$。 参考: $||x||_2=\\sqrt{x_1^2+...+x_d^2}$\n",
"\n",
"为了实现WMD算法,首先需要词向量。 在这里,我们就不自己去训练了,直接使用已经训练好的词向量。 \n",
"请下载训练好的Glove向量:https://nlp.stanford.edu/projects/glove/, 下载其中的 glove.6B.zip, 并使用d=100维的向量。 由于文件较大,需要一些时间来下载。 \n",
"\n",
"请注意:提交作业时不要上传此文件, 但文件路径请使用我们给定的路径,不要改变。 "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#构建word embedding \n",
"def load_embedding():\n",
" w2v = {}\n",
" glovefile = open(\"glove.6B.100d.txt\",\"r\",encoding=\"utf-8\") \n",
" for i, each_line in enumerate(glovefile):\n",
" each_wc = each_line.strip().split(' ')\n",
" w2v[each_wc[0]] = np.array([float(i) for i in each_wc[1:]])\n",
" return w2v"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# 计算两个向量的欧式距离\n",
"def word_distance(emb1, emb2):\n",
" temp = [emb1[i]-emb2[i] for i in range(len(emb1))]\n",
" distance = np.linalg.norm(temp)\n",
" return distance"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"#记录词频\n",
"def word_count(segment):\n",
" word_fre = {}\n",
" for word in segment:\n",
" word_fre[word] = 1.0 + word_fre.get(word,0)\n",
" return word_fre"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# TODO: 编写WMD函数来计算两个句子之间的相似度\n",
"from cvxopt import matrix,solvers\n",
"\n",
"def WMD (sent1, sent2):\n",
" \"\"\"\n",
" 这是主要的函数模块。参数sent1是第一个句子, 参数sent2是第二个句子,可以认为没有经过分词。\n",
" 在英文里,用空格作为分词符号。\n",
" \n",
" 在实现WMD算法的时候,需要用到LP Solver用来解决Transportation proboem. 请使用http://cvxopt.org/examples/tutorial/lp.html\n",
" 也可以参考blog: https://scaron.info/blog/linear-programming-in-python-with-cvxopt.html\n",
" \n",
" 需要做的事情为:\n",
" \n",
" 1. 对句子做分词: 调用 .split() 函数即可\n",
" 2. 获取每个单词的词向量。这需要读取文件之后构建embedding matrix. \n",
" 3. 构建lp问题,并用solver解决\n",
" \n",
" 可以自行定义其他的函数,但务必不要改写WMD函数名。测试时保证WMD函数能够正确运行。\n",
" \"\"\" \n",
" #分词\n",
" seg1 = sent1.strip().split() \n",
" seg2 = sent2.strip().split() \n",
" \n",
" # 统计词频\n",
" word_fre1 = word_count(seg1)\n",
" word_fre2 = word_count(seg2)\n",
" \n",
" # 将分词转为词向量\n",
" emb1 = [w2v[word] for word in word_fre1.keys()]\n",
" emb2 = [w2v[word] for word in word_fre2.keys()]\n",
" \n",
" #计算句子长度\n",
" len1 = len(emb1)\n",
" len2 = len(emb2)\n",
" \n",
" # 获得两个句子之间的词汇距离ci,j,存储在二维数组中\n",
" c_ij = []\n",
" for i in range(len1):\n",
" for j in range(len2):\n",
" c_ij.append(word_distance(emb1[i], emb2[j]))\n",
" \n",
" # 建立A矩阵\n",
" a = []\n",
" # 句子1对应到句子2部分\n",
" a0 = [0.0]*len2\n",
" a1 = [1.0]*len2\n",
" a = []\n",
" for i in np.eye(len1):\n",
" a_temp = []\n",
" for j in i:\n",
" if j == 1:\n",
" a_temp.extend(a1)\n",
" if j == 0:\n",
" a_temp.extend(a0)\n",
" a.append(a_temp)\n",
" # 句子2对应到句子1\n",
" for i in range(len2):\n",
" a_temp = [0.0]*len2\n",
" a_temp[i] = 1.0\n",
" a.append(a_temp*len1)\n",
" \n",
" # 获得出入量之和 \n",
" b = [i / len(seg1) for i in list(word_fre1.values())] + \\\n",
" [i / len(seg2) for i in list(word_fre2.values())]\n",
" \n",
" # 线性规划问题\n",
" A_matrix = matrix(a).trans()\n",
" b_matrix = matrix(b)\n",
" c_matrix = matrix(c_ij)\n",
" num_of_T = len(c_ij)\n",
" G = matrix(-np.eye(num_of_T))\n",
" h = matrix(np.zeros(num_of_T))\n",
" \n",
" sol = solvers.lp(c_matrix, G, h, A=A_matrix, b=b_matrix, solver='glpk')\n",
" \n",
" return sol['primal objective'] #wmd_dist\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"读取成功\n"
]
}
],
"source": [
"#加载词向量\n",
"w2v = load_embedding()\n",
"print('读取成功')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"4.271249445939769"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sent1 = \"people like this car\"\n",
"sent2 = \"those guys enjoy driving that\"\n",
"WMD (sent1, sent2)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5.208708323787745\n",
"5.868833973452187\n"
]
}
],
"source": [
"## TODO: 自己写至少4个Test cases来测试一下。 比如 print (WMD(\"people like this car\", \"those guys enjoy driving that\"))\n",
"## \n",
"sent1 = \"boy like eat apple\"\n",
"sent2 = \"he want some fruit\"\n",
"sent3 = \"a dog dive into water\"\n",
"print(WMD(sent1, sent2))\n",
"print(WMD(sent1, sent3))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.271249445939769\n",
"5.558712147227374\n"
]
}
],
"source": [
"sent1 = \"people like this car\"\n",
"sent2 = \"those guys enjoy driving that\"\n",
"sent3 = \"i am studying the course of math\"\n",
"print(WMD(sent1, sent2))\n",
"print(WMD(sent1, sent3))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2. WMD算法的拓展\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 2.1 从欧式距离到Mahalanobis距离\n",
"WMD算法本身不需要任何的标注好的数据,所以它属于无监督学习。 而且在上述的WMD算法里使用的是欧式距离,$c(i,j)=||x_i-x_j||_2$, 那这种距离有什么缺点呢? 其中一个缺点是欧式距离的计算把一个空间里的每一个维度都看成了同样的权重,也就是每一个维度的重要性都是一致的,而且不同维度之间的相关性也没有考虑进来。如果想把这些信息考虑进来,我们则可以使用一个改进版的距离计算叫做Mahalanobis Distance, 距离计算变成 $c(i,j)=(x_i-x_j)^{\\top}M(x_i-x_j)$。\n",
"\n",
"这如何去理解呢? Mahalanobis distance可以理解成: 首先我们对原始空间里的样本做了一层线性的转换, 然后在转换后的空间里计算欧式距离。 我们把这个过程写一下: 原始空间里的点为 $x_i$, 然后我们定义一个转换矩阵 $L$, 这时候就可以得到 $||Lx_i - Lx_j||_2^2=||L(x_i-x_j)||_2^2=(L(x_i-x_j))^{\\top}L(x_i-x_j)=(x_i-x_j)^{\\top}L^{\\top}L(x_i-x_j)=(x_i-x_j)^{\\top}M(x_i-x_j)$, 相当于把$L^{\\top}L$看做是矩阵$M$。这时候很容易看出来矩阵$M$是PSD(positive semidefinite). \n",
"\n",
"假设我们定义了这种距离,这里的M如何选择呢? 当然,这是需要学出来的! 那为了学出M, 必须要有标注好的训练数据,也就需要监督学习场景! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 2.2 从无监督学习到监督学习\n",
"\n",
"假如拥有数据集$D={(s_1, y_1),...,(s_n, y_n)}$, 这里每一个$s_i$代表的是一个句子, $y_i$代表的是对应每一个句子的标签(label)。 我们希望使用这个数据来学出M的值。那如何学习呢? 在这个问题上能使用的方法其实比较多,但在这里, 我们采用一个margin-based方法,这一点在SVM里面其实接触过。\n",
"\n",
"具体一点,假如我们手里有三个句子,$s_u, s_v, s_w$, 其中$s_u$和$s_v$是属于同一个类别,$s_w$是属于另一个类别,那这时候从KNN的角度来讲,我们希望$s_u, s_v$的距离要小于 $s_u, s_w$之间的距离。 用数学来表示: $d(s_u, s_v) < d(s_u, s_w)$, $~~d(.,.)$表示两个文本之间的距离。 其实我们希望它们之间的距离越大越好,也就是所谓的完全区间越宽越好。 但实际上,这个距离太大也没有什么意义,所以我们就干脆指定一个参数 $\\eta$来表示margin, 也就是只要它俩之间的距离大于这个margin就可以。如果小于margin就给他们一些惩罚(penalty),这一点跟SVM极其相似(slack variable)。所以从这个角度SVM也叫做margin-based classifier. \n",
"\n",
"把上述的表示成数学的话: $d(s_u, s_v) + \\eta < d(s_u, s_k)$, 但如果这个式子不成立的话就可以认为产生了penalty。 所以这部分就可以表示成大家熟悉的hinge loss: $max (0, d(s_u, s_v) + \\eta - d(s_u, s_k))$。 另外,我们同时也希望如果两个样本属于同一个类别, 那它俩的距离也比较相近。所以目标函数可以分为两个部分: 1. 同类型的样本距离尽量要近 2. 不同类型的样本距离尽量远一些。 \n",
"\n",
"当我们把所有的样本以及他们之间的大小关系考虑进来之后就可以得到最终的目标函数。 \n",
"\n",
"\\begin{equation}\n",
"L = \\lambda \\sum_{u=1}^{n}\\sum_{v\\in pos(u)}d(s_u, s_v) + (1-\\lambda)\\sum_{u=1}^{n}\\sum_{v\\in pos(u)}^{}\\sum_{w\\in neg(u)}^{} max (0, d(s_u, s_v) + \\eta - d(s_u, s_w))\n",
"\\end{equation}\n",
"\n",
"这里几个notation: pos(u)代表的是跟样本u属于同一个类别的样本, neg(u)指的是跟样本u属于不同类别的样本。 注意:类别的个数可以大于2, 就是多分类问题。 你也可以参考: http://jmlr.org/papers/volume10/weinberger09a/weinberger09a.pdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在这个式子里,第一部分代表的是让同一类型的样本的距离变小, 第二部分代表的是不同类型的样本之间要扩大距离。 \n",
"\n",
"- #### Q1: 这里$\\lambda$起到什么作用?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO: 你的答案....\n",
"\n",
"调整惩罚力度。如果$\\lambda$比较大,我们就比较注重于减小同类型样本间的距离,即原WMD问题;如果$\\lambda$ 比较小,则$1-\\lambda$比较大,我们对于不同类型样本间距离的惩罚就比较大。\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- #### Q2: 在目标函数里有$\\eta$值,这个值怎么理解? 如果去设定这个值呢?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO: 你的答案 ....\n",
" \n",
"假设以一个样本为中心,半径r内的都和其为一类,半径R以上就是另一类,则 $\\eta = R-r$。这个值可以通过数据集本身的性质设定,通过run不同数值看模型哪个效果比较好。\n",
" \n",
" \n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里的$d_{u,v}$指的是$s_u$和$s_v$之间的距离, 而且这个距离被定义为:\n",
"\n",
"\\begin{equation} d_{u, v}=min_{T\\geq 0}\\sum_{i,j}^{}T_{ij}c(i,j)^u~~~~ s.t. \\sum_{j=1}^{}T_{ij}=d_i^u, ~~\\sum_{i=1}^{}T_{ij}=d_j'^v\\end{equation}\n",
"\n",
"这里 $c(i,j)=(x_i-x_j)^{\\top}M(x_i-x_j)$。 所以是不是可以察觉到这个问题目标函数里既包含了参数$M$也包含了线性规划问题。\n",
"\n",
"- #### Q3: 请试着去理解上述所有的过程,并回答: 优化问题如何解决呢? 请给出解题的思路 (文字适当配合推导过程)。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO 你的答案.... "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对于上述问题,其实我们也可以采用不一样的损失函数来求解M。 一个常用的损失函数叫作 “kNN-LOO error”, 相当于把KNN的准确率转换成了smooth differential loss function. 感兴趣的朋友可以参考: https://papers.nips.cc/paper/6139-supervised-word-movers-distance.pdf\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"以上是优化部分的一个简短的作业,通过这些练习会对优化理论有更清晰的认知。 Good luck for everyone! "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 线性规划与Word Mover's Distance"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"WMD在文本分析领域算作是一个比较经典的算法,它可以用来计算两个文本之间的相似度。 比如问答系统中,可以判断一个用户的query跟哪一个知识库里的问题最相近。而且,计算两个文本之间的相似度这个问题是NLP的核心,这也是为什么文本相似度计算这么重要的原因。 \n",
"\n",
"背景: 在文本相似度匹配问题上如果使用tf-idf等模型,那这时候假如两个文本中没有出现共同的单词,则计算出来的相似度为0,但我们知道实际上很多时候单词可能不一样,但表示的内容确是类似的。 比如 ”People like this car“, \"Those guys enjoy driving that\", 虽然没有任何一样的单词,意思确是类似的。 这是WMD算法提出来的初衷。\n",
"\n",
"WMD作为文本相似度计算的一种方法,最早由Matt J. Kusner, Yu Sun, Nicholas I. Kolkin, Kilian Q. Weinberger等人提出。但实际上它的想法极其简单,可以认为是Transportation Problem用在了词向量上, 其核心是线性规划。 对于Transportation问题在课上已经讲过,仍不清楚的朋友可以回顾一下课程的内容。 \n",
"\n",
"在Section B里我们需要做两件事情: 1. 实现WMD算法来计算两个字符串之间的距离。 2. WMD的拓展方案"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 1. WMD算法的实现\n",
"具体算法的实现是基于线性规划问题,细节请参考WMD的论文。 核心思想是把第一个句子转换成第二个句子过程中需要花费的最小cost。 \n",
"\n",
"<img src=\"picture1.png\" alt=\"drawing\" width=\"600\"/>\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"线性规划问题即可以写成如下形式:\n",
"\n",
"<img src=\"picture2.png\" alt=\"drawing\" width=\"500\"/>\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里的参数是$T_{ij}$, 需要通过LP Solver去解决。$c(i,j)$指的是两个单词之间的距离, $c_{i,j}=||x_i-x_j||_2$。 参考: $||x||_2=\\sqrt{x_1^2+...+x_d^2}$\n",
"\n",
"为了实现WMD算法,首先需要词向量。 在这里,我们就不自己去训练了,直接使用已经训练好的词向量。 \n",
"请下载训练好的Glove向量:https://nlp.stanford.edu/projects/glove/, 下载其中的 glove.6B.zip, 并使用d=100维的向量。 由于文件较大,需要一些时间来下载。 \n",
"\n",
"请注意:提交作业时不要上传此文件, 但文件路径请使用我们给定的路径,不要改变。 "
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#构建word embedding \n",
"def load_embedding():\n",
" w2v = {}\n",
" glovefile = open(\"glove.6B.100d.txt\",\"r\",encoding=\"utf-8\") \n",
" for i, each_line in enumerate(glovefile):\n",
" each_wc = each_line.strip().split(' ')\n",
" w2v[each_wc[0]] = np.array([float(i) for i in each_wc[1:]])\n",
" return w2v"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"# 计算两个向量的欧式距离\n",
"def word_distance(emb1, emb2):\n",
" temp = [emb1[i]-emb2[i] for i in range(len(emb1))]\n",
" distance = np.linalg.norm(temp)\n",
" return distance"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"#记录词频\n",
"def word_count(segment):\n",
" word_fre = {}\n",
" for word in segment:\n",
" word_fre[word] = 1.0 + word_fre.get(word,0)\n",
" return word_fre"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"scrolled": true
},
"outputs": [],
"source": [
"# TODO: 编写WMD函数来计算两个句子之间的相似度\n",
"from cvxopt import matrix,solvers\n",
"\n",
"def WMD (sent1, sent2):\n",
" \"\"\"\n",
" 这是主要的函数模块。参数sent1是第一个句子, 参数sent2是第二个句子,可以认为没有经过分词。\n",
" 在英文里,用空格作为分词符号。\n",
" \n",
" 在实现WMD算法的时候,需要用到LP Solver用来解决Transportation proboem. 请使用http://cvxopt.org/examples/tutorial/lp.html\n",
" 也可以参考blog: https://scaron.info/blog/linear-programming-in-python-with-cvxopt.html\n",
" \n",
" 需要做的事情为:\n",
" \n",
" 1. 对句子做分词: 调用 .split() 函数即可\n",
" 2. 获取每个单词的词向量。这需要读取文件之后构建embedding matrix. \n",
" 3. 构建lp问题,并用solver解决\n",
" \n",
" 可以自行定义其他的函数,但务必不要改写WMD函数名。测试时保证WMD函数能够正确运行。\n",
" \"\"\" \n",
" #分词\n",
" seg1 = sent1.strip().split() \n",
" seg2 = sent2.strip().split() \n",
" \n",
" # 统计词频\n",
" word_fre1 = word_count(seg1)\n",
" word_fre2 = word_count(seg2)\n",
" \n",
" # 将分词转为词向量\n",
" emb1 = [w2v[word] for word in word_fre1.keys()]\n",
" emb2 = [w2v[word] for word in word_fre2.keys()]\n",
" \n",
" #计算句子长度\n",
" len1 = len(emb1)\n",
" len2 = len(emb2)\n",
" \n",
" # 获得两个句子之间的词汇距离ci,j,存储在二维数组中\n",
" c_ij = []\n",
" for i in range(len1):\n",
" for j in range(len2):\n",
" c_ij.append(word_distance(emb1[i], emb2[j]))\n",
" \n",
" # 建立A矩阵\n",
" a = []\n",
" # 句子1对应到句子2部分\n",
" a0 = [0.0]*len2\n",
" a1 = [1.0]*len2\n",
" a = []\n",
" for i in np.eye(len1):\n",
" a_temp = []\n",
" for j in i:\n",
" if j == 1:\n",
" a_temp.extend(a1)\n",
" if j == 0:\n",
" a_temp.extend(a0)\n",
" a.append(a_temp)\n",
" # 句子2对应到句子1\n",
" for i in range(len2):\n",
" a_temp = [0.0]*len2\n",
" a_temp[i] = 1.0\n",
" a.append(a_temp*len1)\n",
" \n",
" # 获得出入量之和 \n",
" b = [i / len(seg1) for i in list(word_fre1.values())] + \\\n",
" [i / len(seg2) for i in list(word_fre2.values())]\n",
" \n",
" # 线性规划问题\n",
" A_matrix = matrix(a).trans()\n",
" b_matrix = matrix(b)\n",
" c_matrix = matrix(c_ij)\n",
" num_of_T = len(c_ij)\n",
" G = matrix(-np.eye(num_of_T))\n",
" h = matrix(np.zeros(num_of_T))\n",
" \n",
" sol = solvers.lp(c_matrix, G, h, A=A_matrix, b=b_matrix, solver='glpk')\n",
" \n",
" return sol['primal objective'] #wmd_dist\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"读取成功\n"
]
}
],
"source": [
"#加载词向量\n",
"w2v = load_embedding()\n",
"print('读取成功')"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"scrolled": true
},
"outputs": [
{
"data": {
"text/plain": [
"4.271249445939769"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"sent1 = \"people like this car\"\n",
"sent2 = \"those guys enjoy driving that\"\n",
"WMD (sent1, sent2)"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"5.208708323787745\n",
"5.868833973452187\n"
]
}
],
"source": [
"## TODO: 自己写至少4个Test cases来测试一下。 比如 print (WMD(\"people like this car\", \"those guys enjoy driving that\"))\n",
"## \n",
"sent1 = \"boy like eat apple\"\n",
"sent2 = \"he want some fruit\"\n",
"sent3 = \"a dog dive into water\"\n",
"print(WMD(sent1, sent2))\n",
"print(WMD(sent1, sent3))"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {
"scrolled": true
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"4.271249445939769\n",
"5.558712147227374\n"
]
}
],
"source": [
"sent1 = \"people like this car\"\n",
"sent2 = \"those guys enjoy driving that\"\n",
"sent3 = \"i am studying the course of math\"\n",
"print(WMD(sent1, sent2))\n",
"print(WMD(sent1, sent3))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 2. WMD算法的拓展\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 2.1 从欧式距离到Mahalanobis距离\n",
"WMD算法本身不需要任何的标注好的数据,所以它属于无监督学习。 而且在上述的WMD算法里使用的是欧式距离,$c(i,j)=||x_i-x_j||_2$, 那这种距离有什么缺点呢? 其中一个缺点是欧式距离的计算把一个空间里的每一个维度都看成了同样的权重,也就是每一个维度的重要性都是一致的,而且不同维度之间的相关性也没有考虑进来。如果想把这些信息考虑进来,我们则可以使用一个改进版的距离计算叫做Mahalanobis Distance, 距离计算变成 $c(i,j)=(x_i-x_j)^{\\top}M(x_i-x_j)$。\n",
"\n",
"这如何去理解呢? Mahalanobis distance可以理解成: 首先我们对原始空间里的样本做了一层线性的转换, 然后在转换后的空间里计算欧式距离。 我们把这个过程写一下: 原始空间里的点为 $x_i$, 然后我们定义一个转换矩阵 $L$, 这时候就可以得到 $||Lx_i - Lx_j||_2^2=||L(x_i-x_j)||_2^2=(L(x_i-x_j))^{\\top}L(x_i-x_j)=(x_i-x_j)^{\\top}L^{\\top}L(x_i-x_j)=(x_i-x_j)^{\\top}M(x_i-x_j)$, 相当于把$L^{\\top}L$看做是矩阵$M$。这时候很容易看出来矩阵$M$是PSD(positive semidefinite). \n",
"\n",
"假设我们定义了这种距离,这里的M如何选择呢? 当然,这是需要学出来的! 那为了学出M, 必须要有标注好的训练数据,也就需要监督学习场景! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"##### 2.2 从无监督学习到监督学习\n",
"\n",
"假如拥有数据集$D={(s_1, y_1),...,(s_n, y_n)}$, 这里每一个$s_i$代表的是一个句子, $y_i$代表的是对应每一个句子的标签(label)。 我们希望使用这个数据来学出M的值。那如何学习呢? 在这个问题上能使用的方法其实比较多,但在这里, 我们采用一个margin-based方法,这一点在SVM里面其实接触过。\n",
"\n",
"具体一点,假如我们手里有三个句子,$s_u, s_v, s_w$, 其中$s_u$和$s_v$是属于同一个类别,$s_w$是属于另一个类别,那这时候从KNN的角度来讲,我们希望$s_u, s_v$的距离要小于 $s_u, s_w$之间的距离。 用数学来表示: $d(s_u, s_v) < d(s_u, s_w)$, $~~d(.,.)$表示两个文本之间的距离。 其实我们希望它们之间的距离越大越好,也就是所谓的完全区间越宽越好。 但实际上,这个距离太大也没有什么意义,所以我们就干脆指定一个参数 $\\eta$来表示margin, 也就是只要它俩之间的距离大于这个margin就可以。如果小于margin就给他们一些惩罚(penalty),这一点跟SVM极其相似(slack variable)。所以从这个角度SVM也叫做margin-based classifier. \n",
"\n",
"把上述的表示成数学的话: $d(s_u, s_v) + \\eta < d(s_u, s_k)$, 但如果这个式子不成立的话就可以认为产生了penalty。 所以这部分就可以表示成大家熟悉的hinge loss: $max (0, d(s_u, s_v) + \\eta - d(s_u, s_k))$。 另外,我们同时也希望如果两个样本属于同一个类别, 那它俩的距离也比较相近。所以目标函数可以分为两个部分: 1. 同类型的样本距离尽量要近 2. 不同类型的样本距离尽量远一些。 \n",
"\n",
"当我们把所有的样本以及他们之间的大小关系考虑进来之后就可以得到最终的目标函数。 \n",
"\n",
"\\begin{equation}\n",
"L = \\lambda \\sum_{u=1}^{n}\\sum_{v\\in pos(u)}d(s_u, s_v) + (1-\\lambda)\\sum_{u=1}^{n}\\sum_{v\\in pos(u)}^{}\\sum_{w\\in neg(u)}^{} max (0, d(s_u, s_v) + \\eta - d(s_u, s_w))\n",
"\\end{equation}\n",
"\n",
"这里几个notation: pos(u)代表的是跟样本u属于同一个类别的样本, neg(u)指的是跟样本u属于不同类别的样本。 注意:类别的个数可以大于2, 就是多分类问题。 你也可以参考: http://jmlr.org/papers/volume10/weinberger09a/weinberger09a.pdf"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在这个式子里,第一部分代表的是让同一类型的样本的距离变小, 第二部分代表的是不同类型的样本之间要扩大距离。 \n",
"\n",
"- #### Q1: 这里$\\lambda$起到什么作用?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO: 你的答案....\n",
"\n",
"调整惩罚力度。如果$\\lambda$比较大,我们就比较注重于减小同类型样本间的距离,即原WMD问题;如果$\\lambda$ 比较小,则$1-\\lambda$比较大,我们对于不同类型样本间距离的惩罚就比较大。\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- #### Q2: 在目标函数里有$\\eta$值,这个值怎么理解? 如果去设定这个值呢?\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO: 你的答案 ....\n",
" \n",
"假设以一个样本为中心,半径r内的都和其为一类,半径R以上就是另一类,则 $\\eta = R-r$。这个值可以通过数据集本身的性质设定,通过run不同数值看模型哪个效果比较好。\n",
" \n",
" \n",
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"这里的$d_{u,v}$指的是$s_u$和$s_v$之间的距离, 而且这个距离被定义为:\n",
"\n",
"\\begin{equation} d_{u, v}=min_{T\\geq 0}\\sum_{i,j}^{}T_{ij}c(i,j)^u~~~~ s.t. \\sum_{j=1}^{}T_{ij}=d_i^u, ~~\\sum_{i=1}^{}T_{ij}=d_j'^v\\end{equation}\n",
"\n",
"这里 $c(i,j)=(x_i-x_j)^{\\top}M(x_i-x_j)$。 所以是不是可以察觉到这个问题目标函数里既包含了参数$M$也包含了线性规划问题。\n",
"\n",
"- #### Q3: 请试着去理解上述所有的过程,并回答: 优化问题如何解决呢? 请给出解题的思路 (文字适当配合推导过程)。 "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"// TODO 你的答案.... "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"对于上述问题,其实我们也可以采用不一样的损失函数来求解M。 一个常用的损失函数叫作 “kNN-LOO error”, 相当于把KNN的准确率转换成了smooth differential loss function. 感兴趣的朋友可以参考: https://papers.nips.cc/paper/6139-supervised-word-movers-distance.pdf\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"以上是优化部分的一个简短的作业,通过这些练习会对优化理论有更清晰的认知。 Good luck for everyone! "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 搭建一个分词工具\n",
"\n",
"### Part 1 基于枚举方法来搭建中文分词工具\n",
"\n",
"此项目需要的数据:\n",
"1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用(第二列:词频+词性)\n",
"2. 以变量的方式提供了部分unigram概率 word_prob\n",
"\n",
"\n",
"举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15\n",
"\n",
"#### Step 1: 对于给定字符串:”我们学习人工智能,人工智能是未来“, 找出所有可能的分割方式\n",
"- [我们,学习,人工智能,人工智能,是,未来]\n",
"- [我们,学习,人工,智能,人工智能,是,未来]\n",
"- [我们,学习,人工,智能,人工,智能,是,未来]\n",
"- [我们,学习,人工智能,人工,智能,是,未来]\n",
".......\n",
"\n",
"\n",
"#### Step 2: 我们也可以计算出每一个切分之后句子的概率\n",
"- p(我们,学习,人工智能,人工智能,是,未来)= -log p(我们)-log p(学习)-log p(人工智能)-log p(人工智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工,智能,人工智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工,智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工)-log p(智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工智能)-log p(人工)-log p(智能)-log(是)-log p(未来)\n",
".....\n",
"\n",
"#### Step 3: 返回第二步中概率最大的结果"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['酢',\n",
" '做做事',\n",
" '做做饭',\n",
" '做做',\n",
" '做作',\n",
" '做主',\n",
" '做针线',\n",
" '做张做智',\n",
" '做张做致',\n",
" '做张做势',\n",
" '做贼心虚',\n",
" '做月子',\n",
" '做一天和尚撞一天钟',\n",
" '做一日和尚撞一天钟',\n",
" '做秀',\n",
" '做小伏低',\n",
" '做戏',\n",
" '做文章',\n",
" '做为',\n",
" '做头',\n",
" '做通',\n",
" '做私商勾当',\n",
" '做寿',\n",
" '做手脚',\n",
" '做事',\n",
" '做市商',\n",
" '做生意',\n",
" '做生日',\n",
" '做神做鬼',\n",
" '做人做世',\n",
" '做人',\n",
" '做起',\n",
" '做派',\n",
" '做梦',\n",
" '做媒',\n",
" '做礼拜',\n",
" '做客',\n",
" '做假账',\n",
" '做家教',\n",
" '做活儿',\n",
" '做活',\n",
" '做好做恶',\n",
" '做好做歹',\n",
" '做好',\n",
" '做鬼做神',\n",
" '做鬼',\n",
" '做官者',\n",
" '做官当老爷',\n",
" '做官',\n",
" '做功',\n",
" '做工精细',\n",
" '做工',\n",
" '做刚做柔',\n",
" '做饭',\n",
" '做法',\n",
" '做东道',\n",
" '做东',\n",
" '做到',\n",
" '做大做强',\n",
" '做出',\n",
" '做成',\n",
" '做操',\n",
" '做菜',\n",
" '做不了',\n",
" '做伴',\n",
" '做爱',\n",
" '做',\n",
" '座座',\n",
" '座子',\n",
" '座钟',\n",
" '座右铭',\n",
" '座椅',\n",
" '座像',\n",
" '座向',\n",
" '座席',\n",
" '座无虚席',\n",
" '座位图',\n",
" '座位数',\n",
" '座位号',\n",
" '座位费',\n",
" '座位表',\n",
" '座位',\n",
" '座套',\n",
" '座谈会',\n",
" '座谈',\n",
" '座上客',\n",
" '座上宾',\n",
" '座山峰',\n",
" '座山雕',\n",
" '座圈',\n",
" '座区',\n",
" '座骑',\n",
" '座票',\n",
" '座盘',\n",
" '座落在',\n",
" '座落',\n",
" '座楼',\n",
" '座架',\n",
" '座驾',\n",
" '座机',\n",
" '座环',\n",
" '座号',\n",
" '座豪华',\n",
" '座垫',\n",
" '座次',\n",
" '座充',\n",
" '座车',\n",
" '座厕',\n",
" '座舱',\n",
" '座标',\n",
" '座便器',\n",
" '座便',\n",
" '座',\n",
" '唑',\n",
" '祚庆',\n",
" '祚',\n",
" '胙',\n",
" '怍',\n",
" '阼',\n",
" '坐坐',\n",
" '坐姿',\n",
" '坐庄',\n",
" '坐支',\n",
" '坐镇',\n",
" '坐诊',\n",
" '坐在',\n",
" '坐运筹策',\n",
" '坐月子',\n",
" '坐浴',\n",
" '坐于涂炭',\n",
" '坐拥书城',\n",
" '坐拥百城',\n",
" '坐椅',\n",
" '坐以待旦',\n",
" '坐以待毙',\n",
" '坐药',\n",
" '坐言起行',\n",
" '坐薪悬胆',\n",
" '坐薪尝胆',\n",
" '坐像',\n",
" '坐享其功',\n",
" '坐享其成',\n",
" '坐下',\n",
" '坐席',\n",
" '坐无虚席',\n",
" '坐卧针毡',\n",
" '坐卧不宁',\n",
" '坐卧不离',\n",
" '坐卧不安',\n",
" '坐位表',\n",
" '坐位',\n",
" '坐堂',\n",
" '坐探',\n",
" '坐台',\n",
" '坐树无言',\n",
" '坐树不言',\n",
" '坐守',\n",
" '坐收渔利',\n",
" '坐收',\n",
" '坐视成败',\n",
" '坐视不救',\n",
" '坐视不管',\n",
" '坐视',\n",
" '坐式',\n",
" '坐食山空',\n",
" '坐失事机',\n",
" '坐失良机',\n",
" '坐失机宜',\n",
" '坐失',\n",
" '坐上琴心',\n",
" '坐商',\n",
" '坐山观虎斗',\n",
" '坐山雕',\n",
" '坐骑',\n",
" '坐盆',\n",
" '坐喷气式',\n",
" '坐南朝北',\n",
" '坐落',\n",
" '坐立不安',\n",
" '坐力',\n",
" '坐冷板凳',\n",
" '坐牢',\n",
" '坐困愁城',\n",
" '坐客',\n",
" '坐具',\n",
" '坐井观天',\n",
" '坐禁闭',\n",
" '坐江山',\n",
" '坐监',\n",
" '坐怀不乱',\n",
" '坐化',\n",
" '坐果',\n",
" '坐观成败',\n",
" '坐骨神经',\n",
" '坐骨',\n",
" '坐功',\n",
" '坐而论道',\n",
" '坐而待旦',\n",
" '坐而待弊',\n",
" '坐而待毙',\n",
" '坐墩',\n",
" '坐蔸',\n",
" '坐定',\n",
" '坐垫',\n",
" '坐地自划',\n",
" '坐地分脏',\n",
" '坐地分赃',\n",
" '坐地',\n",
" '坐凳',\n",
" '坐等',\n",
" '坐待',\n",
" '坐大',\n",
" '坐次',\n",
" '坐床',\n",
" '坐船',\n",
" '坐筹帷幄',\n",
" '坐吃山空',\n",
" '坐吃山崩',\n",
" '坐车',\n",
" '坐禅',\n",
" '坐厕',\n",
" '坐舱',\n",
" '坐不重席',\n",
" '坐不窥堂',\n",
" '坐不改姓',\n",
" '坐不垂堂',\n",
" '坐不安席',\n",
" '坐标轴',\n",
" '坐标系',\n",
" '坐标',\n",
" '坐便器',\n",
" '坐便',\n",
" '坐北朝南',\n",
" '坐班制',\n",
" '坐班',\n",
" '坐',\n",
" '作作有芒',\n",
" '作作',\n",
" '作祖',\n",
" '作子',\n",
" '作主',\n",
" '作忠',\n",
" '作证',\n",
" '作者投稿',\n",
" '作者群',\n",
" '作者',\n",
" '作哲',\n",
" '作战室',\n",
" '作战区',\n",
" '作战科',\n",
" '作战服',\n",
" '作战处',\n",
" '作战部',\n",
" '作战',\n",
" '作贼心虚',\n",
" '作育人材',\n",
" '作用力',\n",
" '作用点',\n",
" '作用',\n",
" '作勇',\n",
" '作翊',\n",
" '作役',\n",
" '作义',\n",
" '作揖',\n",
" '作业组',\n",
" '作业证',\n",
" '作业者',\n",
" '作业员',\n",
" '作业线',\n",
" '作业题',\n",
" '作业区',\n",
" '作业面',\n",
" '作业率',\n",
" '作业流程',\n",
" '作业量',\n",
" '作业机',\n",
" '作业费',\n",
" '作业队',\n",
" '作业点',\n",
" '作业车',\n",
" '作业本',\n",
" '作业',\n",
" '作言造语',\n",
" '作训服',\n",
" '作训',\n",
" '作秀',\n",
" '作兴',\n",
" '作协',\n",
" '作孝',\n",
" '作小服低',\n",
" '作响',\n",
" '作宪',\n",
" '作息时间',\n",
" '作息',\n",
" '作物',\n",
" '作务衣',\n",
" '作武',\n",
" '作文指导',\n",
" '作文网',\n",
" '作文题',\n",
" '作文课',\n",
" '作文辅导',\n",
" '作文簿',\n",
" '作文本',\n",
" '作文',\n",
" '作伪者',\n",
" '作伪',\n",
" '作为',\n",
" '作威作福',\n",
" '作威',\n",
" '作图',\n",
" '作田',\n",
" '作态',\n",
" '作祟',\n",
" '作手脚',\n",
" '作适',\n",
" '作势',\n",
" '作士',\n",
" '作生',\n",
" '作舍道旁',\n",
" '作舍道边',\n",
" '作善降祥',\n",
" '作善',\n",
" '作如是观',\n",
" '作人',\n",
" '作曲者',\n",
" '作曲系',\n",
" '作曲家',\n",
" '作曲法',\n",
" '作曲编曲',\n",
" '作曲',\n",
" '作乔',\n",
" '作品展示',\n",
" '作品展览',\n",
" '作品展',\n",
" '作品阅读',\n",
" '作品选',\n",
" '作品欣赏',\n",
" '作品赏析',\n",
" '作品目录',\n",
" '作品列表',\n",
" '作品简介',\n",
" '作品集',\n",
" '作品',\n",
" '作陪',\n",
" '作派',\n",
" '作呕',\n",
" '作弄',\n",
" '作孽',\n",
" '作鸟兽散',\n",
" '作难',\n",
" '作牧',\n",
" '作民',\n",
" '作美',\n",
" '作梅',\n",
" '作洛',\n",
" '作乱',\n",
" '作料',\n",
" '作乐',\n",
" '作浪兴风',\n",
" '作朗',\n",
" '作客思想',\n",
" '作客',\n",
" '作金石声',\n",
" '作娇',\n",
" '作践',\n",
" '作贱',\n",
" '作件',\n",
" '作茧自缚',\n",
" '作奸犯科',\n",
" '作嫁衣裳',\n",
" '作价',\n",
" '作假者',\n",
" '作假',\n",
" '作家作品',\n",
" '作家资料',\n",
" '作家在线',\n",
" '作家杂志',\n",
" '作家协会',\n",
" '作家网',\n",
" '作家群',\n",
" '作家风景',\n",
" '作家档案',\n",
" '作家出版社',\n",
" '作家',\n",
" '作画',\n",
" '作好作歹',\n",
" '作好',\n",
" '作翰',\n",
" '作鬼',\n",
" '作怪',\n",
" '作谷',\n",
" '作古正经',\n",
" '作古',\n",
" '作工',\n",
" '作梗',\n",
" '作福作威',\n",
" '作孚',\n",
" '作夫',\n",
" '作风建设',\n",
" '作风',\n",
" '作废',\n",
" '作坊式',\n",
" '作坊',\n",
" '作范',\n",
" '作法自弊',\n",
" '作法自毙',\n",
" '作法',\n",
" '作伐',\n",
" '作恶者',\n",
" '作恶多端',\n",
" '作恶',\n",
" '作厄',\n",
" '作对',\n",
" '作东',\n",
" '作登乡',\n",
" '作到',\n",
" '作代会',\n",
" '作大',\n",
" '作答',\n",
" '作词家',\n",
" '作词',\n",
" '作辍无常',\n",
" '作出',\n",
" '作成',\n",
" '作宾',\n",
" '作别',\n",
" '作壁上观',\n",
" '作弊器',\n",
" '作弊',\n",
" '作保',\n",
" '作伴儿',\n",
" '作伴',\n",
" '作罢',\n",
" '作案者',\n",
" '作案人',\n",
" '作案',\n",
" '作',\n",
" '佐佐木元',\n",
" '佐佐木',\n",
" '佐佐',\n",
" '佐助',\n",
" '佐竹',\n",
" '佐州',\n",
" '佐治亚州',\n",
" '佐治亚大学',\n",
" '佐治亚',\n",
" '佐治',\n",
" '佐织',\n",
" '佐之才',\n",
" '佐证',\n",
" '佐钊',\n",
" '佐佑',\n",
" '佐饔得尝',\n",
" '佐雍得尝',\n",
" '佐雍得',\n",
" '佐弋',\n",
" '佐伊',\n",
" '佐野',\n",
" '佐享',\n",
" '佐相',\n",
" '佐维奇',\n",
" '佐托夫',\n",
" '佐藤嘉恭',\n",
" '佐藤',\n",
" '佐特',\n",
" '佐塔',\n",
" '佐书',\n",
" '佐使',\n",
" '佐山',\n",
" '佐人',\n",
" '佐钦',\n",
" '佐派',\n",
" '佐纳',\n",
" '佐幕',\n",
" '佐谋',\n",
" '佐默',\n",
" '佐命',\n",
" '佐米曲坦',\n",
" '佐美',\n",
" '佐洛埃格塞格',\n",
" '佐洛',\n",
" '佐罗',\n",
" '佐卢',\n",
" '佐林',\n",
" '佐料',\n",
" '佐理',\n",
" '佐拉',\n",
" '佐克',\n",
" '佐卡',\n",
" '佐酒',\n",
" '佐剂',\n",
" '佐欢',\n",
" '佐贺县',\n",
" '佐贺',\n",
" '佐哈尔',\n",
" '佐国',\n",
" '佐攻者',\n",
" '佐格',\n",
" '佐夫斯基',\n",
" '佐夫',\n",
" '佐法尔',\n",
" '佐尔坦',\n",
" '佐尔格',\n",
" '佐尔',\n",
" '佐恩',\n",
" '佐渡岛',\n",
" '佐斗',\n",
" '佐登',\n",
" '佐村镇',\n",
" '佐川',\n",
" '佐车',\n",
" '佐餐',\n",
" '佐伯',\n",
" '佐埃',\n",
" '佐',\n",
" '左左右右',\n",
" '左宗棠',\n",
" '左枝右梧',\n",
" '左支右吾',\n",
" '左支右调',\n",
" '左支右绌',\n",
" '左证',\n",
" '左镇乡',\n",
" '左镇',\n",
" '左云县',\n",
" '左云',\n",
" '左右翼',\n",
" '左右眼',\n",
" '左右为难',\n",
" '左右腿',\n",
" '左右图史',\n",
" '左右手',\n",
" '左右脑',\n",
" '左右两难',\n",
" '左右开弓',\n",
" '左右江',\n",
" '左右逢源',\n",
" '左右逢原',\n",
" '左右方',\n",
" '左右侧',\n",
" '左右采获',\n",
" '左右岸',\n",
" '左右',\n",
" '左拥右抱',\n",
" '左萦右拂',\n",
" '左营',\n",
" '左翼文化运动',\n",
" '左翼',\n",
" '左宜右有',\n",
" '左宜右宜',\n",
" '左眼',\n",
" '左延安',\n",
" '左旋肉碱',\n",
" '左旋炔诺孕酮',\n",
" '左旋咪唑涂布剂',\n",
" '左旋',\n",
" '左舷',\n",
" '左贤王',\n",
" '左贤',\n",
" '左下角',\n",
" '左下方',\n",
" '左下',\n",
" '左膝',\n",
" '左溪',\n",
" '左文襄公',\n",
" '左文',\n",
" '左腿',\n",
" '左徒',\n",
" '左图右书',\n",
" '左图右史',\n",
" '左图',\n",
" '左铁镛',\n",
" '左天觉',\n",
" '左提右挈',\n",
" '左藤',\n",
" '左思右想',\n",
" '左思',\n",
" '左司马',\n",
" '左书右息',\n",
" '左首',\n",
" '左手指',\n",
" '左手腕',\n",
" '左手画方',\n",
" '左手',\n",
" '左上角',\n",
" '左上方',\n",
" '左上臂',\n",
" '左上',\n",
" '左嗓子',\n",
" '左炔诺孕酮',\n",
" '左券',\n",
" '左权县',\n",
" '左权墓',\n",
" '左权',\n",
" '左丘明',\n",
" '左晴雯',\n",
" '左倾机会主义',\n",
" '左倾',\n",
" '左强',\n",
" '左前卫',\n",
" '左铅右椠',\n",
" '左迁',\n",
" '左旗',\n",
" '左撇子',\n",
" '左膀右臂',\n",
" '左膀',\n",
" '左派',\n",
" '左木',\n",
" '左民党',\n",
" '左面',\n",
" '左绵',\n",
" '左满舵',\n",
" '左轮手枪',\n",
" '左轮',\n",
" '左路',\n",
" '左岭镇',\n",
" '左麟右李',\n",
" '左邻右舍',\n",
" '左邻右里',\n",
" '左列',\n",
" '左联五烈士',\n",
" '左联',\n",
" '左连璧',\n",
" '左拉',\n",
" '左近',\n",
" '左金丸',\n",
" '左脚',\n",
" '左江日报',\n",
" '左江',\n",
" '左键',\n",
" '左家庄',\n",
" '左家塘',\n",
" '左家',\n",
" '左焕琮',\n",
" '左焕琛',\n",
" '左后卫',\n",
" '左行',\n",
" '左海',\n",
" '左归丸',\n",
" '左顾右盼',\n",
" '左顾右眄',\n",
" '左贡县',\n",
" '左贡',\n",
" '左公柳',\n",
" '左各庄镇',\n",
" '左辅右弼',\n",
" '左锋',\n",
" '左方',\n",
" '左耳',\n",
" '左躲右闪',\n",
" '左端',\n",
" '左道旁门',\n",
" '左传',\n",
" '左丞相',\n",
" '左侧',\n",
" '左不过',\n",
" '左边前卫',\n",
" '左边锋',\n",
" '左边',\n",
" '左臂右膀',\n",
" '左臂',\n",
" '左岸',\n",
" '左安门',\n",
" '左安龙',\n",
" '左安安',\n",
" '左',\n",
" '阝',\n",
" '昨夜',\n",
" '昨晚',\n",
" '昨天',\n",
" '昨日',\n",
" '昨儿个',\n",
" '昨儿',\n",
" '昨',\n",
" '嘬嘬',\n",
" '嘬',\n",
" '撙撙',\n",
" '撙节',\n",
" '撙',\n",
" '鳟鱼',\n",
" '鳟',\n",
" '樽俎折冲',\n",
" '樽俎',\n",
" '樽前月下',\n",
" '樽',\n",
" '遵嘱',\n",
" '遵照',\n",
" '遵章守纪',\n",
" '遵章率',\n",
" '遵义县',\n",
" '遵义钛厂',\n",
" '遵义市政府',\n",
" '遵义市委',\n",
" '遵义市',\n",
" '遵义会议',\n",
" '遵义供电局',\n",
" '遵义',\n",
" '遵业',\n",
" '遵尧',\n",
" '遵养时晦',\n",
" '遵养晦时',\n",
" '遵养待时',\n",
" '遵厌兆祥',\n",
" '遵循',\n",
" '遵学',\n",
" '遵序',\n",
" '遵信',\n",
" '遵帅',\n",
" '遵守宪法',\n",
" '遵守',\n",
" '遵时养晦',\n",
" '遵生',\n",
" '遵钦',\n",
" '遵命',\n",
" '遵理',\n",
" '遵礼',\n",
" '遵敬',\n",
" '遵纪守法户',\n",
" '遵纪守法',\n",
" '遵纪爱民',\n",
" '遵纪',\n",
" '遵化县',\n",
" '遵化市',\n",
" '遵化',\n",
" '遵鸿',\n",
" '遵行',\n",
" '遵海',\n",
" '遵复',\n",
" '遵奉',\n",
" '遵法',\n",
" '遵而勿失',\n",
" '遵而不失',\n",
" '遵典',\n",
" '遵德',\n",
" '遵道秉义',\n",
" '遵道',\n",
" '遵从',\n",
" '遵',\n",
" '尊俎折冲',\n",
" '尊主泽民',\n",
" '尊主',\n",
" '尊重',\n",
" '尊者',\n",
" '尊长',\n",
" '尊章',\n",
" '尊造',\n",
" '尊远',\n",
" '尊仪',\n",
" '尊严感',\n",
" '尊严',\n",
" '尊萱',\n",
" '尊姓大名',\n",
" '尊姓',\n",
" '尊幸',\n",
" '尊贤使能',\n",
" '尊贤',\n",
" '尊无二上',\n",
" '尊翁',\n",
" '尊为',\n",
" '尊威',\n",
" '尊特拉',\n",
" '尊堂',\n",
" '尊肃',\n",
" '尊寿',\n",
" '尊师重教',\n",
" '尊师重道',\n",
" '尊师贵道',\n",
" '尊师',\n",
" '尊盛',\n",
" '尊胜陀罗尼经幢',\n",
" '尊胜',\n",
" '尊神',\n",
" '尊尚',\n",
" '尊容',\n",
" '尊荣',\n",
" '尊亲',\n",
" '尊年尚齿',\n",
" '尊明',\n",
" '尊礼',\n",
" '尊老敬老',\n",
" '尊老爱幼',\n",
" '尊老',\n",
" '尊君',\n",
" '尊爵',\n",
" '尊敬',\n",
" '尊介',\n",
" '尊驾',\n",
" '尊纪',\n",
" '尊华',\n",
" '尊厚',\n",
" '尊号',\n",
" '尊行',\n",
" '尊贵',\n",
" '尊古卑今',\n",
" '尊公',\n",
" '尊庚',\n",
" '尊刚',\n",
" '尊府',\n",
" '尊甫',\n",
" '尊夫人',\n",
" '尊奉',\n",
" '尊范',\n",
" '尊慈',\n",
" '尊宠',\n",
" '尊崇',\n",
" '尊驰',\n",
" '尊称',\n",
" '尊卑',\n",
" '尊宝',\n",
" '尊安',\n",
" '尊',\n",
" '醉枣',\n",
" '醉玉颓山',\n",
" '醉鱼草',\n",
" '醉意',\n",
" '醉眼',\n",
" '醉醺醺',\n",
" '醉心',\n",
" '醉乡',\n",
" '醉舞狂歌',\n",
" '醉舞',\n",
" '醉翁之意不在酒',\n",
" '醉翁亭记',\n",
" '醉翁亭',\n",
" '醉吐相茵',\n",
" '醉态',\n",
" '醉死梦生',\n",
" '醉生梦死',\n",
" '醉山颓倒',\n",
" '醉人',\n",
" '醉拳',\n",
" '醉梦花',\n",
" '醉马草',\n",
" '醉酒者',\n",
" '醉酒饱德',\n",
" '醉酒',\n",
" '醉鸡',\n",
" '醉话',\n",
" '醉汉',\n",
" '醉鬼',\n",
" '醉白池',\n",
" '醉',\n",
" '蕞',\n",
" '罪状',\n",
" '罪证',\n",
" '罪责难逃',\n",
" '罪责',\n",
" '罪有攸归',\n",
" '罪有应得',\n",
" '罪应万死',\n",
" '罪业深重',\n",
" '罪业',\n",
" '罪人不孥',\n",
" '罪人',\n",
" '罪愆',\n",
" '罪孽深重',\n",
" '罪孽',\n",
" '罪逆深重',\n",
" '罪名',\n",
" '罪魁祸首',\n",
" '罪魁',\n",
" '罪加一等',\n",
" '罪行',\n",
" '罪过形式',\n",
" '罪过',\n",
" '罪该万死',\n",
" '罪犯',\n",
" '罪恶滔天',\n",
" '罪恶贯盈',\n",
" '罪恶感',\n",
" '罪恶都市',\n",
" '罪恶的黑手',\n",
" '罪恶',\n",
" '罪当万死',\n",
" '罪大恶极',\n",
" '罪错',\n",
" '罪不胜诛',\n",
" '罪不容诛',\n",
" '罪不容赦',\n",
" '罪不可逭',\n",
" '罪案率',\n",
" '罪案',\n",
" '罪',\n",
" '最最',\n",
" '最重',\n",
" '最终幻想',\n",
" '最终',\n",
" '最长',\n",
" '最早',\n",
" '最远点',\n",
" '最远',\n",
" '最游记',\n",
" '最优化',\n",
" '最新作品',\n",
" '最新咨讯',\n",
" '最新专辑',\n",
" '最新政策',\n",
" '最新招聘',\n",
" '最新战况',\n",
" '最新在线',\n",
" '最新音乐',\n",
" '最新讯息',\n",
" '最新型',\n",
" '最新消息',\n",
" '最新下载',\n",
" '最新文章',\n",
" '最新图片',\n",
" '最新商情',\n",
" '最新软件',\n",
" '最新期刊',\n",
" '最新漏洞',\n",
" '最新楼盘',\n",
" '最新景点',\n",
" '最新技术',\n",
" '最新活动',\n",
" '最新公告',\n",
" '最新更新',\n",
" '最新法规',\n",
" '最新发行',\n",
" '最新电影',\n",
" '最新大片',\n",
" '最新产品',\n",
" '最新报价',\n",
" '最新报道',\n",
" '最新版',\n",
" '最新',\n",
" '最小化',\n",
" '最小公倍数',\n",
" '最小',\n",
" '最先',\n",
" '最为',\n",
" '最深',\n",
" '最少',\n",
" '最全面',\n",
" '最全',\n",
" '最轻量级',\n",
" '最强音',\n",
" '最强',\n",
" '最前沿',\n",
" '最起码',\n",
" '最末',\n",
" '最美',\n",
" '最快',\n",
" '最近新书',\n",
" '最近似值',\n",
" '最近',\n",
" '最简式',\n",
" '最简论坛',\n",
" '最简分数',\n",
" '最佳期',\n",
" '最佳奖',\n",
" '最佳化',\n",
" '最佳',\n",
" '最惠国待遇',\n",
" '最惠国',\n",
" '最惠',\n",
" '最後',\n",
" '最后战士',\n",
" '最后一秒',\n",
" '最后通牒',\n",
" '最后通谍',\n",
" '最后的晚餐',\n",
" '最后的审判',\n",
" '最后的爱',\n",
" '最后',\n",
" '最好',\n",
" '最高值',\n",
" '最高者',\n",
" '最高院',\n",
" '最高人民检察院政治部',\n",
" '最高人民检察院',\n",
" '最高人民法院审判委员会',\n",
" '最高人民法院党组',\n",
" '最高人民法院',\n",
" '最高检察院',\n",
" '最高检',\n",
" '最高价',\n",
" '最高级',\n",
" '最高峰',\n",
" '最高分',\n",
" '最高法院',\n",
" '最高额',\n",
" '最高点',\n",
" '最高处',\n",
" '最高潮',\n",
" '最高层',\n",
" '最高',\n",
" '最底层',\n",
" '最低值',\n",
" '最低限',\n",
" '最低价',\n",
" '最低谷',\n",
" '最低点',\n",
" '最低',\n",
" '最大值',\n",
" '最大者',\n",
" '最大化',\n",
" '最大公约数',\n",
" '最大',\n",
" ...]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import xlrd \n",
"data=xlrd.open_workbook('综合类中文词库.xlsx')#excle文件位置\n",
"sheet=data.sheets()[0] #读取第一bai个表du\n",
"col=sheet.col_values(0) #读取第一列\n",
"col"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.0000000000000002\n"
]
}
],
"source": [
"# TODO: 第一步: 从综合类中文词库.xlsx 中读取所有中文词。\n",
"# hint: 思考一下用什么数据结构来存储这个词典会比较好? 要考虑我们每次查询一个单词的效率。 \n",
"max_len_word = 0\n",
"dic_words = {} # 保存词典库中读取的单词\n",
"for word in col:\n",
" dic_words[word] = 0.00001\n",
" len_word = len(word)\n",
" if len_word > max_len_word:\n",
" max_len_word = len_word\n",
"\n",
"# 以下是每一个单词出现的概率。为了问题的简化,我们只列出了一小部分单词的概率。 在这里没有出现的的单词但是出现在词典里的,统一把概率设置成为0.00001\n",
"# 比如 p(\"学院\")=p(\"概率\")=...0.00001\n",
"\n",
"word_prob = {\"北京\":0.03,\"的\":0.08,\"天\":0.005,\"气\":0.005,\"天气\":0.06,\"真\":0.04,\"好\":0.05,\"真好\":0.04,\"啊\":0.01,\"真好啊\":0.02, \n",
" \"今\":0.01,\"今天\":0.07,\"课程\":0.06,\"内容\":0.06,\"有\":0.05,\"很\":0.03,\"很有\":0.04,\"意思\":0.06,\"有意思\":0.005,\"课\":0.01,\n",
" \"程\":0.005,\"经常\":0.08,\"意见\":0.08,\"意\":0.01,\"见\":0.005,\"有意见\":0.02,\"分歧\":0.04,\"分\":0.02, \"歧\":0.005}\n",
"\n",
"for key, values in word_prob.items():\n",
" dic_words[key] = values\n",
"\n",
"print (sum(word_prob.values()))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def segment(input_str):\n",
" segments = [] # 存储所有分词的结果。如果次字符串不可能被完全切分,则返回空列表(list)\n",
" len_input_str = len(input_str)\n",
" if len_input_str == 0: # 空字符串\n",
" return [segments]\n",
" else:\n",
" result = []\n",
" for idx in range(1, len_input_str + 1):\n",
" if input_str[:idx] in dic_words:\n",
" for remain_segment in segment(input_str[idx:]):\n",
" result.append([input_str[:idx]] + remain_segment)\n",
" return result"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"## TODO 请编写word_segment_naive函数来实现对输入字符串的分词\n",
"def word_segment_naive(input_str):\n",
" \"\"\"\n",
" 1. 对于输入字符串做分词,并返回所有可行的分词之后的结果。\n",
" 2. 针对于每一个返回结果,计算句子的概率\n",
" 3. 返回概率最高的最作为最后结果\n",
" \n",
" input_str: 输入字符串 输入格式:“今天天气好”\n",
" best_segment: 最好的分词结果 输出格式:[\"今天\",\"天气\",\"好\"]\n",
" \"\"\"\n",
"\n",
" # TODO: 第一步: 计算所有可能的分词结果,要保证每个分完的词存在于词典里,这个结果有可能会非常多。 \n",
" segments = segment(input_str) # 存储所有分词的结果。如果次字符串不可能被完全切分,则返回空列表(list)\n",
" # 格式为:segments = [[\"今天\",“天气”,“好”],[\"今天\",“天“,”气”,“好”],[\"今“,”天\",“天气”,“好”],...] \n",
" \n",
" # TODO: 第二步:循环所有的分词结果,并计算出概率最高的分词结果,并返回\n",
" best_score = np.inf\n",
" for seg in segments:\n",
" score = 0\n",
" for word in seg:\n",
" score -= np.log(dic_words[word])\n",
" if score < best_score:\n",
" best_score = score\n",
" best_segment = seg \n",
" \n",
" return best_segment "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['北京', '的', '天气', '真好啊']\n",
"['今天', '的', '课程', '内容', '很有', '意思']\n",
"['经常', '有意见', '分歧']\n"
]
}
],
"source": [
"# 测试\n",
"print (word_segment_naive(\"北京的天气真好啊\"))\n",
"print (word_segment_naive(\"今天的课程内容很有意思\"))\n",
"print (word_segment_naive(\"经常有意见分歧\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Part 2 基于维特比算法来优化上述流程\n",
"\n",
"此项目需要的数据:\n",
"1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用\n",
"2. 以变量的方式提供了部分unigram概率word_prob\n",
"\n",
"\n",
"举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15\n",
"\n",
"#### Step 1: 根据词典,输入的句子和 word_prob来创建带权重的有向图(Directed Graph) 参考:课程内容\n",
"有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率已经给出(存放在word_prob)。\n",
"注意:思考用什么方式来存储这种有向图比较合适? 不一定只有一种方式来存储这种结构。 \n",
"\n",
"#### Step 2: 编写维特比算法(viterebi)算法来找出其中最好的PATH, 也就是最好的句子切分\n",
"具体算法参考课程中讲过的内容\n",
"\n",
"#### Step 3: 返回结果\n",
"跟PART 1的要求一致"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"## TODO 请编写word_segment_viterbi函数来实现对输入字符串的分词\n",
"def word_segment_viterbi(input_str):\n",
" \"\"\"\n",
" 1. 基于输入字符串,词典,以及给定的unigram概率来创建DAG(有向图)。\n",
" 2. 编写维特比算法来寻找最优的PATH\n",
" 3. 返回分词结果\n",
" \n",
" input_str: 输入字符串 输入格式:“今天天气好”\n",
" best_segment: 最好的分词结果 输出格式:[\"今天\",\"天气\",\"好\"]\n",
" \"\"\" \n",
" # TODO: 第一步:根据词典,输入的句子,以及给定的unigram概率来创建带权重的有向图(Directed Graph) 参考:课程内容\n",
" # 有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率在 word_prob,如果不在word_prob里的单词但在\n",
" # 词典里存在的,统一用概率值0.00001。\n",
" # 注意:思考用什么方式来存储这种有向图比较合适? 不一定有只有一种方式来存储这种结构。 \n",
" graph = {}\n",
" N = len(input_str)\n",
" for idx in range(N,-1,-1):\n",
" temp = []\n",
" for k in range(idx):\n",
" if input_str[k:idx] in dic_words:\n",
" temp.append(k)\n",
" graph[idx] = temp \n",
" \n",
" # TODO: 第二步: 利用维特比算法来找出最好的PATH, 这个PATH是P(sentence)最大或者 -log P(sentence)最小的PATH。\n",
" # hint: 思考为什么不用相乘: p(w1)p(w2)...而是使用negative log sum: -log(w1)-log(w2)-...\n",
" # 防止下溢出\n",
" res = [0]*(N+1)\n",
" last_index = [0]*(N+1)\n",
" for i in range(1,N+1):\n",
" temp = np.inf\n",
" for j in graph[i]:\n",
" if input_str[j:i] in dic_words:\n",
" if temp > res[j] - np.log(dic_words[input_str[j:i]]):\n",
" temp = res[j] - np.log(dic_words[input_str[j:i]])\n",
" last_index[i] = j\n",
" res[i] = temp\n",
" path = list(set(last_index))\n",
" \n",
" # TODO: 第三步: 根据最好的PATH, 返回最好的切分\n",
" len_path = len(path)\n",
" best_segment = [input_str[path[x]:path[x+1]] for x in range(len_path-1)]\n",
" best_segment.append(input_str[path[len_path-1]:])\n",
"\n",
" return best_segment "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['北京', '的', '天气', '真好啊']\n",
"['今天', '的', '课程', '内容', '很有', '意思']\n",
"['经常', '有', '意见', '分歧']\n"
]
}
],
"source": [
"# 测试\n",
"print(word_segment_viterbi(\"北京的天气真好啊\"))\n",
"print(word_segment_viterbi(\"今天的课程内容很有意思\"))\n",
"print(word_segment_viterbi(\"经常有意见分歧\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# TODO: 第一种方法和第二种方法的时间复杂度和空间复杂度分别是多少?\n",
"网格宽度为D,长度为N \n",
"第一个方法: \n",
"时间复杂度= $O(D^N)$ , 空间复杂度= $O(D*N)$\n",
"\n",
"第二个方法:\n",
"时间复杂度= $O(nD^2)$, 空间复杂度= $O(D)$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TODO:如果把上述的分词工具持续优化,有哪些可以考虑的方法? (至少列出3点)\n",
"- 0. (例), 目前的概率是不完整的,可以考虑大量的语料库,然后从中计算出每一个词出现的概率,这样更加真实\n",
"- 1. 概率太低的词可以不用记录,节约空间\n",
"- 2. 隐马尔可夫不止基于前一个词,而是基于前几个词\n",
"- 3. 对概率进行转换,保证相加为1"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 搭建一个分词工具\n",
"\n",
"### Part 1 基于枚举方法来搭建中文分词工具\n",
"\n",
"此项目需要的数据:\n",
"1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用(第二列:词频+词性)\n",
"2. 以变量的方式提供了部分unigram概率 word_prob\n",
"\n",
"\n",
"举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15\n",
"\n",
"#### Step 1: 对于给定字符串:”我们学习人工智能,人工智能是未来“, 找出所有可能的分割方式\n",
"- [我们,学习,人工智能,人工智能,是,未来]\n",
"- [我们,学习,人工,智能,人工智能,是,未来]\n",
"- [我们,学习,人工,智能,人工,智能,是,未来]\n",
"- [我们,学习,人工智能,人工,智能,是,未来]\n",
".......\n",
"\n",
"\n",
"#### Step 2: 我们也可以计算出每一个切分之后句子的概率\n",
"- p(我们,学习,人工智能,人工智能,是,未来)= -log p(我们)-log p(学习)-log p(人工智能)-log p(人工智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工,智能,人工智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工,智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工)-log p(智能)-log p(人工)-log p(智能)-log p(是)-log p(未来)\n",
"- p(我们,学习,人工智能,人工,智能,是,未来)=-log p(我们)-log p(学习)-log p(人工智能)-log p(人工)-log p(智能)-log(是)-log p(未来)\n",
".....\n",
"\n",
"#### Step 3: 返回第二步中概率最大的结果"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import pandas as pd\n",
"import numpy as np"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"['酢',\n",
" '做做事',\n",
" '做做饭',\n",
" '做做',\n",
" '做作',\n",
" '做主',\n",
" '做针线',\n",
" '做张做智',\n",
" '做张做致',\n",
" '做张做势',\n",
" '做贼心虚',\n",
" '做月子',\n",
" '做一天和尚撞一天钟',\n",
" '做一日和尚撞一天钟',\n",
" '做秀',\n",
" '做小伏低',\n",
" '做戏',\n",
" '做文章',\n",
" '做为',\n",
" '做头',\n",
" '做通',\n",
" '做私商勾当',\n",
" '做寿',\n",
" '做手脚',\n",
" '做事',\n",
" '做市商',\n",
" '做生意',\n",
" '做生日',\n",
" '做神做鬼',\n",
" '做人做世',\n",
" '做人',\n",
" '做起',\n",
" '做派',\n",
" '做梦',\n",
" '做媒',\n",
" '做礼拜',\n",
" '做客',\n",
" '做假账',\n",
" '做家教',\n",
" '做活儿',\n",
" '做活',\n",
" '做好做恶',\n",
" '做好做歹',\n",
" '做好',\n",
" '做鬼做神',\n",
" '做鬼',\n",
" '做官者',\n",
" '做官当老爷',\n",
" '做官',\n",
" '做功',\n",
" '做工精细',\n",
" '做工',\n",
" '做刚做柔',\n",
" '做饭',\n",
" '做法',\n",
" '做东道',\n",
" '做东',\n",
" '做到',\n",
" '做大做强',\n",
" '做出',\n",
" '做成',\n",
" '做操',\n",
" '做菜',\n",
" '做不了',\n",
" '做伴',\n",
" '做爱',\n",
" '做',\n",
" '座座',\n",
" '座子',\n",
" '座钟',\n",
" '座右铭',\n",
" '座椅',\n",
" '座像',\n",
" '座向',\n",
" '座席',\n",
" '座无虚席',\n",
" '座位图',\n",
" '座位数',\n",
" '座位号',\n",
" '座位费',\n",
" '座位表',\n",
" '座位',\n",
" '座套',\n",
" '座谈会',\n",
" '座谈',\n",
" '座上客',\n",
" '座上宾',\n",
" '座山峰',\n",
" '座山雕',\n",
" '座圈',\n",
" '座区',\n",
" '座骑',\n",
" '座票',\n",
" '座盘',\n",
" '座落在',\n",
" '座落',\n",
" '座楼',\n",
" '座架',\n",
" '座驾',\n",
" '座机',\n",
" '座环',\n",
" '座号',\n",
" '座豪华',\n",
" '座垫',\n",
" '座次',\n",
" '座充',\n",
" '座车',\n",
" '座厕',\n",
" '座舱',\n",
" '座标',\n",
" '座便器',\n",
" '座便',\n",
" '座',\n",
" '唑',\n",
" '祚庆',\n",
" '祚',\n",
" '胙',\n",
" '怍',\n",
" '阼',\n",
" '坐坐',\n",
" '坐姿',\n",
" '坐庄',\n",
" '坐支',\n",
" '坐镇',\n",
" '坐诊',\n",
" '坐在',\n",
" '坐运筹策',\n",
" '坐月子',\n",
" '坐浴',\n",
" '坐于涂炭',\n",
" '坐拥书城',\n",
" '坐拥百城',\n",
" '坐椅',\n",
" '坐以待旦',\n",
" '坐以待毙',\n",
" '坐药',\n",
" '坐言起行',\n",
" '坐薪悬胆',\n",
" '坐薪尝胆',\n",
" '坐像',\n",
" '坐享其功',\n",
" '坐享其成',\n",
" '坐下',\n",
" '坐席',\n",
" '坐无虚席',\n",
" '坐卧针毡',\n",
" '坐卧不宁',\n",
" '坐卧不离',\n",
" '坐卧不安',\n",
" '坐位表',\n",
" '坐位',\n",
" '坐堂',\n",
" '坐探',\n",
" '坐台',\n",
" '坐树无言',\n",
" '坐树不言',\n",
" '坐守',\n",
" '坐收渔利',\n",
" '坐收',\n",
" '坐视成败',\n",
" '坐视不救',\n",
" '坐视不管',\n",
" '坐视',\n",
" '坐式',\n",
" '坐食山空',\n",
" '坐失事机',\n",
" '坐失良机',\n",
" '坐失机宜',\n",
" '坐失',\n",
" '坐上琴心',\n",
" '坐商',\n",
" '坐山观虎斗',\n",
" '坐山雕',\n",
" '坐骑',\n",
" '坐盆',\n",
" '坐喷气式',\n",
" '坐南朝北',\n",
" '坐落',\n",
" '坐立不安',\n",
" '坐力',\n",
" '坐冷板凳',\n",
" '坐牢',\n",
" '坐困愁城',\n",
" '坐客',\n",
" '坐具',\n",
" '坐井观天',\n",
" '坐禁闭',\n",
" '坐江山',\n",
" '坐监',\n",
" '坐怀不乱',\n",
" '坐化',\n",
" '坐果',\n",
" '坐观成败',\n",
" '坐骨神经',\n",
" '坐骨',\n",
" '坐功',\n",
" '坐而论道',\n",
" '坐而待旦',\n",
" '坐而待弊',\n",
" '坐而待毙',\n",
" '坐墩',\n",
" '坐蔸',\n",
" '坐定',\n",
" '坐垫',\n",
" '坐地自划',\n",
" '坐地分脏',\n",
" '坐地分赃',\n",
" '坐地',\n",
" '坐凳',\n",
" '坐等',\n",
" '坐待',\n",
" '坐大',\n",
" '坐次',\n",
" '坐床',\n",
" '坐船',\n",
" '坐筹帷幄',\n",
" '坐吃山空',\n",
" '坐吃山崩',\n",
" '坐车',\n",
" '坐禅',\n",
" '坐厕',\n",
" '坐舱',\n",
" '坐不重席',\n",
" '坐不窥堂',\n",
" '坐不改姓',\n",
" '坐不垂堂',\n",
" '坐不安席',\n",
" '坐标轴',\n",
" '坐标系',\n",
" '坐标',\n",
" '坐便器',\n",
" '坐便',\n",
" '坐北朝南',\n",
" '坐班制',\n",
" '坐班',\n",
" '坐',\n",
" '作作有芒',\n",
" '作作',\n",
" '作祖',\n",
" '作子',\n",
" '作主',\n",
" '作忠',\n",
" '作证',\n",
" '作者投稿',\n",
" '作者群',\n",
" '作者',\n",
" '作哲',\n",
" '作战室',\n",
" '作战区',\n",
" '作战科',\n",
" '作战服',\n",
" '作战处',\n",
" '作战部',\n",
" '作战',\n",
" '作贼心虚',\n",
" '作育人材',\n",
" '作用力',\n",
" '作用点',\n",
" '作用',\n",
" '作勇',\n",
" '作翊',\n",
" '作役',\n",
" '作义',\n",
" '作揖',\n",
" '作业组',\n",
" '作业证',\n",
" '作业者',\n",
" '作业员',\n",
" '作业线',\n",
" '作业题',\n",
" '作业区',\n",
" '作业面',\n",
" '作业率',\n",
" '作业流程',\n",
" '作业量',\n",
" '作业机',\n",
" '作业费',\n",
" '作业队',\n",
" '作业点',\n",
" '作业车',\n",
" '作业本',\n",
" '作业',\n",
" '作言造语',\n",
" '作训服',\n",
" '作训',\n",
" '作秀',\n",
" '作兴',\n",
" '作协',\n",
" '作孝',\n",
" '作小服低',\n",
" '作响',\n",
" '作宪',\n",
" '作息时间',\n",
" '作息',\n",
" '作物',\n",
" '作务衣',\n",
" '作武',\n",
" '作文指导',\n",
" '作文网',\n",
" '作文题',\n",
" '作文课',\n",
" '作文辅导',\n",
" '作文簿',\n",
" '作文本',\n",
" '作文',\n",
" '作伪者',\n",
" '作伪',\n",
" '作为',\n",
" '作威作福',\n",
" '作威',\n",
" '作图',\n",
" '作田',\n",
" '作态',\n",
" '作祟',\n",
" '作手脚',\n",
" '作适',\n",
" '作势',\n",
" '作士',\n",
" '作生',\n",
" '作舍道旁',\n",
" '作舍道边',\n",
" '作善降祥',\n",
" '作善',\n",
" '作如是观',\n",
" '作人',\n",
" '作曲者',\n",
" '作曲系',\n",
" '作曲家',\n",
" '作曲法',\n",
" '作曲编曲',\n",
" '作曲',\n",
" '作乔',\n",
" '作品展示',\n",
" '作品展览',\n",
" '作品展',\n",
" '作品阅读',\n",
" '作品选',\n",
" '作品欣赏',\n",
" '作品赏析',\n",
" '作品目录',\n",
" '作品列表',\n",
" '作品简介',\n",
" '作品集',\n",
" '作品',\n",
" '作陪',\n",
" '作派',\n",
" '作呕',\n",
" '作弄',\n",
" '作孽',\n",
" '作鸟兽散',\n",
" '作难',\n",
" '作牧',\n",
" '作民',\n",
" '作美',\n",
" '作梅',\n",
" '作洛',\n",
" '作乱',\n",
" '作料',\n",
" '作乐',\n",
" '作浪兴风',\n",
" '作朗',\n",
" '作客思想',\n",
" '作客',\n",
" '作金石声',\n",
" '作娇',\n",
" '作践',\n",
" '作贱',\n",
" '作件',\n",
" '作茧自缚',\n",
" '作奸犯科',\n",
" '作嫁衣裳',\n",
" '作价',\n",
" '作假者',\n",
" '作假',\n",
" '作家作品',\n",
" '作家资料',\n",
" '作家在线',\n",
" '作家杂志',\n",
" '作家协会',\n",
" '作家网',\n",
" '作家群',\n",
" '作家风景',\n",
" '作家档案',\n",
" '作家出版社',\n",
" '作家',\n",
" '作画',\n",
" '作好作歹',\n",
" '作好',\n",
" '作翰',\n",
" '作鬼',\n",
" '作怪',\n",
" '作谷',\n",
" '作古正经',\n",
" '作古',\n",
" '作工',\n",
" '作梗',\n",
" '作福作威',\n",
" '作孚',\n",
" '作夫',\n",
" '作风建设',\n",
" '作风',\n",
" '作废',\n",
" '作坊式',\n",
" '作坊',\n",
" '作范',\n",
" '作法自弊',\n",
" '作法自毙',\n",
" '作法',\n",
" '作伐',\n",
" '作恶者',\n",
" '作恶多端',\n",
" '作恶',\n",
" '作厄',\n",
" '作对',\n",
" '作东',\n",
" '作登乡',\n",
" '作到',\n",
" '作代会',\n",
" '作大',\n",
" '作答',\n",
" '作词家',\n",
" '作词',\n",
" '作辍无常',\n",
" '作出',\n",
" '作成',\n",
" '作宾',\n",
" '作别',\n",
" '作壁上观',\n",
" '作弊器',\n",
" '作弊',\n",
" '作保',\n",
" '作伴儿',\n",
" '作伴',\n",
" '作罢',\n",
" '作案者',\n",
" '作案人',\n",
" '作案',\n",
" '作',\n",
" '佐佐木元',\n",
" '佐佐木',\n",
" '佐佐',\n",
" '佐助',\n",
" '佐竹',\n",
" '佐州',\n",
" '佐治亚州',\n",
" '佐治亚大学',\n",
" '佐治亚',\n",
" '佐治',\n",
" '佐织',\n",
" '佐之才',\n",
" '佐证',\n",
" '佐钊',\n",
" '佐佑',\n",
" '佐饔得尝',\n",
" '佐雍得尝',\n",
" '佐雍得',\n",
" '佐弋',\n",
" '佐伊',\n",
" '佐野',\n",
" '佐享',\n",
" '佐相',\n",
" '佐维奇',\n",
" '佐托夫',\n",
" '佐藤嘉恭',\n",
" '佐藤',\n",
" '佐特',\n",
" '佐塔',\n",
" '佐书',\n",
" '佐使',\n",
" '佐山',\n",
" '佐人',\n",
" '佐钦',\n",
" '佐派',\n",
" '佐纳',\n",
" '佐幕',\n",
" '佐谋',\n",
" '佐默',\n",
" '佐命',\n",
" '佐米曲坦',\n",
" '佐美',\n",
" '佐洛埃格塞格',\n",
" '佐洛',\n",
" '佐罗',\n",
" '佐卢',\n",
" '佐林',\n",
" '佐料',\n",
" '佐理',\n",
" '佐拉',\n",
" '佐克',\n",
" '佐卡',\n",
" '佐酒',\n",
" '佐剂',\n",
" '佐欢',\n",
" '佐贺县',\n",
" '佐贺',\n",
" '佐哈尔',\n",
" '佐国',\n",
" '佐攻者',\n",
" '佐格',\n",
" '佐夫斯基',\n",
" '佐夫',\n",
" '佐法尔',\n",
" '佐尔坦',\n",
" '佐尔格',\n",
" '佐尔',\n",
" '佐恩',\n",
" '佐渡岛',\n",
" '佐斗',\n",
" '佐登',\n",
" '佐村镇',\n",
" '佐川',\n",
" '佐车',\n",
" '佐餐',\n",
" '佐伯',\n",
" '佐埃',\n",
" '佐',\n",
" '左左右右',\n",
" '左宗棠',\n",
" '左枝右梧',\n",
" '左支右吾',\n",
" '左支右调',\n",
" '左支右绌',\n",
" '左证',\n",
" '左镇乡',\n",
" '左镇',\n",
" '左云县',\n",
" '左云',\n",
" '左右翼',\n",
" '左右眼',\n",
" '左右为难',\n",
" '左右腿',\n",
" '左右图史',\n",
" '左右手',\n",
" '左右脑',\n",
" '左右两难',\n",
" '左右开弓',\n",
" '左右江',\n",
" '左右逢源',\n",
" '左右逢原',\n",
" '左右方',\n",
" '左右侧',\n",
" '左右采获',\n",
" '左右岸',\n",
" '左右',\n",
" '左拥右抱',\n",
" '左萦右拂',\n",
" '左营',\n",
" '左翼文化运动',\n",
" '左翼',\n",
" '左宜右有',\n",
" '左宜右宜',\n",
" '左眼',\n",
" '左延安',\n",
" '左旋肉碱',\n",
" '左旋炔诺孕酮',\n",
" '左旋咪唑涂布剂',\n",
" '左旋',\n",
" '左舷',\n",
" '左贤王',\n",
" '左贤',\n",
" '左下角',\n",
" '左下方',\n",
" '左下',\n",
" '左膝',\n",
" '左溪',\n",
" '左文襄公',\n",
" '左文',\n",
" '左腿',\n",
" '左徒',\n",
" '左图右书',\n",
" '左图右史',\n",
" '左图',\n",
" '左铁镛',\n",
" '左天觉',\n",
" '左提右挈',\n",
" '左藤',\n",
" '左思右想',\n",
" '左思',\n",
" '左司马',\n",
" '左书右息',\n",
" '左首',\n",
" '左手指',\n",
" '左手腕',\n",
" '左手画方',\n",
" '左手',\n",
" '左上角',\n",
" '左上方',\n",
" '左上臂',\n",
" '左上',\n",
" '左嗓子',\n",
" '左炔诺孕酮',\n",
" '左券',\n",
" '左权县',\n",
" '左权墓',\n",
" '左权',\n",
" '左丘明',\n",
" '左晴雯',\n",
" '左倾机会主义',\n",
" '左倾',\n",
" '左强',\n",
" '左前卫',\n",
" '左铅右椠',\n",
" '左迁',\n",
" '左旗',\n",
" '左撇子',\n",
" '左膀右臂',\n",
" '左膀',\n",
" '左派',\n",
" '左木',\n",
" '左民党',\n",
" '左面',\n",
" '左绵',\n",
" '左满舵',\n",
" '左轮手枪',\n",
" '左轮',\n",
" '左路',\n",
" '左岭镇',\n",
" '左麟右李',\n",
" '左邻右舍',\n",
" '左邻右里',\n",
" '左列',\n",
" '左联五烈士',\n",
" '左联',\n",
" '左连璧',\n",
" '左拉',\n",
" '左近',\n",
" '左金丸',\n",
" '左脚',\n",
" '左江日报',\n",
" '左江',\n",
" '左键',\n",
" '左家庄',\n",
" '左家塘',\n",
" '左家',\n",
" '左焕琮',\n",
" '左焕琛',\n",
" '左后卫',\n",
" '左行',\n",
" '左海',\n",
" '左归丸',\n",
" '左顾右盼',\n",
" '左顾右眄',\n",
" '左贡县',\n",
" '左贡',\n",
" '左公柳',\n",
" '左各庄镇',\n",
" '左辅右弼',\n",
" '左锋',\n",
" '左方',\n",
" '左耳',\n",
" '左躲右闪',\n",
" '左端',\n",
" '左道旁门',\n",
" '左传',\n",
" '左丞相',\n",
" '左侧',\n",
" '左不过',\n",
" '左边前卫',\n",
" '左边锋',\n",
" '左边',\n",
" '左臂右膀',\n",
" '左臂',\n",
" '左岸',\n",
" '左安门',\n",
" '左安龙',\n",
" '左安安',\n",
" '左',\n",
" '阝',\n",
" '昨夜',\n",
" '昨晚',\n",
" '昨天',\n",
" '昨日',\n",
" '昨儿个',\n",
" '昨儿',\n",
" '昨',\n",
" '嘬嘬',\n",
" '嘬',\n",
" '撙撙',\n",
" '撙节',\n",
" '撙',\n",
" '鳟鱼',\n",
" '鳟',\n",
" '樽俎折冲',\n",
" '樽俎',\n",
" '樽前月下',\n",
" '樽',\n",
" '遵嘱',\n",
" '遵照',\n",
" '遵章守纪',\n",
" '遵章率',\n",
" '遵义县',\n",
" '遵义钛厂',\n",
" '遵义市政府',\n",
" '遵义市委',\n",
" '遵义市',\n",
" '遵义会议',\n",
" '遵义供电局',\n",
" '遵义',\n",
" '遵业',\n",
" '遵尧',\n",
" '遵养时晦',\n",
" '遵养晦时',\n",
" '遵养待时',\n",
" '遵厌兆祥',\n",
" '遵循',\n",
" '遵学',\n",
" '遵序',\n",
" '遵信',\n",
" '遵帅',\n",
" '遵守宪法',\n",
" '遵守',\n",
" '遵时养晦',\n",
" '遵生',\n",
" '遵钦',\n",
" '遵命',\n",
" '遵理',\n",
" '遵礼',\n",
" '遵敬',\n",
" '遵纪守法户',\n",
" '遵纪守法',\n",
" '遵纪爱民',\n",
" '遵纪',\n",
" '遵化县',\n",
" '遵化市',\n",
" '遵化',\n",
" '遵鸿',\n",
" '遵行',\n",
" '遵海',\n",
" '遵复',\n",
" '遵奉',\n",
" '遵法',\n",
" '遵而勿失',\n",
" '遵而不失',\n",
" '遵典',\n",
" '遵德',\n",
" '遵道秉义',\n",
" '遵道',\n",
" '遵从',\n",
" '遵',\n",
" '尊俎折冲',\n",
" '尊主泽民',\n",
" '尊主',\n",
" '尊重',\n",
" '尊者',\n",
" '尊长',\n",
" '尊章',\n",
" '尊造',\n",
" '尊远',\n",
" '尊仪',\n",
" '尊严感',\n",
" '尊严',\n",
" '尊萱',\n",
" '尊姓大名',\n",
" '尊姓',\n",
" '尊幸',\n",
" '尊贤使能',\n",
" '尊贤',\n",
" '尊无二上',\n",
" '尊翁',\n",
" '尊为',\n",
" '尊威',\n",
" '尊特拉',\n",
" '尊堂',\n",
" '尊肃',\n",
" '尊寿',\n",
" '尊师重教',\n",
" '尊师重道',\n",
" '尊师贵道',\n",
" '尊师',\n",
" '尊盛',\n",
" '尊胜陀罗尼经幢',\n",
" '尊胜',\n",
" '尊神',\n",
" '尊尚',\n",
" '尊容',\n",
" '尊荣',\n",
" '尊亲',\n",
" '尊年尚齿',\n",
" '尊明',\n",
" '尊礼',\n",
" '尊老敬老',\n",
" '尊老爱幼',\n",
" '尊老',\n",
" '尊君',\n",
" '尊爵',\n",
" '尊敬',\n",
" '尊介',\n",
" '尊驾',\n",
" '尊纪',\n",
" '尊华',\n",
" '尊厚',\n",
" '尊号',\n",
" '尊行',\n",
" '尊贵',\n",
" '尊古卑今',\n",
" '尊公',\n",
" '尊庚',\n",
" '尊刚',\n",
" '尊府',\n",
" '尊甫',\n",
" '尊夫人',\n",
" '尊奉',\n",
" '尊范',\n",
" '尊慈',\n",
" '尊宠',\n",
" '尊崇',\n",
" '尊驰',\n",
" '尊称',\n",
" '尊卑',\n",
" '尊宝',\n",
" '尊安',\n",
" '尊',\n",
" '醉枣',\n",
" '醉玉颓山',\n",
" '醉鱼草',\n",
" '醉意',\n",
" '醉眼',\n",
" '醉醺醺',\n",
" '醉心',\n",
" '醉乡',\n",
" '醉舞狂歌',\n",
" '醉舞',\n",
" '醉翁之意不在酒',\n",
" '醉翁亭记',\n",
" '醉翁亭',\n",
" '醉吐相茵',\n",
" '醉态',\n",
" '醉死梦生',\n",
" '醉生梦死',\n",
" '醉山颓倒',\n",
" '醉人',\n",
" '醉拳',\n",
" '醉梦花',\n",
" '醉马草',\n",
" '醉酒者',\n",
" '醉酒饱德',\n",
" '醉酒',\n",
" '醉鸡',\n",
" '醉话',\n",
" '醉汉',\n",
" '醉鬼',\n",
" '醉白池',\n",
" '醉',\n",
" '蕞',\n",
" '罪状',\n",
" '罪证',\n",
" '罪责难逃',\n",
" '罪责',\n",
" '罪有攸归',\n",
" '罪有应得',\n",
" '罪应万死',\n",
" '罪业深重',\n",
" '罪业',\n",
" '罪人不孥',\n",
" '罪人',\n",
" '罪愆',\n",
" '罪孽深重',\n",
" '罪孽',\n",
" '罪逆深重',\n",
" '罪名',\n",
" '罪魁祸首',\n",
" '罪魁',\n",
" '罪加一等',\n",
" '罪行',\n",
" '罪过形式',\n",
" '罪过',\n",
" '罪该万死',\n",
" '罪犯',\n",
" '罪恶滔天',\n",
" '罪恶贯盈',\n",
" '罪恶感',\n",
" '罪恶都市',\n",
" '罪恶的黑手',\n",
" '罪恶',\n",
" '罪当万死',\n",
" '罪大恶极',\n",
" '罪错',\n",
" '罪不胜诛',\n",
" '罪不容诛',\n",
" '罪不容赦',\n",
" '罪不可逭',\n",
" '罪案率',\n",
" '罪案',\n",
" '罪',\n",
" '最最',\n",
" '最重',\n",
" '最终幻想',\n",
" '最终',\n",
" '最长',\n",
" '最早',\n",
" '最远点',\n",
" '最远',\n",
" '最游记',\n",
" '最优化',\n",
" '最新作品',\n",
" '最新咨讯',\n",
" '最新专辑',\n",
" '最新政策',\n",
" '最新招聘',\n",
" '最新战况',\n",
" '最新在线',\n",
" '最新音乐',\n",
" '最新讯息',\n",
" '最新型',\n",
" '最新消息',\n",
" '最新下载',\n",
" '最新文章',\n",
" '最新图片',\n",
" '最新商情',\n",
" '最新软件',\n",
" '最新期刊',\n",
" '最新漏洞',\n",
" '最新楼盘',\n",
" '最新景点',\n",
" '最新技术',\n",
" '最新活动',\n",
" '最新公告',\n",
" '最新更新',\n",
" '最新法规',\n",
" '最新发行',\n",
" '最新电影',\n",
" '最新大片',\n",
" '最新产品',\n",
" '最新报价',\n",
" '最新报道',\n",
" '最新版',\n",
" '最新',\n",
" '最小化',\n",
" '最小公倍数',\n",
" '最小',\n",
" '最先',\n",
" '最为',\n",
" '最深',\n",
" '最少',\n",
" '最全面',\n",
" '最全',\n",
" '最轻量级',\n",
" '最强音',\n",
" '最强',\n",
" '最前沿',\n",
" '最起码',\n",
" '最末',\n",
" '最美',\n",
" '最快',\n",
" '最近新书',\n",
" '最近似值',\n",
" '最近',\n",
" '最简式',\n",
" '最简论坛',\n",
" '最简分数',\n",
" '最佳期',\n",
" '最佳奖',\n",
" '最佳化',\n",
" '最佳',\n",
" '最惠国待遇',\n",
" '最惠国',\n",
" '最惠',\n",
" '最後',\n",
" '最后战士',\n",
" '最后一秒',\n",
" '最后通牒',\n",
" '最后通谍',\n",
" '最后的晚餐',\n",
" '最后的审判',\n",
" '最后的爱',\n",
" '最后',\n",
" '最好',\n",
" '最高值',\n",
" '最高者',\n",
" '最高院',\n",
" '最高人民检察院政治部',\n",
" '最高人民检察院',\n",
" '最高人民法院审判委员会',\n",
" '最高人民法院党组',\n",
" '最高人民法院',\n",
" '最高检察院',\n",
" '最高检',\n",
" '最高价',\n",
" '最高级',\n",
" '最高峰',\n",
" '最高分',\n",
" '最高法院',\n",
" '最高额',\n",
" '最高点',\n",
" '最高处',\n",
" '最高潮',\n",
" '最高层',\n",
" '最高',\n",
" '最底层',\n",
" '最低值',\n",
" '最低限',\n",
" '最低价',\n",
" '最低谷',\n",
" '最低点',\n",
" '最低',\n",
" '最大值',\n",
" '最大者',\n",
" '最大化',\n",
" '最大公约数',\n",
" '最大',\n",
" ...]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import xlrd \n",
"data=xlrd.open_workbook('综合类中文词库.xlsx')#excle文件位置\n",
"sheet=data.sheets()[0] #读取第一bai个表du\n",
"col=sheet.col_values(0) #读取第一列\n",
"col"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.0000000000000002\n"
]
}
],
"source": [
"# TODO: 第一步: 从综合类中文词库.xlsx 中读取所有中文词。\n",
"# hint: 思考一下用什么数据结构来存储这个词典会比较好? 要考虑我们每次查询一个单词的效率。 \n",
"max_len_word = 0\n",
"dic_words = {} # 保存词典库中读取的单词\n",
"for word in col:\n",
" dic_words[word] = 0.00001\n",
" len_word = len(word)\n",
" if len_word > max_len_word:\n",
" max_len_word = len_word\n",
"\n",
"# 以下是每一个单词出现的概率。为了问题的简化,我们只列出了一小部分单词的概率。 在这里没有出现的的单词但是出现在词典里的,统一把概率设置成为0.00001\n",
"# 比如 p(\"学院\")=p(\"概率\")=...0.00001\n",
"\n",
"word_prob = {\"北京\":0.03,\"的\":0.08,\"天\":0.005,\"气\":0.005,\"天气\":0.06,\"真\":0.04,\"好\":0.05,\"真好\":0.04,\"啊\":0.01,\"真好啊\":0.02, \n",
" \"今\":0.01,\"今天\":0.07,\"课程\":0.06,\"内容\":0.06,\"有\":0.05,\"很\":0.03,\"很有\":0.04,\"意思\":0.06,\"有意思\":0.005,\"课\":0.01,\n",
" \"程\":0.005,\"经常\":0.08,\"意见\":0.08,\"意\":0.01,\"见\":0.005,\"有意见\":0.02,\"分歧\":0.04,\"分\":0.02, \"歧\":0.005}\n",
"\n",
"for key, values in word_prob.items():\n",
" dic_words[key] = values\n",
"\n",
"print (sum(word_prob.values()))"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"def segment(input_str):\n",
" segments = [] # 存储所有分词的结果。如果次字符串不可能被完全切分,则返回空列表(list)\n",
" len_input_str = len(input_str)\n",
" if len_input_str == 0: # 空字符串\n",
" return [segments]\n",
" else:\n",
" result = []\n",
" for idx in range(1, len_input_str + 1):\n",
" if input_str[:idx] in dic_words:\n",
" for remain_segment in segment(input_str[idx:]):\n",
" result.append([input_str[:idx]] + remain_segment)\n",
" return result"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"## TODO 请编写word_segment_naive函数来实现对输入字符串的分词\n",
"def word_segment_naive(input_str):\n",
" \"\"\"\n",
" 1. 对于输入字符串做分词,并返回所有可行的分词之后的结果。\n",
" 2. 针对于每一个返回结果,计算句子的概率\n",
" 3. 返回概率最高的最作为最后结果\n",
" \n",
" input_str: 输入字符串 输入格式:“今天天气好”\n",
" best_segment: 最好的分词结果 输出格式:[\"今天\",\"天气\",\"好\"]\n",
" \"\"\"\n",
"\n",
" # TODO: 第一步: 计算所有可能的分词结果,要保证每个分完的词存在于词典里,这个结果有可能会非常多。 \n",
" segments = segment(input_str) # 存储所有分词的结果。如果次字符串不可能被完全切分,则返回空列表(list)\n",
" # 格式为:segments = [[\"今天\",“天气”,“好”],[\"今天\",“天“,”气”,“好”],[\"今“,”天\",“天气”,“好”],...] \n",
" \n",
" # TODO: 第二步:循环所有的分词结果,并计算出概率最高的分词结果,并返回\n",
" best_score = np.inf\n",
" for seg in segments:\n",
" score = 0\n",
" for word in seg:\n",
" score -= np.log(dic_words[word])\n",
" if score < best_score:\n",
" best_score = score\n",
" best_segment = seg \n",
" \n",
" return best_segment "
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['北京', '的', '天气', '真好啊']\n",
"['今天', '的', '课程', '内容', '很有', '意思']\n",
"['经常', '有意见', '分歧']\n"
]
}
],
"source": [
"# 测试\n",
"print (word_segment_naive(\"北京的天气真好啊\"))\n",
"print (word_segment_naive(\"今天的课程内容很有意思\"))\n",
"print (word_segment_naive(\"经常有意见分歧\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Part 2 基于维特比算法来优化上述流程\n",
"\n",
"此项目需要的数据:\n",
"1. 综合类中文词库.xlsx: 包含了中文词,当做词典来用\n",
"2. 以变量的方式提供了部分unigram概率word_prob\n",
"\n",
"\n",
"举个例子: 给定词典=[我们 学习 人工 智能 人工智能 未来 是], 另外我们给定unigram概率:p(我们)=0.25, p(学习)=0.15, p(人工)=0.05, p(智能)=0.1, p(人工智能)=0.2, p(未来)=0.1, p(是)=0.15\n",
"\n",
"#### Step 1: 根据词典,输入的句子和 word_prob来创建带权重的有向图(Directed Graph) 参考:课程内容\n",
"有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率已经给出(存放在word_prob)。\n",
"注意:思考用什么方式来存储这种有向图比较合适? 不一定只有一种方式来存储这种结构。 \n",
"\n",
"#### Step 2: 编写维特比算法(viterebi)算法来找出其中最好的PATH, 也就是最好的句子切分\n",
"具体算法参考课程中讲过的内容\n",
"\n",
"#### Step 3: 返回结果\n",
"跟PART 1的要求一致"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
"## TODO 请编写word_segment_viterbi函数来实现对输入字符串的分词\n",
"def word_segment_viterbi(input_str):\n",
" \"\"\"\n",
" 1. 基于输入字符串,词典,以及给定的unigram概率来创建DAG(有向图)。\n",
" 2. 编写维特比算法来寻找最优的PATH\n",
" 3. 返回分词结果\n",
" \n",
" input_str: 输入字符串 输入格式:“今天天气好”\n",
" best_segment: 最好的分词结果 输出格式:[\"今天\",\"天气\",\"好\"]\n",
" \"\"\" \n",
" # TODO: 第一步:根据词典,输入的句子,以及给定的unigram概率来创建带权重的有向图(Directed Graph) 参考:课程内容\n",
" # 有向图的每一条边是一个单词的概率(只要存在于词典里的都可以作为一个合法的单词),这些概率在 word_prob,如果不在word_prob里的单词但在\n",
" # 词典里存在的,统一用概率值0.00001。\n",
" # 注意:思考用什么方式来存储这种有向图比较合适? 不一定有只有一种方式来存储这种结构。 \n",
" graph = {}\n",
" N = len(input_str)\n",
" for idx in range(N,-1,-1):\n",
" temp = []\n",
" for k in range(idx):\n",
" if input_str[k:idx] in dic_words:\n",
" temp.append(k)\n",
" graph[idx] = temp \n",
" \n",
" # TODO: 第二步: 利用维特比算法来找出最好的PATH, 这个PATH是P(sentence)最大或者 -log P(sentence)最小的PATH。\n",
" # hint: 思考为什么不用相乘: p(w1)p(w2)...而是使用negative log sum: -log(w1)-log(w2)-...\n",
" # 防止下溢出\n",
" res = [0]*(N+1)\n",
" last_index = [0]*(N+1)\n",
" for i in range(1,N+1):\n",
" temp = np.inf\n",
" for j in graph[i]:\n",
" if input_str[j:i] in dic_words:\n",
" if temp > res[j] - np.log(dic_words[input_str[j:i]]):\n",
" temp = res[j] - np.log(dic_words[input_str[j:i]])\n",
" last_index[i] = j\n",
" res[i] = temp\n",
" path = list(set(last_index))\n",
" \n",
" # TODO: 第三步: 根据最好的PATH, 返回最好的切分\n",
" len_path = len(path)\n",
" best_segment = [input_str[path[x]:path[x+1]] for x in range(len_path-1)]\n",
" best_segment.append(input_str[path[len_path-1]:])\n",
"\n",
" return best_segment "
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"scrolled": false
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['北京', '的', '天气', '真好啊']\n",
"['今天', '的', '课程', '内容', '很有', '意思']\n",
"['经常', '有', '意见', '分歧']\n"
]
}
],
"source": [
"# 测试\n",
"print(word_segment_viterbi(\"北京的天气真好啊\"))\n",
"print(word_segment_viterbi(\"今天的课程内容很有意思\"))\n",
"print(word_segment_viterbi(\"经常有意见分歧\"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# TODO: 第一种方法和第二种方法的时间复杂度和空间复杂度分别是多少?\n",
"网格宽度为D,长度为N \n",
"第一个方法: \n",
"时间复杂度= $O(D^N)$ , 空间复杂度= $O(D*N)$\n",
"\n",
"第二个方法:\n",
"时间复杂度= $O(nD^2)$, 空间复杂度= $O(D)$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# TODO:如果把上述的分词工具持续优化,有哪些可以考虑的方法? (至少列出3点)\n",
"- 0. (例), 目前的概率是不完整的,可以考虑大量的语料库,然后从中计算出每一个词出现的概率,这样更加真实\n",
"- 1. 概率太低的词可以不用记录,节约空间\n",
"- 2. 隐马尔可夫不止基于前一个词,而是基于前几个词\n",
"- 3. 对概率进行转换,保证相加为1"
]
},
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.6"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": true,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment