【问题标题】:matlab return every second occurrence of value in vectormatlab返回向量中每第二次出现的值
【发布时间】:2015-09-15 17:06:36
【问题描述】:

我有一个 ID 号重复偶数次的向量。我只对每个数字出现的第二次感兴趣。我想创建一个布尔掩码,为每第二次出现一个数字给出一个 true/1。我已经用循环完成了这个,但是实际的向量将包含数百万个元素,所以循环太慢了。我需要一个“矢量化”的解决方案。

这是一个示例向量:

101
102
103
101
104
102
101
103
101
104

这应该输出以下掩码:

0 (first occurrence of 101)
0 (first occurrence of 102)
0 (first occurrence of 103)
1 (second occurrence of 101)
0 (first occurrence of 104)
1 (second occurrence of 102)
0 (third occurrence of 101) 
1 (second occurrence of 103)
1 (fourth occurrence of 101)
1 (second occurrence of 104)

【问题讨论】:

    标签: matlab vector boolean vectorization


    【解决方案1】:

    您可以通过结合使用uniqueaccumarray 轻松完成此操作。首先为每个值分配一个唯一的 ID,然后将属于同一 ID 的所有数组位置合并在一起。您需要对它们进行排序,因为accumarray 不能保证在您将物品组合在一起时的顺序。其输出将是一个单元格数组,其中每个单元格为您提供特定索引出现的数组位置。

    完成此操作后,从accumarray 生成的每个单元格中提取每隔一个元素,然后使用这些将掩码中的所有相应位置设置为 1。您可以使用 cellfun 的组合,它可以用于单独处理每个单元格并提取每隔一个元素以创建一个新的单元格数组,vertcat 可用于将所有单元格数组堆叠在一起成为一个最终索引数组。该索引数组可用于将掩码中的位置设置为true

    %// Your data
    V = [101,102,103,101,104,102,101,103,101,104];
    
    %// Get list of unique IDs
    [~,~,id] = unique(V,'stable');
    
    %// Bin all of the locations in V together that belong to the
    %// same bin
    out = accumarray(id, (1:numel(V)).',[], @(x) {sort(x)}); %'
    
    %// Extract out every second value that is for each bin
    out2 = cellfun(@(x) x(2:2:end), out, 'uni', 0);
    
    %// Create a mask and set the corresponding locations to true
    mask = false(numel(V), 1);
    mask(vertcat(out2{:})) = 1;
    

    我们得到:

    >> mask
    
    mask =
    
         0
         0
         0
         1
         0
         1
         0
         1
         1
         1
    

    【讨论】:

    • 当我意识到 unique 部分只是改变了我的变量数并且我仍然需要一个循环时,我就被困在了这部分。使用我最好的朋友accumarray 做得很好
    • 这是我的示例向量。然而,在我的真实向量上,mask(cell2mat(out2)) = 1; 我得到:Error using cat Dimensions of matrices being concatenated are not consistent. Error in cell2mat (line 83) m{n} = cat(1,c{:,n}); 这可能是什么原因造成的?是不是有些值出现奇数次?
    • @Trashman - 没关系。让我修改它,使它不使用cell2mat...这可能是错误的来源。
    • @Trashman - 我已将 cell2mat 替换为 vertcat。我还确保每个 bin 的所有索引都是列向量。希望这对你有用。
    • 是的,vertcat 有效!仅供参考:我确实更深入地追踪了 cell2mat 问题。我在 out2 中的一些元素是空的。如果我选择了在第一个空单元格之前停止的范围,它不会给出错误,如果我包含空单元格它会给出错误。我怀疑空可能是由于特定 ID 在原始值中仅出现一次。不过,自从 vertcat 工作以来,我不会进一步追踪它。谢谢!
    【解决方案2】:

    让我们 bsxfun 它来获取矢量化解决方案 -

    %// Assuming A as the input vector
    M = bsxfun(@eq,A(:),unique(A(:).'))  %//'
    out = any(M - mod(cumsum(M,1).*M,2),2)
    

    【讨论】:

    • @rayryeng M 是所有独特事件的掩码。 mod(cumsum(M,1).*M,2) 是所有奇数事件的出现,所以从M 中减去它会得到偶数出现,最后是any,因为最终输出是一个向量。希望这是有道理的! golfing 的情况如何 ;)
    • 优秀的,最“优雅”和完全矢量化的解决方案。我将不得不更改我接受的答案。你和rayryeng都有40k+的评分,所以我认为这不会对你产生太大影响。感谢 rayryeng、excaza 和 Divakar 的帮助。所有的答案都很棒。我不认为我会有三个解决方案可供选择,尤其是没有这么快!
    • @Trashman - 我也会选择这个答案。 Divakar 有一种矢量化方法。祝你好运!
    【解决方案3】:

    这是一种方法:

    A = [101,102,103,101,104,102,101,103,101,104];
    IDs = unique(A); % Find all the IDs present
    
    test = arrayfun(@(x) find(A==x), IDs, 'UniformOutput', false); % Per ID, find where A == ID
    repeatidx = cellfun(@(x) x(2:2:length(x)), test, 'UniformOutput', false); % Dump out the second match
    repeatidx = cell2mat(repeatidx); % Flatten the cell array
    
    B = false(size(A)); % Intialize output boolean array
    B(repeatidx) = true; % Set true values based on repeatidx
    

    返回:

    B =
    
         0     0     0     1     0     1     0     1     1     1
    

    【讨论】:

    • 与 rayryeng 的原始回复类似,“cell2mat”在我的真实数据中出现错误。我认为当一个元素实际上没有重复时它会失败。 “垂直猫”效果更好。确切语法:repeatidx = vertcat(repeateidx{:})。用那个替换,你的方法也有效!谢谢。
    • 我希望我也能接受你的回答。不幸的是,我只能接受一个。 Rayryeng 是第一个得到它,但你的答案同样好(有一个修改)。我确实给了你一个赞成票。再次感谢。
    • @Trashman vertcat 使用此方法的问题在于,如果该值有多次重复,它将不起作用(例如,您的示例中的 101,我们的掩码是两次 true)因为嵌套数组的大小会不同。
    • 也投给我一票。原来你先发布了几秒钟。接受你的接受感觉很糟糕!
    • @excaza 当我尝试此方法时,将 cell2mat 替换为 vertcat,在我的实际数据上使用它,并将其与我从 rayryeng 的方法得到的结果进行比较,检查的掩码彼此完全相同。所以,要么你的使用 vertcat 没有这个问题,要么他们都有......我不认为他们有,但我会仔细检查我的数据。
    猜你喜欢
    • 1970-01-01
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-04-06
    • 2019-12-20
    • 1970-01-01
    相关资源
    最近更新 更多