【问题标题】:Minimal values of cell arrays in MATLABMATLAB中元胞数组的最小值
【发布时间】:2016-04-13 07:14:13
【问题描述】:

我在 MATLAB 中有一个元胞数组,其中包含一些按大小降序排列的矩阵(例如 [512x512 double] [256x256 double] [128x128 double] 等)。

现在我想找到并擦除(变成零)元胞数组总共中矩阵中的 100 个最小元素(而不是单独在每个矩阵中)。例如,最小的元素可能在 128x128 矩阵中,下一个在 512x512 矩阵中,依此类推。

我怎样才能最有效地做到这一点?

下一个是我的超慢代码,用于三个这样的单元格数组 - H、D、V(percent2zero 是从整个单元格数组中擦除的元素百分比的参数):

details=[H;D;V];
for k=1:3
    numOfLevels=length(details(k,:));
    TotalCoeffs=0;
    minimalInEachLevel=zeros(1,numOfLevels);
    for i=1:numOfLevels
        temp=cell2mat(details(k,i));
        TotalCoeffs=TotalCoeffs+numel(temp);
        minimalInEachLevel(i) = min(min(abs(temp)));
    end
    CoeffsToBeRemoved=percent2zero*TotalCoeffs/100;
    for i=1:CoeffsToBeRemoved
        for j=1:numOfLevels
            temp=cell2mat(details(k,j));
            minimalInEachLevel(j) = min(min(abs(temp)));
        end
        [val,ind]=min(minimalInEachLevel);
        temp=cell2mat(details(k,ind));
        temp(find(abs(temp==val),1))=0;
        details(k,ind)=mat2cell(temp,size(temp,1),size(temp,2));        
    end
end

【问题讨论】:

  • 看看cellfun
  • 嗨...怎么了?我们帮你了吗?
  • 如果其中一个答案解决了您的问题,请通过单击复选标记考虑accepting it。这表明您已经找到了解决方案,这不再是一个悬而未决的问题。如果您的问题没有得到解答,请说明缺少的内容。

标签: matlab


【解决方案1】:

我可以建议的一件事是将所有矩阵中的每个值放入单个 1D 向量中,对向量进行排序并选择 100 个最小值。使用cellfunsort 执行此第一步。这背后的逻辑是,如果我们收集所有矩阵的所有值并将它们放入单个向量中,然后对整个向量进行排序,我们将选择 100 个最小值all together,正如您提到的那样。

找到这 100 个最小值后,您必须遍历每个单元格,然后您可以使用 intersect 查看单元格数组中的每个矩阵中是否有任何与这 100 个最小值相同的元素。您可以使用 intersect 的第二个输出,然后使用它来索引每个单元格并将值设置为 0。因为您正在处理单元格并且每个单元格的大小不同,所以循环是唯一的选择。

想到这样的事情。这是假设details 是一个元胞数组,其中每个元胞都是一个矩阵:

%// Create single 1D vector of all values
vals = cellfun(@(x) reshape(x, [], 1), details, 'uni', 0);
vals = cat(1, vals{:});

%// Sort the UNIQUE values and grab the 100 smallest values
vals = unique(vals);
vals = vals(1:100);

%// Loop through each cell, determine those values that are among
%// the 100 smallest and set to 0
for ii = 1 : numel(details)
    [~,ind,~] = intersect(details{ii}, vals);
    details{ii}(ind) = 0;
end

unique 可以在数组或矩阵中找到唯一值,但也可以对唯一值进行排序。因此,此代码将找到 100 个最小且 唯一 值来处理您的元胞数组。

