Skip to content

Latest commit

 

History

History

chapter05

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

最近邻域法

5.1 最近邻域法介绍

最近邻域算法的思想很简单,首先将训练集看作训练模型,然后基于新数据点与训练集的距离来预测新数据点。最直观的最近邻域算法是让预测值与最接近的训练数据集作为同一类。但是大部分样本数据集包含一定程序的噪声,更通用的方法是k个邻域的加权平均,该方法称为k最近邻域法(k-nearest neighbor, k-NN)。

假设样本训练集(x_1, x_2, ..., x_n), 对应的目标值(y_1, y_2, ..., y_n), 通过最近邻域法预测数据点z。预测的实际方法取决于我们是想做回归训练(连续型y_i)还是分类训练(离散型y_i)。

对于离散型分类目标,预测值由到预测数据点的加权距离的最大投票方案决定,公式如下:

f(z) = max(j, sum(i:=1->k, φ(d_i_j)*I_i_j

其中,预测函数f(z)是所有分类j上的最大加权值。预测数据点到训练数据点i的加权距离用φ(d_i_j)表示。I_i_j是指示函数,表示数据点i是否属于分类j。

对于连续回归训练目标,预测值是所有k个最近邻域数据点到预测数据点的加权平均,公式如下:

f(z) = 1/k * sum(i:=1->k, φ(d_i))

明显地,预测值严重依赖距离度量(d)方式的选择。常用的距离度量是L1范数和L2范数。公式如下:

d_L1(x_i, x_j) = |x_i-x_j|=|x_i_1-y_j_1|+|x_i_2-y_j_2| + ...
d_L2(x_i, x_j) = ||x_i - x_j|| = sqrt((x_i_1-x_j_1)**2 + (x_i_2+x_j_2)**2 + ... )

距离度量方式可选择性广,目前仅选用L1范数和L2范数,也会使用编辑距离和文本距离。

我们也需要选择如何加权距离。最直观的方式是用距离本身来加权,即加权权重为1。考虑到更近的数据点对预测数据点的预测值影响更小,因而最通用的加权方式是距离的归一化倒数。

注意,k-NN算法是一种聚合的方法。对于回归算法来说,需要计算邻域的加权平均距离,因而预测值将比实际目标值的特征更平缓。影响的程度将取决于k值,该值是算法中的邻域个数。

5.2 最近邻域法的使用

1. 导入必要的编辑库,创建一个计算图会话

2. 使用requests 模块加载数据集

3. 分离数据集为特征依赖的数据集和特征无关的数据集。

4. 分离x_vals值和y_vals值为训练数据集和测试数据集。随机选择80%的行作为训练集,剩下的20%数据行作为测试集

5. 声明k值和批量大小

6. 声明占位符。

7. 为批量测试集创建距离函数,这里使用L1范数距离

8. 创建预测函数。使用top_k()函数,其以张量的方式返回最大值的值和索引。因为需要找到最小距离的索引,所以将对最大距离取负。声明预测函数和目标值的均方误差(MSE)

9. 进行测试

10. 下面通过直方图来比较实际值和预测值。使用的是平均方法,所以在预测目标值最大和最小极值时遇到问题

5.3 如何度量文本距离

  • TensorFlow的文本距离度----字符串间的编辑距离(Levenshtein距离)。
  • Levenshtein距离是指由一个字符串转换成另一个字符串所需的最少编辑操作次数。允许的编辑操作包括插入一个字符,删除一个字符和将一个字符替换成另一个字符。使用TensorFlow的内建函数edit_distance()求解Levenshtein距离。

1. 加载TensorFlow,初始化一个计算图会话

2. 展示如何计算两个单词'bear'和'beer'间的编辑距离。用Python的list()函数创建字符list,然后将list映射为一个三维稀疏矩阵。TensorFlow的tf.SparseTensor()函数需指定字符索引、矩阵形状和张量中的非零值。编辑距离计算时,指定normalize=False表示计算总的编辑距离: 指定normalize=True表示计算归一化编辑距离,通过编辑距离除以第二个单词的长度进行归一化

3. 编辑距离计算结果如下

4. 下面比较两个单词bear和beer与另一个单词beers。为了做比较,需要重复beers使得比较的单词有相同的数量

5. 结果如下

6. 另外一种更有效地比较一个单词集合与单个单词的方法。事先为参考字符串(hypothesis)和真实字符串(ground)创建索引和字符列表

7. 结果如下

8. 展示如何用占位符来计算两个单词列表间的编辑距离。基本思路是一样的,不同的是现在用SparseTensorValue()替代先前稀疏张量。首先,创建一个函数,该函数根据单词列表,输出稀疏张量

9. 输出结果如下

  • 文本距离的度量方式
名称 描述 公式
汉明距离(Hamming distance) 两个等长字符串中对应位置的不同字符的个数 D(s1,s2) = sum(0,n,I_i),其中I是等长字符串的指示函数
余弦距离(Cosine distance) 不同k-gram的点积除以不同k-gram的L2范数 D(s1,s2) = 1-(k(s_1)k(s_2))/(||k(s_1)||||k(s_2)||)
Jaccard距离(Jaccard distance) 两个字符串中相同字符数除以所有字符数 D(s1,s2) = (|s_1且s_2|)/(|s_1并s_2|)

5.4 用TensorFlow实现混合距离计算

  • 当处理的数据观测点有多种特征时,我们应该意识到不同的特征应该用不同的归一化方式来缩放。
  • 扩展最近邻域法进行多维度缩放。下面将展示如何扩展多变量的距离函数。特别地,我们将扩展距离函数为特征变量的函数。
  • 加权距离函数的关键是使用加权权重矩阵。包含矩阵操作的距离函数的表达式如下:
D(x,y) = sqrt((x-y).T*A*(x-y))

其中,A是对角权重矩阵。

1. 导入必要的编程库,创建一个计算图会话

2. 加载数据集,存储为numpy数组。再次提醒,我们只使用某些列来预测,不使用id变量或者方差非常小的变量

3. 用min-max缩放法缩放x_vals值到0和1之间

4. 创建对角权重矩阵,该矩阵提供归一化的距离度量,其值为特征的标准差

5. 分割数据集为训练集和测试集。声明k值,该值为最近邻域的数量。设置批量大小为测试集大小

6. 声明所需的占位符。占位符有四个,分别是训练集和测试集的x值输入和y目标输入

7. 声明距离函数。为了使可读性更好,我们将距离函数分解。注意:本例需要tf.tile函数为权重矩阵指定batch_size维度扩展。使用matmul()函数进行批量矩阵乘法

8. 计算完每个测试数据点的距离,需要返回k-NN法的前k个最近邻域(使用tf.nn.top_k()函数)。因为tf.nn.top_k()函数返回最大值,而我们需要的是最小距离,所以转换成返回距离负值的最大值。然后将前k个最近邻域的距离进行加权平均做预测

9. 计算预测值的MSE,评估训练模型

10. 遍历迭代训练批量测试数据,每次迭代计算其MSE

11. 输出结果如下

12.为了最终对比,我们绘制测试数据集的房价分布和测试集上的预测值分布

5.5 用TensorFlow 实现地址匹配

1. 先导入必要的编程库

2. 创建参考数据集

3. 为了创建一个测试数据集,我们需要一个随机创建"打印错误"的字符函数,然后返回结果字符串

4. 初始化一个计算图会话,声明所需占位符

5. 声明数值的邮政编码距离和地址字符串的编辑距离

6. 把邮政编码距离和地址距离转换成相似度

7. 结合上面两个相似度函数,并对其进行加权平均

8. 为了在TensorFlow中使用编辑距离,我们必须把地址字符串转换成稀疏向量

9. 分离参考集中的地址和邮政编码,然后在遍历迭代中占位符赋值

10. 利用步骤8中创建的函数将参考地址转换为稀疏矩阵

11. 遍历循环测试集和每项,返回参考集中最接近的索引,打印出测试集和参考集的每项

12. 输出结果如下

5.6 用TensorFlow实现图像识别

1. 导入必要的编程库

2. 创建一个计算图会话,加载MNIST手写数字数据集,并指定one-hot编码

3. 由于MINIST手写数字数据集较大,直接计算成千上万个输入的784个特征之间的距离是比较困难的,所以本例会抽样成小数据集进行训练

4. 声明k值和批量的大小

5. 现在在计算图中开始初始化占位符,并赋值

6. 声明距离度量函数。本例使用L1范数(即绝对值)作为距离函数

7. 找到最接近的top k图片和预测模型。在数据集的one-hot编码索引上进行预测模型计算,然后统计发生的数量

8. 在测试集上遍历迭代运行,计算预测值,并将结果存储

9. 现在已经保存了实际值和预测返回值,下面计算模型训练准确度。不过该结果会因为测试数据集和训练数据集的随机抽样而变化,但是其准确度约为80%~90%

10. 绘制最后批次的计算结果