【问题标题】:Matlab: Count till sum equals 360 > insert event1, next 360 >insert event 2 etcMatlab:计数直到总和等于 360 > 插入事件 1,下一个 360 > 插入事件 2 等
【发布时间】:2014-03-27 14:57:13
【问题描述】:

我已经尝试解决这个问题一段时间了,如果能朝着正确的方向前进,我将不胜感激。

我有一个名为 Turn 的矩阵。该矩阵包含 1 列数据,介于 10000 到 15000 行之间(可变)。我喜欢做的事情如下: 从第 1 行开始并添加第 2 行、第 3 行等的值,直到总和 ==360。当 sum==360 在该特定行“事件 1”的第 2 列中插入。 从下一行开始计数(在“事件 1”之后),直到总和 ==360。当 sum==360 在该特定行“事件 2”的第 2 列中插入。等等

所以我基本上想将我的数据分组到 sum==360 的分区中 这些将被称为事件。

sum==360 所在的行号对我也很重要(每一行都是一个时间点,因此它会告诉我事件的持续时间)。我想将这些行号放在一个新矩阵中,其中第 1 行:rownr 事件 1 发生,第 2 行:rownr 事件 2 发生等等。

【问题讨论】:

    标签: matlab if-statement sum


    【解决方案1】:

    您可以使用以下代码找到发生事件的行索引。基本上,您将使用模运算符来查找Turn 的第一列的总和是 360 的倍数。

    mod360 = mod(cumsum(Turn(:,1)),360);
    eventInds = find(mod360 == 0);
    

    然后您可以遍历eventInds 以将您想要的任何值放在Turn 第二列的适当行中。

    我认为您不能将字符串“event 1”放在列中,因为字符串数组的行为类似于向量,并且会导致维度不匹配。您可以只为第一个事件存储数值1,为第二个事件存储2,依此类推。

    【讨论】:

    • 所以在 mod360 矩阵中我找到了达到 360 的实例?事件的数字也可以
    • 巧妙地使用模运算来查找索引。 +1
    • mod360 将包含您的累积总和除以 360 的余数。因此,mod360 包含零的任何地方都意味着您的第一列的累积总和是 360 的倍数。
    【解决方案2】:

    Ryan 的回答看起来不错。但是,如果您的条件是您需要找到累积和不完全是 360 的行号,那么您将需要做更多的工作。对于这种情况,您可以使用这个 -

    试试这个矢量化(并且没有循环)代码来获取发生 360 分组的行 ID -

    threshold = 360;
    cumsum_val = cumsum(Turn);
    ind1 = find(cumsum_val>=threshold,1)
    num_events = floor(cumsum_val(end)/threshold);
    [x1,y1] = find(bsxfun(@gt,cumsum_val,threshold.*(1:num_events)));
    [~,b,~] = unique(y1,'first');
    row_nums = x1(b)
    

    之后就可以获取事件数据了,像这样-

    event1 = Turn(1:row_nums(1));
    event2 = Turn(row_nums(1)+1:row_nums(2));
    event3 = Turn(row_nums(2)+1:row_nums(3));
    ...
    event21 = Turn(row_nums(20)+1:row_nums(21));
    
    ...
    eventN = Turn(row_nums(N-1)+1:row_nums(N));
    

    编辑 1

    示例案例:

    我们创建了一个由20 随机整数组成的小数据,而不是用于原始问题的15000。此外,我们使用30 的阈值而不是360 来考虑小数据量。

    代码

    Turn = randi(10,[20 1]);
    threshold = 30;
    
    cumsum_val = cumsum(Turn);
    ind1 = find(cumsum_val>=threshold,1)
    num_events = floor(cumsum_val(end)/threshold);
    [x1,y1] = find(bsxfun(@gt,cumsum_val,threshold.*(1:num_events)));
    [~,b,~] = unique(y1,'first');
    row_nums = x1(b);
    

    运行

    Turn =
    
         7
         6
         3
         4
         5
         3
         9
         2
         3
         2
         3
         5
         4
        10
         5
         2
        10
        10
         5
         2
    
    
    threshold =
    
        30
    
    
    row_nums =
    
         7
        14
        18
    

    运行结果显示row_nums7, 14, 18,表示第二组从Turn中的第7个索引开始,第三组从第14个索引开始,以此类推。当然,你可以在row_nums的开头附加1,表示第一个分组从第一个索引开始。

    【讨论】:

    • 我尝试了这种方法,它部分有效。事件的数量是正确的,但是 row_nums 是 8 倍 1
    • @user3462307 row_nums 基本上是Turn 的行索引向量,每个这样的 360 分组从这里开始。在上面的编辑 1 部分了解更多信息。
    【解决方案3】:

    给定一个列向量x,比如说,

    x = randi(100,10,1)
    

    以下将为您提供第一行的索引,其中该行上方所有项目的累积总和总计为 360:

    i = max( find( cumsum(x) <= 360) )
    

    然后,您将不得不使用该索引来查找下一组累计和为 360,类似于

    offset = max( find( cumsum(x(i+1:end)) <= 360 ) )
    i_new = i + offset
    

    您可能需要将 +1/-1 添加到偏移量和索引。

    >> x = randi(100,10,1)'
    x =
      90    47    47    44     8    79    45     9    91     6
    
    >> cumsum(x)
    ans =
      90   137   184   228   236   315   360   369   460   466
    
    >> i = max(find(cumsum(x)<=360))
    i =
      7
    

    【讨论】:

    • 感谢您的快速回复。我之前尝试过,但没有奏效。它基本上给出了最后一个行号(在本例中为 15550),而在第 10 行指示值 360。所以我应该是第 10 行
    • 你一定是搞错了。上面的代码应该可以工作。请参阅我在答案中发布的结果。
    • 不知道是什么,但你是对的,第一部分现在可以了。
    • 您必须编写一个 for 循环,最初是 offset=0。在 for 循环中计算 i,计算 offset 并将其添加到 i 以在下一次迭代中计算其新值,依此类推。
    猜你喜欢
    • 2014-12-30
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    相关资源
    最近更新 更多