首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

代码详解:用Python构建邻域矩阵

全文共1522字,预计学习时长3分钟

如何构建邻域矩阵?只掌握理论知识,很难让人深入地了解这一问题。

本文我们以这样一个模型为例:

\tilde = W \cdot YY~=W⋅Y

其中W是一个矩阵,可以定义为(例如):

w_ = 1wij=1

当j在最临近i的K内,Wij=1,否则结果为0。

下面,我们将详细介绍通过使用numpy、scipy和matplotlib进行可视化来创建W矩阵的方法。

样本数据

为达到演示目的,我们创建了一个虚拟数据集,大小为N = 12个训练样本,M = 3个测试样本:

import numpy as np

XY_test = np.array([[1, 1], [-1, 1], [-1, -1], [1, -1]])

让我们来看看这些点的分布情况:红点是训练数据,而绿点是测试数据。

寻找邻域

用现代工具寻找邻域是非常简单的。在这里,我们选择使用scipy,因为稍后将使用这个软件包中的其他工具,但sklearn或其他软件包也可以完成这项工作。使用scipy时,首先使用训练数据集创建一个cKDTree:

from scipy.spatial import cKDTree

tree = cKDTree(XY_train)

可再次查询该tree:

K = 3

result = tree.query(XY_test, k=K)

在这里,我们需要测试样本元素中训练样本的三个最近邻域。默认情况下,tree.query返回邻域索引和相关距离。我们将保留两者。

distances, indices = result

让我们集中讨论索引数组。

array([[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]])

索引数组是一个numpy数组,包含M(测试样本数)行和K(邻域数)列。那么如何将其转换为我们需要的矩阵呢?示例如下:

在一个情节中看到所选邻域会很有趣:

import matplotlib.pyplot as plt

n = 0 # first element in the test dataset

xy_test = XY_test[n]

index = indices[n]

neighbours = XY_train[index]

plt.clf()

plt.scatter(xy_test[0], xy_test[1], color="red")

plt.scatter(neighbours[:,0], neighbours[:,1], color="blue")

plt.xlabel("x")

plt.ylabel("y")

plt.xlim(-2, 2)

plt.ylim(-2, 2)

plt.show()

好吧,所以邻域的寻找似乎和预期的一样有效!让我们了解如何将索引数组转换为完全可用的矩阵,我们的目的应该是:

1 1 1 0 0 0 0 0 0 0 0 0

0 0 0 1 1 1 0 0 0 0 0 0

0 0 0 0 0 0 1 1 1 0 0 0

0 0 0 0 0 0 0 0 0 1 1 1

因为测试观察0(第一行)的邻域是训练观察0,1和2,所以测试观察1(第二行)的邻域是训练观测3,4和5,依此类推。

创建矩阵

首先,我们将使用numpy索引创建这样的矩阵:

import numpy as np

a = np.array([1, 2, 3, 4, 5, 6])

i = [0, 0, 1, 1, 2, 2]

a[i]

# array([1, 1, 2, 2, 3, 3])

但你会发现它不适用于多维度数组。

我们选择的解决方案是使用scipy稀疏矩阵,其可在索引列表中创建。例如,使用稀疏矩阵创建大小为N = 4的对角矩阵,可以表示为:

from scipy import sparse

i_index = [0, 1, 2, 3]

j_index = [0, 1, 2, 3]

values = [1, 1, 1, 1]

matrix = sparse.coo_matrix((values, (i_index, j_index)), shape=(4, 4))

print(matrix)

# (0, 0)1

# (1, 1)1

# (2, 2)1

# (3, 3)1

因此scipy获取i_index和j_index数组的第一个元素i和j,并将values数组的第一个元素放在最终矩阵中的[i,j]位置。或者换句话说,元素(0,0)的值是1,元素(1,1)的值也是1 ...... 其他未特殊说明的元素的值都是零。

如果你更喜欢数组表示,可以输入以下代码查看结果:

matrix.toarray() # transforms sparse matrix into numpy array just for visualization

#array([[1, 0, 0, 0],

# [0, 1, 0, 0],

# [0, 0, 1, 0],

# [0, 0, 0, 1]])

这里你可以看到对角线矩阵。

让我们用第二个例子来更清楚地说明一切。现在要创建的是逆对角矩阵:

array([[0, 0, 0, 1], [0, 0, 1, 0], [0, 1, 0, 0], [1, 0, 0, 0]])

此次的编码是:

i_index = [3, 2, 1, 0] #

j_index = [0, 1, 2, 3]

values = [1, 1, 1, 1]

matrix = sparse.coo_matrix((values, (i_index, j_index)), shape=(4, 4))

注意:只有当矩阵规模相对较小时才能从稀疏表示切换到密集表示,否则会出现内存问题(稀疏矩阵存在的原因!)

如何创建W矩阵?

对于w矩阵,j_index(即“列”)对应相邻索引:

j_index = indices.flatten()

#array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11])

然后行索引i_index 对应测试样本中的索引,但需要重复K次以匹配j_index 排序:

i_index = np.repeat(np.array(range(M), dtype=int), repeats=K, axis=0).ravel()

#array([0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3])

这意味着在第一行(行索引0)的0、1和2列将有一个索引。在第二行(1)的第3、4、5列中会有一个索引……如果你再次查看测试/训练样本位置(第一个图),结果是一致的!

我们假设所有值为“1”:

values = np.ones(M * K) # M = number of test sample, K = number of neighbours

或者用取决于距离的函数表示,例如:

values = 1. / distances.flatten()**2

最后,我们的矩阵看起来像(值为“1”):

matrix = sparse.coo_matrix((values, (i_index, j_index)), shape=(M, N))

# array([[1., 1., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0.],

# [0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.],

# [0., 0., 0., 0., 0., 0., 1., 1., 1., 0., 0., 0.],

# [0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1.]])

回到我们最初的问题

现在,我们可以计算点积(使用稀疏或密集矩阵):

y_tilde = matrix.dot(y) # where y has shape (N, )

最后,问题解决啦!

留言 点赞 发个朋友圈

我们一起分享AI学习与发展的干货

编译组:王玲、狄思云

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20190202B0ES8100?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券