【问题标题】:How do I calculate the length of continuous occurrences of a value (uptimes) in a matrix?如何计算矩阵中值(正常运行时间)连续出现的长度?
【发布时间】:2015-12-29 23:45:11
【问题描述】:

我有这样的数据:

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

每一列代表一个设备,每一行代表一个时间段。每个数据点指示设备在该时间段内是否处于活动状态。我正在尝试计算每个设备处于活动状态的每个正常运行时间或“咒语”的长度。换句话说,每列中每个连续咒语的长度。在这种情况下,第一列将是 2 11 3,依此类推。

这很容易在一台设备上完成(单列数据):

rng(1)

%% Parameters
lambda = 0.05;      % Pr(failure)
N = 1;              % number of devices
T = 18;             % number of time periods in sample

%% Generate example data
device_status = [rand(T, N) >= lambda ; false(1, N)];

%% Calculate spell lengths, i.e. duration of uptime for each device
cumul_status = cumsum(device_status);

% The 'cumul_status > 0' condition excludes the case where the vector begins with one
% or more zeros
cumul_uptimes = cumul_status(device_status == 0 & cumul_status > 0);
uptimes = cumul_uptimes - [0 ; cumul_uptimes(1:end-1)];

所以我可以简单地遍历列并一次执行一列,并使用parfor(例如)并行运行它。有没有办法使用矢量化矩阵运算同时在所有列上执行此操作?

编辑:我应该补充一点,这很复杂,因为每个设备可能有不同数量的正常运行时间。

【问题讨论】:

  • 您可以尝试使用类似:reshape(max(cumsum(cumprod(hankel([zeros(1,size(A,2));A])'))),size(A,1)+1,size(A,2)); 其中 A 是矩阵。然后你可以找到局部最大值,但有时使用循环会更好更快。
  • 如果您没有那么多设备,那么我认为将这种方法与循环一起使用是非常好的。不要把事情复杂化。 Donald Knuth 说它是最好的“过早的优化是万恶之源”。除非您可以清楚地看到单独循环每个设备与尝试以矢量化方式对所有设备执行此操作之间存在巨大的运行时差异,否则不值得这样做。
  • 另外作为旁注,您可能不会为每列获得相同数量的正常运行时间。特别是在您的示例中,第一列有三个正常运行时间实例,而最后两个有两个。这种“不均匀”已经阻碍了您的矢量化能力。
  • @rayryeng 这是一个很好的观点。我最初意识到这一点,但我忘了在我的问题中明确说明。我添加了一个编辑。另外,你说得对,循环可能是我最好的选择。我主要是为了教育而问这个问题,因为我在问 SO 的时候总是学到不少东西。

标签: arrays matlab matrix vectorization


【解决方案1】:

这是一种方法。不过,不确定它是否算作矢量化。

让您的数据矩阵表示为x。那么

[ii, jj] = find([true(1,size(x,2)); ~x; true(1,size(x,2))]);
result = accumarray(jj, ii, [], @(x){nonzeros(diff(x)-1)});

生成一个元胞数组,其中每个元胞对应一列。在你的例子中,

result{1} =
     2
    11
     3
result{2} =
    13
     3
result{3} =
     6
    11

这是如何工作的

想法是在x中找到零的行和列索引(即~x中的true值),然后将列索引用作分组变量(accumarray的第一个参数) .

在每个组中,我们使用anonymous function@(x){nonzeros(diff(x)-1)} 来计算零的行位置差异。我们可以直接应用diff,因为来自find 的列索引已经排序,这要归功于Matlab 的column major 顺序。我们减去1,因为x 中的零不算作正常运行时间的一部分;删除等于0(使用nonzeros)的正常运行时间长度,并将生成的向量打包到一个单元格中({...})。

一行true 值被附加并附加到~x 之前,以确保我们检测到初始和最终正常运行时间段。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-08
    • 1970-01-01
    • 2021-05-08
    • 2021-05-15
    • 1970-01-01
    • 2014-08-12
    • 2022-01-25
    相关资源
    最近更新 更多