【问题标题】:Matlab matrix and vector sorting for indexes索引的Matlab矩阵和向量排序
【发布时间】:2015-03-08 21:12:51
【问题描述】:

我有一个矩阵,其行代表音符。 [A,A#,B,C,C#,D,D#,E,F,F#,G,G#] 所以索引 1 代表 A,2 代表 A#,以此类推。在矩阵中,该索引中最大的元素越有可能出现在音频中。

我想计算这 3 个索引在可能的 12 个索引中出现的频率最高。

这就是我的推理方式。首先,我使用 [B,I] = sort() 对每一列进行排序。 B 现在包含排好序的列 I 现在包含按升序排序的索引。

因此,I[10]、I[11] 和 I[12] 现在包含该列中的 3 个最大索引。

现在我创建一个名为 notes 的新向量。如果一个特定的注释在排序时发现自己位于 I 的最大 3 个索引中,则相应的注释应该递增。

我正在尝试前 3 列,它们是:

0.0690   0.0530   0.0656
0.2453   0.2277   0.2306
0.0647   0.0315   0.0494
1.2037   1.1612   1.1613
0.0772   0.0346   0.0367
0.1628   0.1429   0.1648
0.0572   0.0370   0.0493
0.4119   0.3577   0.3635
0.0392   0.0430   0.0466
0.1182   0.0921   0.0935
0.7473   0.6680   0.7088
0.0794   0.0527   0.0566

因此在 B 中我应该得到的第一个循环迭代,

 0.0392
 0.0572
 0.0674
 0.0690
 0.0772
 0.0794
 0.1182
 0.1628
 0.2453
 0.4119
 0.7473
 1.2037

我得到了(所以到目前为止一切都很好)。 I(包含排序的索引)也被正确返回,3 个最大的索引是 8、11、4(即包含最大元素的原始索引,其中 8、11、4 按升序排列)

问题在于 if 条件。在第一次迭代中,在 if 条件之后,'notes' 列向量应该在第 8 位、第 11 位、第 4 位递增,即。

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

然而,在 if 条件之后,只有向量中的第 4 位被递增。事实上,在第一次迭代之后,当显示“notes”向量时,我得到了

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

这是代码:

for col = 1:3        
    [B,I] = sort(C(:,col), 'ascend'); %B is the sorted column. I is the sorted indexes
    fprintf('Col No:');
    disp(col);
    fprintf('Sorted Column: ');
    disp(B);
    fprintf('Sorted Indexes: ');
    disp(I);

    if (I(10) == 1 || I(11) == 1 || I(12) == 1)
        notes(1,:) = notes(1,:) + 1;
    elseif (I(10) == 2 || I(11) == 2 || I(12) == 2)
        notes(2,:) = notes(2,:) + 1;
    elseif (I(10) == 3 || I(11) == 3 || I(12) == 3)
        notes(3,:) = notes(3,:) + 1;
    elseif (I(10) == 4 || I(11) == 4 || I(12) == 4)
        notes(4,:) = notes(4,:) + 1;
    elseif (I(10) == 5 || I(11) == 5 || I(12) == 5)
        notes(5,:) = notes(5,:) + 1;
    elseif (I(10) == 6 || I(11) == 6 || I(12) == 6)
        notes(6,:) = notes(6,:) + 1;
    elseif (I(10) == 7 || I(11) == 7 || I(12) == 7)
        notes(7,:) = notes(7,:) + 1;
    elseif (I(10) == 8 || I(11) == 8 || I(12) == 8)
        notes(8,:) = notes(8,:) + 1;
    elseif (I(10) == 9 || I(11) == 9 || I(12) == 9)
        notes(9,:) = notes(9,:) + 1;
    elseif (I(10) == 10 || I(11) == 10 || I(12) == 10)
        notes(10,:) = notes(10,:) + 1;
    elseif (I(10) == 11 || I(11) == 11 || I(12) == 11)
        notes(11,:) = notes(11,:) + 1;
    elseif (I(10) == 12 || I(11) == 12 || I(12) == 12)
        notes(12,:) = notes(12,:) + 1;

    end

    disp(notes);

我做错了什么?代码可能是错误的(或者可能会更好)。我并不擅长 Matlab。这是第一次使用它。

非常感谢您的想法、意见和更正。

提前感谢您的宝贵时间

【问题讨论】:

    标签: matlab sorting matrix


    【解决方案1】:

    你似乎想多了这个问题。您可以做的是使用sort 并单独将排序应用于每一列。 sort 函数使用第二个参数告诉您要应用排序的维度。由于要对列进行排序,因此需要将第二个参数设置为 1,这意味着您要对每一列的行进行排序。

    因此,定义你的“笔记”矩阵C

    C = [0.0690   0.0530   0.0656
    0.2453   0.2277   0.2306
    0.0647   0.0315   0.0494
    1.2037   1.1612   1.1613
    0.0772   0.0346   0.0367
    0.1628   0.1429   0.1648
    0.0572   0.0370   0.0493
    0.4119   0.3577   0.3635
    0.0392   0.0430   0.0466
    0.1182   0.0921   0.0935
    0.7473   0.6680   0.7088
    0.0794   0.0527   0.0566];
    

    你可以这样做:

    [~,I] = sort(C, 1, 'descend')
    

    'descend' 标志按 降序 顺序对值进行排序。因此,I 将是一个矩阵,其中每一列都告诉您每个排序值的位置将出现在每列中的位置。因此,您只需获取I 的前三行。

    因此,如果我们显示I 的前三行,我们会得到:

    >> disp(I(1:3,:))
    
     4     4     4
    11    11    11
     8     8     8
    

    这是有道理的,对于每一列,我们分别在位置 4、11 和 8 找到最高值。

    现在,如果您想计算在上述矩阵中看到的位置,您可以非常简单地使用histcaccumarray

    因此:

    ind = I(1:3,:); %// Get the first three rows of the sorted indices
    notes = histc(ind(:), 1:12); %// or
    %notes = accumarray(ind(:), 1, [12 1]);
    

    因此,对于notes,我们得到:

    notes =
    
         0
         0
         0
         3
         0
         0
         0
         3
         0
         0
         3
         0
    

    因此,我们看到每列的索引为 4、8 和 11,因此我们应该每次将这些位置增加 1。 histc 会计算事物发生的频率,因此我们可以自然地使用它来计算我们看到 4、8 和 11 的次数,或者我们在 I 的前三行看到的任何次数。 accumarray 做同样的事情,但accumarray 是一个更通用的函数,它不仅仅是将相同垃圾箱中的东西加在一起。 histc 是适合您的情况的更好方法 - 特别是因为垃圾箱的数量是恒定的。


    作为对这篇文章的编辑,您在下面的 cmets 中说您希望能够将其应用于 18 个列段。最好的办法可能是在某种循环中执行此操作。首先计算出我们有多少个 18 列的段,然后将其放入循环中多次并更新我们的结果。在循环中的每次迭代中,我们需要从矩阵中取出正确的 18 列,并不断获取 18 的块,直到到达数组的末尾。

    我们将结果放在另一个矩阵中,其中每一列是每 18 列段中三个最常出现的音符的结果。

    类似这样的:

    numColumns = size(C, 2); %// Get total number of columns for matrix
    numSegments = ceil(numColumns / 18); %// Get total number of segments
    
    finalMatrix = zeros(12, numSegments);
    for idx = 1 : numSegments
    
        %// Make sure that when we get 18 chunks, we don't out of bounds
        if 18*idx > numColumns
            seg = C(:,(idx-1)*18 + 1 : end);
        else
            seg = C(:,(idx-1)*18 + 1 : 18*idx);
        end
    
        [~,I] = sort(seg, 1, 'descend');
        ind = I(1:3,:); %// Get the first three rows of the sorted indices
        notes = histc(ind(:), 1:12);
    
        %// Your code
        [~,y] = sort(notes, 'descend'); 
        finalvec = zeros(12,1);
        finalvec(y(1)) = 1; finalvec(y(2)) = 1; finalvec(y(3)) = 1;
    
        %// Place in final matrix
        finalMatrix(:, idx) = finalvec;
    end
    

    finalMatrix 会将每个 18 段的结果存储到一个单独的列中,其中每一列是您在评论中编写的逻辑。

    【讨论】:

    • 哇,谢谢!很好解释。现在要构建一个包含 3 个最高音符的向量,我做了这样的事情:finalvec = zeros(12,1); [x,y] = sort(notes, 'descend'); finalvec(y(1)) = 1; finalvec(y(2)) = 1; finalvec(y(3)) = 1;显示(finalvec);够了吗?
    • 是的,我觉得不错!
    • 顺便说一句,如果我有帮助,请考虑接受我的回答。祝你好运!
    • @JurgenCuschieri - 谢谢!最简单的方法是循环执行此操作并将矩阵分解为 12 行的 18 列段。此上下文中的 ~ 表示您要丢弃该输出变量。因为我没有使用它,所以分配一个变量来存储这个结果是没有意义的,所以~ 基本上丢弃了结果。
    • @JurgenCuschieri - 我会更新我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-26
    • 1970-01-01
    • 2016-06-22
    • 1970-01-01
    相关资源
    最近更新 更多