实现自定义距离功能

时间:2016-06-09 18:07:53

标签: matlab matrix distance

AB是由二元元素组成的矩阵。 A表示为基础数据矩阵,B是查询矩阵。 A由75个数据点组成,每个数据点的长度为10,B由50个数据点组成,每个数据点的长度为10.我想计算A中所有数据点与每个查询数据之间的距离指向B以应用最近邻搜索。因此,我没有使用欧几里德或汉明距离,而是使用了另一个指标:

metric

N = 2k = length of data sampless = A(1,:)t = B(1,:)。 该代码适用于A中的一个数据样本和B中的另一个数据样本。如何缩放以使其适用于所有基础数​​据点和所有查询数据点?

代码工作的示例

A(1,:) = [1,0,1,1,0,0,0,1,1,0]是A矩阵中的第一个样本。让B(1,:) = [1,1,0,0,1,1,1,1,0,0]成为第一个查询点。

如果取自A和B的样本中的元素相同,则为每个相似元素记录0,否则为1.最终距离是1的总和。因此,程序检查两个序列是否相同,将b设置为1  所以,否则为零。有人可以告诉我如何将其应用于矩阵吗?

代码

l = length(A);

D=zeros(1,l);
for i=1:l,
    if A(1,i)==B(1,i),
        D(1,i)=0;
    else 
        D(1,i)=1;
    end
end

sum=0;
for j=1:l,
    sum=sum+D(1,j);
end

if sum==0, 
    b = 1;
else 
    b = 0;
end

4 个答案:

答案 0 :(得分:5)

一线解决方案

此计算可以在一行代码中完成:

D = A*B'+(1-A)*(1-B)' < size(A,2)

<强>解释

对于A和B是二进制的这一事实,A处的每个样本与B处的每个样本之间的距离函数基本上检查每坐标匹配的量是否等于样本的长度。 您可以使用矩阵乘法来实现此目的。

更具描述性的代码示例

将A和B定义为您在答案中提到的两个二进制矩阵:

%initializes A and B randomly
A = double(rand(75,10) > 0.5);
B = double(rand(50,10) > 0.5);
[m,n] = size(A);

A中每个样品与B中每个样品之​​间的距离可以如下计算:

首先,定义一个大小为75x50的矩阵D,s.t D(i,j)包含A中样本i和B中样本j之间的匹配数。

可以按如下方式计算:

D = A*B' + (1-A)*(1-B)';

如果匹配量小于n(n是每个样本的长度),则可以通过测试每对(i,j)来完成最终距离测量。如果它较小,则样本不同,结果应为1.否则它应为零。这可以按如下方式完成:

finalDist = D < n ;

答案 1 :(得分:2)

您的距离指标实际上只是L1范数,即sum(abs(x-y))所以在Octave 中您可以使用pdist2,如下所示:

pdist2(A,B,'L1')

在MATLAB中,您可以使用城市街区距离:

pdist2(A,B,'cityblock')

注意,要定义自己的距离指标(但'cityblock'更好):

pdist2(A,B,@(x,y)sum(abs(bsxfun(@minus,x,y)),2))

或者

pdist2(A,B,@(x,y)sum(bsxfun(@xor,x,y),2))

或者

pdist2(A,B,@(x,y)sum(bsxfun(@ne,x,y),2))

你的一个矢量与另一个矢量的距离可以这样找到:

distance = @(x,y)sum(x~=y)

但是,您想要将A的所有行与B的所有行进行比较。 bsxfun在这里很有用,我们只需要使用permute使其中一个矩阵进入第三维:

D = squeeze(sum(bsxfun(@ne, permute(B, [3,2,1]),A),2))'

例如,如果

A = [1,1,0;
     0,0,1;
     1,1,1];

B = [1,1,1;
     0,0,0;
     1,1,1;
     0,1,0]

然后

> D = squeeze(sum(bsxfun(@ne, permute(B, [3,2,1]),A),2))'

D =

   1   2   0
   2   1   3
   1   2   0
   1   2   2

因此,列现在是A的行,而他的行是B的行,因此D(2,3)表示比较B(2,:)[0,0,0]A(3,:) [1,1,1] 3,因为所有元素都不同,所以它们之间的距离为distance

如果您拥有统计工具箱,那么您可以使用上面的pdist2功能代替ImageButton

答案 2 :(得分:2)

如果您希望让代码按循环工作,只需分配size(A,1) x size(B,1)大的空间,以便每个空间位置(i,j)为您提供行i之间的“距离”和j

因此,做这样的事情。这假设AM x d矩阵,而BN x d矩阵,其中d是要素点的总数,M N是任意正数,表示每个元素的行数。

b = zeros(size(A,1), size(B,1)); % Change
l = size(A,2); % Change - Total number of feature points

for ii = 1 : size(A,1) % Change
    for jj = 1 : size(B,1)
        D=zeros(1,l);
        for i=1:l,
            if A(ii,i)==B(jj,i) % Change
                D(i)=0;
            else 
                D(i)=1;
            end
        end

        sum=0;
        for j=1:l,
            sum=sum+D(j);
        end

        if sum==0, 
            b(ii,jj) = 1; % Change
        end
    end
end

这将迭代所有行组合。但是,请使用此前的任何答案来使其矢量化。我只是想告诉你如何修改你当前的代码,如果这是你最熟悉的。

答案 3 :(得分:0)

这就是我从你的描述中理解的(如果我错了,请纠正我) 设A为矩阵

A =

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

和B是

B =

     0     1     1     1     0     1     0     0     1     0
     0     1     0     1     0     0     1     1     1     1
     1     0     0     1     1     0     0     0     1     1
     0     1     0     1     1     0     0     0     1     0
     1     1     0     0     0     0     0     0     0     1
     1     1     0     1     1     1     1     1     1     0
     1     1     0     0     1     0     0     1     0     1
     0     0     1     1     0     1     1     1     0     1
     0     0     0     1     1     0     0     0     1     0
     0     1     1     0     0     0     1     1     0     1
>> C = A.*B

会给出你们之间的共同点,如果A有更多的行,那么你可以说A(1:size(B,1),:).*B而不是

C =

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

在查找中是否没有匹配点b = 1否则为0

b = ~find(sum(sum(C)))

更新:如果D应该像你说的那样是75x50,那么C应该是

  C = A*(B.')

而不是

C = A.*B

因为我首先想到你的代码中的点比较