【讨论】:

    【解决方案2】:

    我一直在摆弄这个,基本上想出了与 rayryeng 相同的东西。想法是将每个矩阵重塑为一维向量,对每个向量进行排序并跟踪原始索引,然后开始将一维向量开头的最小元素归零,使用未排序的一维向量的索引返回到二维矩阵并将这些元素归零。我认为它有点将一维向量视为队列。无论如何,我设计了一个函数,该函数将遵循这个过程,用于包含 3 个矩阵的元胞数组。对于具有任意数量矩阵的元胞数组来说,它并不漂亮、优化或泛化,但我认为改进起来并不那么困难。

    function [X] = wipeCellMinima(X,percent2zero)
    %wipeCellMinima
    
    x1 = X{1};
    x2 = X{2};
    x3 = X{3};
    
    l1 = length(x1);
    l2 = length(x2);
    l3 = length(x3);
    
    %reshape each matrix into a 1D vector and sort them, keeping sorted indices
    [q1,I1] = sort(reshape(x1,1,l1^2));
    [q2,I2] = sort(reshape(x2,1,l2^2));
    [q3,I3] = sort(reshape(x3,1,l3^2));
    
    %total number of elements to be "wiped"
    n = fix((l1^2 + l2^2 + l3^2)*percent2zero*0.01); 
    
    i1 = 1;
    i2 = 1;
    i3 = 1;
    
    %treat the reshaped and sorted matrices kind of like queues
    for j = 1:n
        %Find the smallest value indexed in sort1 by i1, in sort2 by i2,
        %and in sort3 by i3.
        [~,idx_min] = min([q1(i1),q2(i2),q3(i3)]);
        if(idx_min == 1)
            %The smallest element in all matrices is the first one in the
            %sorted version of x1. Use it's index in the unsorted version of q1
            %to set the corresponding element in x1 to zero. And increment i1.
    
            %In the unsorted version of q1, the I1(i1)th element needs to be
            %set to zero. The correct row and column can be extracted from the
            %size of the original matrix x1 and the position of the element in
            %the 1D vector.
            row = mod(I1(i1),l1);
            if(row == 0)
                row = l1;
                col = I1(i1)/l1;
            else
                col = floor(I1(i1)/l1) + 1;
            end
            x1(row,col) = 0;
            i1 = i1 + 1;
        elseif(idx_min == 2)
            row = mod(I2(i2),l2);
            if(row == 0)
                row = l2;
                col = I2(i2)/l2;
            else
                col = floor(I2(i2)/l2) + 1;
            end
            x2(row,col) = 0;
            i2 = i2 + 1;
        else
            row = mod(I3(i3),l3);
            if(row == 0)
                row = l3;
                col = I3(i3)/l3;
            else
                col = floor(I3(i3)/l3) + 1;
            end
            x3(row,col) = 0;
            i3 = i3 + 1;
        end
    end
    
    X = {x1,x2,x3};
    
    end
    

    【讨论】:

    • 这段代码能否处理用于删除元胞数组中值的系数数组有重复的情况?
    • 我想这取决于您所说的“句柄”是什么意思。它将每次将固定数量的元素设置为零,具体取决于所有矩阵中的元素总数和percent2zero,但它不会根据单元格数组中矩阵的顺序或任何其他内容优先将元素归零像这样。
    【解决方案3】:
    n = sum(cellfun('prodofsize',details),2);
    CoeffsToBeRemoved = round(percent2zero/100*n);
    for i = 1:size(details,1)
        tmp = cellfun(@(x)x(:),details(i,:),'un',0);
        tmp = sort(abs(vertcat(tmp{:})));
        val = tmp(CoeffsToBeRemoved(i));
        for j = 1:size(details,2)
            details{i,j} = details{i,j}.*(abs(details{i,j})>val);
        end
    end
    

    【讨论】:

    • 欢迎来到 SO。您能否提供一些信息,这如何解决 OP 的问题?你到底做了什么改变,为什么它有帮助?纯代码块可能难以处理。 ;)
    • 此代码能否处理用于删除元胞数组中值的系数数组有重复项的情况?还有一些关于这段代码如何工作的解释会很好。
    猜你喜欢
    • 1970-01-01
    • 2016-08-01
    • 2017-05-29
    • 2013-08-09
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多