Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/visual-studio-2012/2.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
Performance 如何在Matlab中进行有效的k近邻计算_Performance_Algorithm_Matlab_Nearest Neighbor - Fatal编程技术网

Performance 如何在Matlab中进行有效的k近邻计算

Performance 如何在Matlab中进行有效的k近邻计算,performance,algorithm,matlab,nearest-neighbor,Performance,Algorithm,Matlab,Nearest Neighbor,我正在用Matlab中的k-最近邻算法进行数据分析。我的数据由大约11795x88个数据矩阵组成,其中行是观察值,列是变量 我的任务是为n个选定的测试点找到k个最近邻。目前,我正在按照以下逻辑进行操作: 对于所有测试点 LOOP all the data and find the k-closest neighbors (by euclidean distance) 换句话说,我循环所有n个测试点。对于每个测试点,我通过欧氏距离搜索数据(不包括测试点本身)中的k近邻。对于每个测试点,这大

我正在用Matlab中的k-最近邻算法进行数据分析。我的数据由大约11795x88个数据矩阵组成,其中行是观察值,列是变量

我的任务是为n个选定的测试点找到k个最近邻。目前,我正在按照以下逻辑进行操作:

对于所有测试点

   LOOP all the data and find the k-closest neighbors (by euclidean distance)
换句话说,我循环所有n个测试点。对于每个测试点,我通过欧氏距离搜索数据(不包括测试点本身)中的k近邻。对于每个测试点,这大约需要k x 11794次迭代。所以整个过程大约需要n x k x 11794次迭代。如果n=10000,k=7,这将是大约8.256亿次迭代

有没有更有效的方法来计算k近邻?现在大部分计算都会浪费,因为我的算法只是:

计算到所有其他点的欧几里德距离,选取最近的点并将其排除在进一步考虑之外-->计算到所有其他点的欧几里德距离并选取最近的-->等-->等

有没有一个聪明的方法来摆脱这种“浪费计算”

