Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab K-最近邻的寻找及其实现_Matlab_Machine Learning_Classification_Knn - Fatal编程技术网

Matlab K-最近邻的寻找及其实现

Matlab K-最近邻的寻找及其实现,matlab,machine-learning,classification,knn,Matlab,Machine Learning,Classification,Knn,我正在使用欧几里德距离的KNN对简单数据进行分类。我已经看到了一个关于我想用MATLAB knnsearch函数实现的示例,如下所示: load fisheriris x = meas(:,3:4); gscatter(x(:,1),x(:,2),species) newpoint = [5 1.45]; [n,d] = knnsearch(x,newpoint,'k',10); line(x(n,1),x(n,2),'color',[.5 .5 .5],'marker','o','lines

我正在使用欧几里德距离的KNN对简单数据进行分类。我已经看到了一个关于我想用MATLAB knnsearch函数实现的示例,如下所示:

load fisheriris 
x = meas(:,3:4);
gscatter(x(:,1),x(:,2),species)
newpoint = [5 1.45];
[n,d] = knnsearch(x,newpoint,'k',10);
line(x(n,1),x(n,2),'color',[.5 .5 .5],'marker','o','linestyle','none','markersize',10)

上述代码获取一个新点,即[5 1.45],并找到与新点最近的10个值。有人能给我看一个MATLAB算法,详细解释knnsearch函数的作用吗?还有其他方法吗?

K近邻KNN算法的基础是,你有一个由N行和M列组成的数据矩阵,其中N是我们拥有的数据点的数量,而M是每个数据点的维数。例如,如果我们把笛卡尔坐标放在一个数据矩阵中,这通常是一个nx2或nx3矩阵。使用此数据矩阵,您可以提供一个查询点,并在此数据矩阵中搜索与此查询点最接近的k点

我们通常使用查询与数据矩阵中其他点之间的欧几里德距离来计算距离。但是,也使用其他距离,如L1或城市街区/曼哈顿距离。完成此操作后,将有N个欧几里德距离或曼哈顿距离,表示查询与数据集中每个对应点之间的距离。找到这些点后,只需按升序排序距离并检索数据集与查询之间距离最小的k个点,即可搜索距离查询最近的k个点

假设您的数据矩阵存储在x中,并且newpoint是一个样本点,其中有M列,即1 x M,这是您将以点形式遵循的一般过程:

求新点和x中每个点之间的欧几里德距离或曼哈顿距离。 按升序排列这些距离。 返回x中最接近newpoint的k个数据点。 让我们慢慢地走每一步

第一步 有人这样做的一种方式可能是这样的for循环:

N = size(x,1);
dists = zeros(N,1);
for idx = 1 : N
    dists(idx) = sqrt(sum((x(idx,:) - newpoint).^2));
end
如果您想要实现曼哈顿距离,这将是:

N = size(x,1);
dists = zeros(N,1);
for idx = 1 : N
    dists(idx) = sum(abs(x(idx,:) - newpoint));
end
dists是一个N元素向量,包含x中每个数据点和newpoint之间的距离。我们在新点和x中的数据点之间进行一个元素一个元素的减法,求差的平方,然后将它们全部加在一起。然后,这个和是平方根的,这就完成了欧几里德距离。对于曼哈顿距离,您将执行逐元素减法,取绝对值,然后将所有分量相加。这可能是最简单的实现,但可能是最低效的。。。特别是对于较大的数据集和数据的较大维度

另一种可能的解决方案是复制newpoint并使该矩阵与x的大小相同,然后对该矩阵进行逐元素减法,然后对每行的所有列求和并求平方根。因此,我们可以这样做:

N = size(x, 1);
dists = sqrt(sum((x - repmat(newpoint, N, 1)).^2, 2));
对于曼哈顿距离,您可以执行以下操作:

N = size(x, 1);
dists = sum(abs(x - repmat(newpoint, N, 1)), 2);
dists = sum(abs(bsxfun(@minus, x, newpoint)), 2);
获取一个矩阵或向量,并在给定方向上重复一定次数。在我们的例子中,我们希望得到我们的newpoint向量,并将其叠加N次,以创建一个nxm矩阵,其中每行有M个元素。我们将这两个矩阵相减,然后求每个分量的平方。一旦我们这样做了,我们对每一行的所有列求和,最后取所有结果的平方根。对于曼哈顿距离,我们做减法,取绝对值,然后求和

然而,在我看来,最有效的方法是使用。这实际上就是我们在幕后通过单个函数调用所讨论的复制。因此,代码应该是这样的:

dists = sqrt(sum(bsxfun(@minus, x, newpoint).^2, 2));
对我来说,这看起来更干净,更切中要害。对于曼哈顿距离,您可以执行以下操作:

N = size(x, 1);
dists = sum(abs(x - repmat(newpoint, N, 1)), 2);
dists = sum(abs(bsxfun(@minus, x, newpoint)), 2);
步骤2 既然我们有了距离,我们只需对它们进行排序。我们可以使用以下方法对距离进行排序:

[d,ind] = sort(dists);
d将包含按升序排序的距离,而ind将告诉您未排序数组中出现在排序结果中的每个值。我们需要使用ind,提取这个向量的前k个元素,然后使用ind索引到我们的x数据矩阵中,以返回最接近newpoint的点

步骤3 最后一步是现在返回最接近newpoint的k个数据点。我们可以通过以下方式非常简单地做到这一点:

ind_closest = ind(1:k);
x_closest = x(ind_closest,:);
ind_Nestest应包含原始数据矩阵x中最接近新点的索引。具体地说,ind_nextest包含需要从x中的哪些行进行采样以获得与newpoint最近的点。x_将包含这些实际数据点

为了便于复制和粘贴,代码如下所示:

dists = sqrt(sum(bsxfun(@minus, x, newpoint).^2, 2));
%// Or do this for Manhattan
% dists = sum(abs(bsxfun(@minus, x, newpoint)), 2);
[d,ind] = sort(dists);
ind_closest = ind(1:k);
x_closest = x(ind_closest,:);
通过您的示例,让我们看看我们的代码:< /p> 通过检查ind_Nestest和x_Nestest,我们得到:

>> ind_closest

ind_closest =

   120
    53
    73
   134
    84
    77
    78
    51
    64
    87

>> x_closest

x_closest =

    5.0000    1.5000
    4.9000    1.5000
    4.9000    1.5000
    5.1000    1.5000
    5.1000    1.6000
    4.8000    1.4000
    5.0000    1.7000
    4.7000    1.4000
    4.7000    1.4000
    4.7000    1.5000
如果运行knnsearch,您将看到变量n与ind_最接近匹配。但是,变量d返回从newpoint到每个点x的距离,而不是实际数据点本身。如果需要实际距离,只需在我编写的代码之后执行以下操作:

dist_sorted = d(1:k);
请注意,上面的答案在一批N个示例中只使用了一个查询点。KNN经常同时用于多个示例。假设我们有要在KNN中测试的Q个查询点。这将产生一个k x M x Q矩阵,其中对于每个示例或每个切片,我们返回维度为M的k个最近点。或者,我们可以返回k个最近点的ID,从而得到一个Q x k矩阵。让我们计算两者

一种简单的方法是在循环中应用上述代码,并在每个示例上循环

类似的方法可以在我们分配一个Q x k矩阵并应用基于bsxfun的方法将输出矩阵的每一行设置为数据集中的k个最近点的情况下工作,在这里我们将使用Fisher Iris数据集,就像以前一样。我们还将保持与上一个示例相同的维度,我将使用四个示例,因此Q=4和M=2:

虽然这很好,但我们可以做得更好。有一种方法可以有效地计算两组向量之间的平方欧氏距离。如果你想在曼哈顿做这件事,我就把它作为练习。参考,假设A是一个Q1 x M矩阵,其中每行是一个带有Q1点的维度M点,B是一个带有Q2点的Q2 x M矩阵,其中每行也是一个带有Q2点的维度M点,我们可以有效地计算距离矩阵Di,j其中,第i行和第j列的元素表示A的第i行和B的第j行之间的距离,使用以下矩阵公式:

nA = sum(A.^2, 2); %// Sum of squares for each row of A
nB = sum(B.^2, 2); %// Sum of squares for each row of B
D = bsxfun(@plus, nA, nB.') - 2*A*B.'; %// Compute distance matrix
D = sqrt(D); %// Compute square root to complete calculation
因此,如果我们让A作为查询点矩阵,B作为由原始数据组成的数据集,我们可以通过对每一行进行单独排序并确定每一行中最小的k个位置来确定k个最近的点。我们还可以使用它来检索实际点本身

因此:

%// Load the data and create the query points
load fisheriris;
x = meas(:,3:4);
newpoints = [5 1.45; 7 2; 4 2.5; 2 3.5];

%// Define k and other variables
k = 10;
Q = size(newpoints, 1);
M = size(x, 2);

nA = sum(newpoints.^2, 2); %// Sum of squares for each row of A
nB = sum(x.^2, 2); %// Sum of squares for each row of B
D = bsxfun(@plus, nA, nB.') - 2*newpoints*x.'; %// Compute distance matrix
D = sqrt(D); %// Compute square root to complete calculation 

%// Sort the distances 
[d, ind] = sort(D, 2);

%// Get the indices of the closest distances
ind_closest = ind(:, 1:k);

%// Also get the nearest points
x_closest = permute(reshape(x(ind_closest(:), :).', M, k, []), [2 1 3]);
我们看到,我们使用的计算距离矩阵的逻辑是相同的,但一些变量已经改变,以适应这个例子。我们还使用sort的两个输入版本对每行进行独立排序,因此ind将包含每行的id,d将包含相应的距离。然后,我们通过简单地将该矩阵截断为k列来确定哪些索引最接近每个查询点。然后,我们使用和来确定关联的最近点是什么。我们首先使用所有最接近的索引,创建一个点矩阵,将所有ID堆叠在一起,得到一个Q*kxm矩阵。使用“重塑”和“置换”可以创建3D矩阵,使其成为我们指定的k x M x Q矩阵。如果你想得到实际的距离,我们可以索引到d并获取我们需要的。要做到这一点,您需要使用来获得线性索引,以便我们可以一次索引到d。ind_的值已经为我们提供了需要访问的列。我们需要访问的行仅为1,k次,2,k次,等等。到Q为止。k表示我们想要返回的点数:

row_indices = repmat((1:Q).', 1, k);
linear_ind = sub2ind(size(d), row_indices, ind_closest);
dist_sorted = D(linear_ind);
当我们为上述查询点运行上述代码时,我们得到的是索引、点和距离:

>> ind_closest

ind_closest =

   120   134    53    73    84    77    78    51    64    87
   123   119   118   106   132   108   131   136   126   110
   107    62    86   122    71   127   139   115    60    52
    99    65    58    94    60    61    80    44    54    72

>> x_closest

x_closest(:,:,1) =

    5.0000    1.5000
    6.7000    2.0000
    4.5000    1.7000
    3.0000    1.1000
    5.1000    1.5000
    6.9000    2.3000
    4.2000    1.5000
    3.6000    1.3000
    4.9000    1.5000
    6.7000    2.2000


x_closest(:,:,2) =

    4.5000    1.6000
    3.3000    1.0000
    4.9000    1.5000
    6.6000    2.1000
    4.9000    2.0000
    3.3000    1.0000
    5.1000    1.6000
    6.4000    2.0000
    4.8000    1.8000
    3.9000    1.4000


x_closest(:,:,3) =

    4.8000    1.4000
    6.3000    1.8000
    4.8000    1.8000
    3.5000    1.0000
    5.0000    1.7000
    6.1000    1.9000
    4.8000    1.8000
    3.5000    1.0000
    4.7000    1.4000
    6.1000    2.3000


x_closest(:,:,4) =

    5.1000    2.4000
    1.6000    0.6000
    4.7000    1.4000
    6.0000    1.8000
    3.9000    1.4000
    4.0000    1.3000
    4.7000    1.5000
    6.1000    2.5000
    4.5000    1.5000
    4.0000    1.3000

>> dist_sorted

dist_sorted =

    0.0500    0.1118    0.1118    0.1118    0.1803    0.2062    0.2500    0.3041    0.3041    0.3041
    0.3000    0.3162    0.3606    0.4123    0.6000    0.7280    0.9055    0.9487    1.0198    1.0296
    0.9434    1.0198    1.0296    1.0296    1.0630    1.0630    1.0630    1.1045    1.1045    1.1180
    2.6000    2.7203    2.8178    2.8178    2.8320    2.9155    2.9155    2.9275    2.9732    2.9732
要将其与knnsearch进行比较,您可以为第二个参数指定一个点矩阵,其中每一行都是一个查询点,您将看到此实现与knnsearch之间的索引和排序距离匹配


希望这对你有帮助。祝你好运

这很简单。对于特定点,我们找到数据与该点之间的10个最近点,并返回这些最近点,它们是数据的一部分。通常,当一个点的分量用于比较另一个点的分量时,使用欧几里德距离。维基百科上的这篇文章特别有用:哦。。。是否要自己执行此过程?我当然可以给你一个答案。其实实现算法并不像你想象的那么难。请说明您需要什么。是的,我正在尝试自己实现“knnsearch”功能,就像我的代码示例一样,谢谢!没问题。过一会儿我会给你写一个答案。我在一个没有MATLAB来测试代码的地方。当我写的时候,我会写一个答案。然而,为了让您开始,基本步骤是找到测试点与数据矩阵中所有其他点之间的欧几里德距离。将距离从最小到最大排序,然后选择产生最小距离的k点。很快会有答复的!你好,rayryeng,我只是想澄清一下;我的测试点
在这种情况下,t是newpoint=[51.45];正当因此,我现在将计算数据中其他点的EU距离;x=meas:,3:4;Fisherris数据是一个matlab示例数据,请加载它并查看是否发生意外。谢谢这确实很有帮助!非常感谢你!现在我明白了@rayryeng@Young_DataAnalyst-我的荣幸!如果我帮助过你,请考虑接受我的回答。祝你好运@卡姆塔尔-酷:!我很高兴@如果x和newpoints都在同一对称平面上对称,knnsearch可能会返回该平面上的不对称索引。“有办法实现对称吗?”JuneWang我不理解你的询问。你能给我举个例子吗?