【问题标题】:How to count patterns columnwise in Matlab?如何在 Matlab 中按列计算模式?
【发布时间】:2015-02-11 00:24:44
【问题描述】:

我在 Matlab 中有一个矩阵 S,如下所示:

2   2   1   2
2   3   1   1
3   3   1   1
3   4   1   1
3   1   2   1
4   1   3   1
1   1   3   1

我想按列计算值的模式。我对在任何列中紧跟数字 3 之后的数字的频率很感兴趣。例如,数字 3 在第一列中出现了 3 次。我们第一次观察到它后面是 3,第二次后面是 3,第三次后面是 4。因此,在第一列中观察到的模式的频率如下所示:

3-3: 66.66%
3-4: 33.33% 
3-1: 0%
3-2: 0%

【问题讨论】:

  • 我不明白你的问题陈述。您能告诉我们您是如何计算这些值的吗?
  • 上面提供的百分比是假设的,并且对应于在特定矩阵 S 中可以找到的确切百分比。我们的想法是找出 1/2 的次数/3/4 跟随矩阵列中的数字 3。
  • 好吧,我还是不明白。你需要为我分解它。想象一下,我是一个 5 岁的孩子。我们来看第一列。您想计算 1、2、3 或 4 的值跟随数字 3 的次数吗?正如我所说,一个示例计算将有助于理解您的观点。另外,这些百分比是什么意思?
  • 感谢您的提问。在第一列中,数字 3 出现了 3 次。我们第一次观察到它之后是 3,第二次之后是 3,第三次是 4。因此,在第一列中观察到的模式的频率看起来像 3-3 : 66.66% 和 3-4: 33.33% 而没有观察到 3-1:0% 和 3-2:0% 的组合。
  • 致 SO 社区:如果您检查了本主题开头的无数问题,我似乎相当困惑和充满敌意。这是因为原始问题缺乏足够的信息来解决最终包含在问题的最终编辑版本中的问题。没有任何冒犯的意图。

标签: matlab matrix frequency


【解决方案1】:

要生成输出,您可以使用方便的tabulate

S = [
    2   2   1   2
    2   3   1   1
    3   3   1   1
    3   4   1   1
    3   1   2   1
    4   1   3   1
    1   1   3   1];

idx = find(S(1:end-1,:)==3);
S2 = S(2:end,:);

tabulate(S2(idx))
  Value    Count   Percent
      1        0      0.00%
      2        0      0.00%
      3        4     66.67%
      4        2     33.33%

【讨论】:

  • 我发现这个解决方案非常干净和高效。谢谢分享。
【解决方案2】:

这是一种方法,找到 3,然后查看以下数字

[i,j]=find(S==3);
k=i+1<=size(S,1);
T=S(sub2ind(size(S),i(k)+1,j(k))) %// the elements of S that are just below a 3
R=arrayfun(@(x) sum(T==x)./sum(k),1:max(S(:))).' %// get the number of probability of each digit

【讨论】:

  • 我也加了 1。这是我最初的方法,但我决定使用accumarray,因为我发现它更简单。
【解决方案3】:

我将以我可以理解的方式重述您的问题陈述,我的解决方案将反映这个新的问题陈述。

  1. 对于特定列,找到包含数字 3 的位置。
  2. 查看这些位置正下方的行并查看这些位置的值
  3. 获取这些值并计算找到的总次数。
  4. 对所有列重复这些操作并更新计数,然后确定这些值的出现百分比。

我们可以通过以下方式做到这一点:

A = [2   2   1   2
2   3   1   1
3   3   1   1
3   4   1   1
3   1   2   1
4   1   3   1
1   1   3   1]; %// Define your matrix
[row,col] = find(A(1:end-1,:) == 3);
vals = A(sub2ind(size(A), row+1, col));
h = 100*accumarray(vals, 1) / numel(vals)

h =

          0
          0
    66.6667
    33.3333

让我们慢慢看一下上面的代码。前几行定义了您的示例矩阵A。接下来,我们查看矩阵的所有行除了最后一行,并使用find 查看数字 3 的位置。我们跳过最后一行,因为我们想确保我们在矩阵的范围内。如果最后一行有一个数字 3,如果我们尝试检查最后一行下面的值,我们将有未定义的行为,因为那里什么都没有!

完成此操作后,我们会查看矩阵中位于编号为 3 的值下方 1 行的值。我们使用sub2ind 来帮助我们实现这一点。接下来,我们使用这些值并使用accumarray 对它们进行统计,然后通过统计的总和将它们归一化为百分比。

结果将是一个 4 元素数组,显示每个数字遇到的百分比。

再次检查,如果我们查看矩阵,我们会看到 3 的值跟随其他值 3 总共 4 次 - 第一列、第 3 行、第 4 行、第二列、第 2 行和第三列,第 6 行。4 的值跟随 3 的值两次:第一列,第 6 行,第二列,第 3 行。

