矩阵列中数字的巧合计数 - MATLAB

5
我是一名有用的助手,可以为您进行翻译。以下是需要翻译的内容:

我有一个矩阵(A),形式如下(实际上要大得多):

205   204   201
202   208   202

我该如何逐列统计数字的重复出现情况,并将其输出为矩阵?
我希望最终的矩阵可以从min(A)到max(A)(或者能够指定特定范围)沿着上方和侧面运行,并统计每一列中数字的重复出现情况。使用以上示例:
    200 201 202 203 204 205 206 207 208
200  0   0   0   0   0   0   0   0   0
201  0   0   1   0   0   0   0   0   0
202  0   0   0   0   0   1   0   0   0 
203  0   0   0   0   0   0   0   0   0
204  0   0   0   0   0   0   0   0   1
205  0   0   0   0   0   0   0   0   0
206  0   0   0   0   0   0   0   0   0
207  0   0   0   0   0   0   0   0   0
208  0   0   0   0   0   0   0   0   0

(矩阵标签不是必需的)

两个重要点:计数需要非重复,并按数字顺序发生。例如,包含以下内容的列:

205
202

我会将这个作为202和205的组合出现(如上矩阵所示),但不包括205和202的重复互换。在决定使用哪个数字作为参考时,应该选择最小的数字。
编辑:

enter image description here

3个回答

4

sparse来拯救我们!

让您的数据和所需范围被定义为:

A = [ 205   204   201
      202   208   202 ]; %// data. Two-row matrix
limits = [200 208]; %// desired range. It needn't include all values of A

那么

lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all((A>=limits(1)) & (A<=limits(2)), 1);
B = sort(A(:,cols), 1, 'descend')-lim1;
R = full(sparse(B(2,:), B(1,:), 1, s, s));

提供

R =
     0     0     0     0     0     0     0     0     0
     0     0     1     0     0     0     0     0     0
     0     0     0     0     0     1     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     1
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0

或者,您可以放弃使用sort,而是使用矩阵加法,然后使用triu来获得相同的结果(可能更快):

lim1 = limits(1)-1;
s = limits(2)-lim1;
cols = all( (A>=limits(1)) & (A<=limits(2)) , 1);
R = full(sparse(A(2,cols)-lim1, A(1,cols)-lim1, 1, s, s));
R = triu(R + R.');

这两种方法都可以正确处理重复的列(在排序之前),并正确增加它们的计数。例如,

A = [205   204   201
     201   208   205]

提供

R =
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     2     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     1
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0

3
看看这是否符合您的要求 -
range1 = 200:208 %// Set the range

A = A(:,all(A>=min(range1)) & all(A<=max(range1))) %// select A with columns
                                                   %// that fall within range1
A_off = A-range1(1)+1 %// Get the offsetted indices from A

A_off_sort = sort(A_off,1) %// sort offset indices to satisfy "smallest" criteria

out = zeros(numel(range1)); %// storage for output matrix
idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:)) %// get the indices to be set

unqidx = unique(idx)
out(unqidx) = histc(idx,unqidx) %// set coincidences

With

A = [205   204   201
     201   208   205]

这是获取 -

out =
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     2     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     1
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0

这里可以使用一些性能优化技巧-

I. 替换

out = zeros(numel(range1)); 

使用

标签

out(numel(range1),numel(range1)) = 0;

二、替换

idx = sub2ind(size(out),A_off_sort(1,:),A_off_sort(2,:))  

使用

idx = (A_off_sort(2,:)-1)*numel(range1)+A_off_sort(1,:)

我认为提问者希望结果中的数字大于1,如果同一列(排序后)出现多次。 - Luis Mendo
@LuisMendo 感谢你提醒,已经编辑好了!给你点赞! - Divakar
好的修复!+1 现在也是。 - Luis Mendo
@Divakar - 问题有点傻...但是accumarray在这里也有用吗? - rayryeng
@rayryeng,我对此不是专家。我猜你可以试试看,它必须像histc一样添加,我认为它会这样做。在此之前,我想你得先把标签搞对。这些都只是猜测,最好的方法是尝试一下 :) - Divakar
@Divakar - 好的,我还是写了一个回答哈哈。虽然不如你的答案好,但也算是为这个话题做出了一点贡献。 - rayryeng

3

那么使用accumarray解决方案如何?我会首先独立地对每一列进行排序,然后将第一行作为最终累加矩阵的第一维度,将第二行作为最终累加矩阵的第二维度。类似这样:

limits = 200:208;
A = A(:,all(A>=min(limits)) & all(A<=max(limits))); %// Borrowed from Divakar

%// Sort the columns individually and bring down to 1-indexing
B = sort(A, 1) - limits(1) + 1;

%// Create co-occurrence matrix
C = accumarray(B.', 1, [numel(limits) numel(limits)]);

带有:

A = [205   204   201
     202   208   202]

这是输出结果:
C =

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

带有重复项(借用自Luis Mendo):

A = [205   204   201
     201   208   205]

输出:

C =

     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     2     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     1
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0
     0     0     0     0     0     0     0     0     0

看起来运行得很好!实际上做得很好,因为代码相当紧凑。看起来你已经很熟悉accumarray了! - Divakar
@Divakar - 哈哈,谢谢 :) 我是从chappjc那里学的。一旦你掌握了它,它就非常容易使用。 - rayryeng
这看起来是一个非常好的紧凑解决方案。然而,我仍然在处理我的原始矩阵时遇到问题,使用A = A(:,all(A>=min(limits)) & all(A<=max(limits)));尽管在限制范围内存在值,但它只返回一个空矩阵=[]。只有当限制包括0作为最小值时才有效。原始矩阵确实在某些行中包含0,但我不知道为什么它不能以这种方式处理。 - AnnaSchumann
@AnnaSchumann - 你能发一下ARE1s1长什么样子的示例吗?只需要几行即可。 - rayryeng
昨天我看到了你的评论,但没有看到你的答案 - 为accumarray解决方案点赞! - Luis Mendo
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接