我有这样的数据:
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
(例如)并行运行。有没有办法在所有列中同时使用矢量化矩阵运算?
编辑:我应该补充说,由于每个设备可能具有不同数量的正常运行时间,因此这很复杂。
答案 0 :(得分:3)
这是一种方式。但不确定它是否为矢量化。
让您的数据矩阵表示为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
中查找零的行索引和列索引(即true
中的~x
值),然后使用列索引作为分组变量(首先参数accumarray
)。
在每个组中,我们使用anonymous function @(x){nonzeros(diff(x)-1)}
来计算零行位置的差异。我们可以直接应用diff
,因为来自find
的列索引已经排序,这要归功于Matlab的column major顺序。我们减去1
因为x
中的零不算作正常运行时间的一部分;删除等于0
的正常运行时间长度(使用nonzeros
),并将结果向量打包到单元格中({...}
)。
附加一行true
值并添加到~x
,以确保我们检测到初始和最终正常运行时间段。