目前,这个过程在我的计算机上大约需要7个小时(3.2 GHz,8 GB RAM,64位Win 7)(

下面是一些明确说明的逻辑(这不是我的全部代码,但这是消耗性能的部分):

对于i=1:size(测试点,1)%Loop所有测试点
neighborcandidates=不包括测试点的所有数据;%使用不包括测试点的其余数据搜索k-最近邻
testpoint=testpoints(i,:);%这是我们找到k近邻的测试点
kneighbors=[];%将k近邻存储在此处。
对于j=1:k%,查找k-最近邻
bdist=Inf;%最近邻居的距离
bind=0;%最近邻居的索引
对于n=1:size(邻居条件,1)%Loop所有候选项
如果pdist([testpoint;neighborcandidates(n,:)])小于bdist%,请检查欧几里德距离
bdist=pdist([testpoint;neighborcandidates(n,:)]);%更新到目前为止的最佳距离
bind=n;%保存到目前为止找到的最佳索引
终止
终止
kneighbors=[kneighbors;neighbors条件(绑定,:)];%保存找到的邻居
neighborcandidates(bind,:)=[];%从进一步考虑中删除邻居
终止
终止

我不熟悉特定的matlab函数,但您可以从公式中删除k

有一种众所周知的选择算法

  • 将数组A(大小为n)和数字k作为输入
  • 给出数组A的排列,使第k个最大/最小元素位于第k位
  • 较小的元素位于左侧,较大的元素位于右侧
  • e、 g

    这是在O(n)步中完成的,不依赖于k


    EDIT1:您也可以预计算所有距离,因为它看起来是您花费大部分计算时间的地方。它大约是一个800米的矩阵,因此在现代机器上不应成为问题。

    我不熟悉特定的matlab函数,但您可以从公式中删除k

    有一种众所周知的选择算法

  • 将数组A(大小为n)和数字k作为输入
  • 给出数组A的排列,使第k个最大/最小元素位于第k位
  • 较小的元素位于左侧,较大的元素位于右侧
  • e、 g

    这是在O(n)步中完成的,不依赖于k


    EDIT1:您还可以预计算所有距离,因为它看起来是您花费大部分计算时间的地方。它大约是一个800米的矩阵,因此在现代机器上不应该成为问题。

    我不确定它是否会加快代码速度,但它删除了内部的两个循环

    for i = 1:size(testpoints, 1) % //Loop all the test points 
        temp = repmat(testpoints(i,:),size(neighborcandidates, 1),1);
        euclead_dist = (sum((temp - neighborcandidates).^2,2).^(0.5));
        [sort_dist ind] = sort(euclead_dist);
        lowest_k_ind = ind(1:k);
        kneighbors = neighborcandidates(lowest_k_ind, :);
        neighborcandidates(lowest_k_ind, :) = [];
    end
    

    我不确定它是否会加快代码的速度,但它删除了内部的两个循环

    for i = 1:size(testpoints, 1) % //Loop all the test points 
        temp = repmat(testpoints(i,:),size(neighborcandidates, 1),1);
        euclead_dist = (sum((temp - neighborcandidates).^2,2).^(0.5));
        [sort_dist ind] = sort(euclead_dist);
        lowest_k_ind = ind(1:k);
        kneighbors = neighborcandidates(lowest_k_ind, :);
        neighborcandidates(lowest_k_ind, :) = [];
    end
    

    使用
    pdist2

    A = rand(20,5);             %// This is your 11795 x 88
    B = A([1, 12, 4, 8], :);    %// This is your n-by-88 subset, i.e. n=4 in this case
    n = size(B,1);
    
    D = pdist2(A,B);
    [~, ind] = sort(D);
    kneighbours = ind(2:2+k, :);
    
    现在您可以使用
    kneighbours
    a
    中的行进行索引。请注意,
    kneighbours
    的列对应于
    B

    但是既然您已经在使用
    pdist
    进入统计工具箱,为什么不使用Matlab的
    knnsearch

    kneighbours_matlab = knnsearch(A,B,'K',k+1);
    

    请注意,
    kneighbours
    kneighbours\u matlab(:,2:end)
    使用
    pdist2

    A = rand(20,5);             %// This is your 11795 x 88
    B = A([1, 12, 4, 8], :);    %// This is your n-by-88 subset, i.e. n=4 in this case
    n = size(B,1);
    
    D = pdist2(A,B);
    [~, ind] = sort(D);
    kneighbours = ind(2:2+k, :);
    
    现在您可以使用
    kneighbours
    a
    中的行进行索引。请注意,
    kneighbours
    的列对应于
    B

    但是既然您已经在使用
    pdist
    进入统计工具箱,为什么不使用Matlab的
    knnsearch

    kneighbours_matlab = knnsearch(A,B,'K',k+1);
    
    请注意,
    kneighbours
    kneighbours\u matlab(:,2:end)

    这不起作用吗

    adjk = adj;
    
    for i=1:k-1 
    adj_k = adj_k*adj; 
    end
    
    kneigh = find(adj_k(n,:)>0)
    
    给定一个节点n和一个索引k?

    这不可行吗

    adjk = adj;
    
    for i=1:k-1 
    adj_k = adj_k*adj; 
    end
    
    kneigh = find(adj_k(n,:)>0)
    

    给定一个节点n和一个索引k?

    在Matlab环境下,这可能是一个更快的代码。您还可以尝试并行函数、数据索引和近似最近邻算法,以提高理论效率

    % a slightly faster way to find k nearest neighbors in matlab
    % find neighbors for data Y from data X
    
    m=size(X,1);
    n=size(Y,1);
    IDXs_out=zeros(n,k);
    
    distM=(repmat(X(:,1),1,n)-repmat(Y(:,1)',m,1)).^2;
    for d=2:size(Y,2)
        distM=distM+(repmat(X(:,d),1,n)-repmat(Y(:,d)',m,1)).^2;
    end
    distM=sqrt(distM);
    for i=1:k
        [~,idx]=min(distM,[],1);
        id=sub2ind(size(distM),idx',(1:n)');
        distM(id)=inf;
        IDXs_out(:,i)=idx';
    end
    

    在Matlab环境下,这可能是一个更快的代码。您也可以尝试并行函数、数据索引和近似最近邻算法,使其在理论上更有效

    % a slightly faster way to find k nearest neighbors in matlab
    % find neighbors for data Y from data X
    
    m=size(X,1);
    n=size(Y,1);
    IDXs_out=zeros(n,k);
    
    distM=(repmat(X(:,1),1,n)-repmat(Y(:,1)',m,1)).^2;
    for d=2:size(Y,2)
        distM=distM+(repmat(X(:,d),1,n)-repmat(Y(:,d)',m,1)).^2;
    end
    distM=sqrt(distM);
    for i=1:k
        [~,idx]=min(distM,[],1);
        id=sub2ind(size(distM),idx',(1:n)');
        distM(id)=inf;
        IDXs_out(:,i)=idx';
    end
    

    添加一个小例子来清楚地说明。这是很多循环-如果你只是在整个矩阵上运行
    pdist2
    作为一个输入,然后将
    n
    观察值的子集作为第二个输入矩阵,会发生什么?你的计算机能处理这个问题吗/你知道需要多长时间吗?因为这样你就可以得到所有e的成对距离你在一行中寻找的元素,找到每个
    n
    观察值的顶部
    k
    ,应该很简单……嗨,丹,我用了
    PDI