我们总共计算了 6 个数字,因此除以 6 得到 3 的 4/6 或 66.67% 和 4 的 2/6 或 33.33%。

【讨论】:

  • 很好地使用了accumarray,你也干净利落地解决了最后一行的问题。
【解决方案4】:

如果我的问题陈述正确,您可以使用MATLAB's logical indexing 和基本上由两行组成的方法有效地实现这一点 -

%// Input 2D matrix
S = [
    2   2   1   2
    2   3   1   1
    3   3   1   1
    3   4   1   1
    3   1   2   1
    4   1   3   1
    1   1   3   1]

Labels = [1:4]'; %//'# Label array

counts = histc(S([false(1,size(S,2)) ; S(1:end-1,:) == 3]),Labels)
Percentages = 100*counts./sum(counts)

验证/呈现结果

接下来列出的用于呈现输出结果的样式使用MATLAB's table 来表示人类可读格式的数据。

样式#1

>> table(Labels,Percentages)
ans = 
    Labels    Percentages
    ______    ___________
    1              0     
    2              0     
    3         66.667     
    4         33.333     

样式#2

你可以做一些花哨的字符串操作,以更“有代表性”的方式呈现结果 -

>> Labels_3 = strcat('3-',cellstr(num2str(Labels','%1d')'));
>> table(Labels_3,Percentages)
ans = 
    Labels_3    Percentages
    ________    ___________
    '3-1'            0     
    '3-2'            0     
    '3-3'       66.667     
    '3-4'       33.333    

样式#3

如果您想根据问题的预期输出部分中列出的百分比以降序排列的方式显示它们,您可以使用sort 进行额外的步骤 -

>> [Percentages,idx] = sort(Percentages,'descend');
>> Labels_3 = strcat('3-',cellstr(num2str(Labels(idx)','%1d')'));
>> table(Labels_3,Percentages)
ans = 
    Labels_3    Percentages
    ________    ___________
    '3-3'       66.667     
    '3-4'       33.333     
    '3-1'            0     
    '3-2'            0   

Bonus Stuff:查找所有案例的频率(计数)

现在,假设您想对 124 重复此过程,即分别在 124 之后找到匹配项。在这种情况下,您可以针对所有情况重复上述步骤,同样您可以使用arrayfun -

%// Get counts
C = cell2mat(arrayfun(@(n) histc(S([false(1,size(S,2)) ; S(1:end-1,:) == n]),...
    1:4),1:4,'Uni',0))

%// Get percentages
Percentages = 100*bsxfun(@rdivide, C, sum(C,1))

给我们 -

Percentages =
   90.9091   20.0000         0  100.0000
    9.0909   20.0000         0         0
         0   60.0000   66.6667         0
         0         0   33.3333         0

     

因此,在Percentages 中,第一列是在输入矩阵中某处出现1 之后立即出现的[1,2,3,4] 的计数。例如,当您在输入矩阵中查找紧跟在3 之后的元素时,可以看到Percentages 中的column -3 是示例输出中的内容。

【讨论】:

  • 不错的解决方案。我认为表格功能仅适用于 Matlab 2014!谢谢分享。
【解决方案5】:

如果您想为每列独立计算频率

S = [2   2   1   2
     2   3   1   1
     3   3   1   1
     3   4   1   1
     3   1   2   1
     4   1   3   1
     1   1   3   1];                                    %// data: matrix
N = 3;                                                  %// data: number
r = max(S(:));
[R, C] = size(S);
[ii, jj] = find(S(1:end-1,:)==N);                       %// step 1
count = full(sparse(S(ii+1+(jj-1)*R), jj, 1, r, C));    %// step 2
result = bsxfun(@rdivide, count, sum(S(1:end-1,:)==N)); %// step 3

它的工作原理如下:

  1. find 首先用于确定NS 中出现的行和列索引,但最后一行除外。
  2. 条目正下方中的值是步骤 1 的索引在变量count 中为每一列累加的。非常方便的sparse 函数用于此目的。请注意,这会将linear indexing 用于S
  3. 要获得每列的频率,count 将除以N 在每列中的出现次数(与bsxfun)。

这个例子的结果是

result =
         0         0         0       NaN
         0         0         0       NaN
    0.6667    0.5000    1.0000       NaN
    0.3333    0.5000         0       NaN

请注意,最后一列正确包含NaNs,因为该列未定义所寻找模式的频率。

【讨论】:

    猜你喜欢
    • 2017-03-06
    • 1970-01-01
    • 2017-11-09
    • 2020-10-03
    • 2021-07-03
    • 2012-05-25
    • 2016-09-02
    • 2021-05-03
    • 1970-01-01
    相关资源
    最近更新 更多