Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/matlab/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/heroku/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Matlab 时间序列聚合效率_Matlab_Time Series - Fatal编程技术网

Matlab 时间序列聚合效率

Matlab 时间序列聚合效率,matlab,time-series,Matlab,Time Series,我通常需要用给定的聚合函数(即总和、平均值等)总结一个时间不规则的时间序列。然而,我目前的解决方案似乎效率低下,速度缓慢 以聚合函数为例: function aggArray = aggregate(array, groupIndex, collapseFn) groups = unique(groupIndex, 'rows'); aggArray = nan(size(groups, 1), size(array, 2)); for iGr = 1:size(groups,1)

我通常需要用给定的聚合函数(即总和、平均值等)总结一个时间不规则的时间序列。然而,我目前的解决方案似乎效率低下,速度缓慢

以聚合函数为例:

function aggArray = aggregate(array, groupIndex, collapseFn)

groups = unique(groupIndex, 'rows');
aggArray = nan(size(groups, 1), size(array, 2));

for iGr = 1:size(groups,1)
    grIdx = all(groupIndex == repmat(groups(iGr,:), [size(groupIndex,1), 1]), 2);
    for iSer = 1:size(array, 2)
      aggArray(iGr,iSer) = collapseFn(array(grIdx,iSer));
    end
end

end
请注意,
array
groupIndex
都可以是二维的。
array
中的每一列都是要聚合的独立序列,但是
groupIndex
中的列应该放在一起(作为一行)以指定一个期间

然后,当我们将一个不规则的时间序列引入时(注意,第二个周期比第一个基期长一个基期),计时结果很差:

a = rand(20006,10);
b = transpose([ones(1,5) 2*ones(1,6) sort(repmat((3:4001), [1 5]))]);

tic; aggregate(a, b, @sum); toc
Elapsed time is 1.370001 seconds.
使用探查器,我们可以发现
grpIdx
行占用了大约1/4的执行时间(.28秒),而
iSer
循环占用了大约3/4(1.17秒)的总时间(1.48秒)

将其与时间无关的情况进行比较:

tic; cumsum(a); toc
Elapsed time is 0.000930 seconds.
有没有更有效的方法来聚合这些数据


计时结果 将每个响应放在一个单独的函数中,下面是我在Windows 7上使用Matlab 2015b和Intel i7获得的使用
timeit
的计时结果:

    original | 1.32451
      felix1 | 0.35446
      felix2 | 0.16432
    divakar1 | 0.41905
    divakar2 | 0.30509
    divakar3 | 0.16738
matthewGunn1 | 0.02678
matthewGunn2 | 0.01977
关于
groupIndex
2D
groupIndex
的一个例子是,为涵盖1980-2015年的一组每日数据指定了年数和周数:

a2 = rand(36*52*5, 10);
b2 = [sort(repmat(1980:2015, [1 52*5]))' repmat(1:52, [1 36*5])'];

因此,“年-周”周期由一行
groupIndex
唯一标识。通过调用
unique(groupIndex,'rows')
并获取第三个输出,可以有效地处理这一问题,因此可以忽略问题的这一部分。

去掉内部循环,即

function aggArray = aggregate(array, groupIndex, collapseFn)

groups = unique(groupIndex, 'rows');
aggArray = nan(size(groups, 1), size(array, 2));

for iGr = 1:size(groups,1)
    grIdx = all(groupIndex == repmat(groups(iGr,:), [size(groupIndex,1), 1]), 2);
   aggArray(iGr,:) = collapseFn(array(grIdx,:));
end
以及使用维度参数调用collapse函数

res=aggregate(a, b, @(x)sum(x,1));
在遇到没有标注参数的单行数据,然后跨列而不是标签折叠时,已经提供了一些加速(在我的机器上是3倍),并避免了错误,例如sum或mean PRODUCT

如果只有一个组标签向量,即所有数据列的组标签相同,则可以进一步加快速度:

function aggArray = aggregate(array, groupIndex, collapseFn)

ng=max(groupIndex);
aggArray = nan(ng, size(array, 2));

for iGr = 1:ng
    aggArray(iGr,:) = collapseFn(array(groupIndex==iGr,:));
end
后面的函数为您的示例提供了相同的结果,具有6倍的加速比,但不能处理每个数据列的不同组标签

假设组索引有一个2D测试用例(此处提供了组索引的10个不同列):

a = rand(20006,10);
B=[]; % make random length periods for each of the 10 signals
for i=1:size(a,2)
      n0=randi(10);
      b=transpose([ones(1,n0) 2*ones(1,11-n0) sort(repmat((3:4001), [1 5]))]);
      B=[B b];
end
tic; erg0=aggregate(a, B, @sum); toc % original method 
tic; erg1=aggregate2(a, B, @(x)sum(x,1)); toc %just remove the inner loop
tic; erg2=aggregate3(a, B, @(x)sum(x,1)); toc %use function below
运行时间为2.646297秒。 运行时间为1.214365秒。 运行时间为0.039678秒(!!!!)

我认为这是最快的,因为它没有使用MEX。感谢马修葛恩的建议! 分析表明,“unique”在这里非常便宜,只获取groupIndex中重复行的第一个和最后一个索引可以大大加快速度。我在这个聚合迭代中获得88倍的加速。

方法#1

您可以跨所有网格创建对应于
grIdx
的掩码
一次完成。现在,对于
collapseFn
作为
@sum
,您可以引入,因此有一个完全矢量化的方法,如下所示-

M = squeeze(all(bsxfun(@eq,groupIndex,permute(groups,[3 2 1])),2))
aggArray = M.'*array
dims = max(groupIndex,[],1);
agg_dims = cumprod([1 dims(end:-1:2)]);
[~,~,idx] = unique(groupIndex*agg_dims(end:-1:1).'); %//'

m = size(groupIndex,1);
M = false(m,max(idx));
M((idx-1)*m + [1:m]') = 1;
对于
collapseFn
作为
@mean
,您需要做更多的工作,如下所示-

M = squeeze(all(bsxfun(@eq,groupIndex,permute(groups,[3 2 1])),2))
aggArray = bsxfun(@rdivide,M,sum(M,1)).'*array

方法#2

如果您使用的是一个通用的
collapseFn
,您可以使用前面方法创建的二维掩码
M
索引到
数组的行中,从而将复杂性从
O(n^2)
更改为
O(n)
。一些快速测试表明,与原始循环代码相比,这可以提供可观的加速。以下是实现-

n = size(groups,1);
M = squeeze(all(bsxfun(@eq,groupIndex,permute(groups,[3 2 1])),2));
out = zeros(n,size(array,2));
for iGr = 1:n
    out(iGr,:) = collapseFn(array(M(:,iGr),:),1);
end
请注意,
collapseFn(数组(M(:,iGr),:),1)
中的
1
表示应用
collapseFn
的维度,因此
1
在那里是必不可少的


奖金

顾名思义,
groupIndex
似乎包含整数值,通过将
groupIndex
的每一行视为一个索引元组,从而将
groupIndex
的每一行转换为一个标量,最终得到
groupIndex的1D数组版本,可以滥用整数值来更有效地创建
M
e> 。这必须更有效,因为现在的数据大小将是
0(n)
。这
M
可以提供给本文中列出的所有方法。因此,我们将有
M
这样-

M = squeeze(all(bsxfun(@eq,groupIndex,permute(groups,[3 2 1])),2))
aggArray = M.'*array
dims = max(groupIndex,[],1);
agg_dims = cumprod([1 dims(end:-1:2)]);
[~,~,idx] = unique(groupIndex*agg_dims(end:-1:1).'); %//'

m = size(groupIndex,1);
M = false(m,max(idx));
M((idx-1)*m + [1:m]') = 1;
Mex功能1 锤击时间:: 在我的机器上,使用问题中的原始代码进行的基本用例测试花费了1.334139秒。IMHO,结果是:

运行时间为0.589330秒

然后我的MEX函数:

[groups3, aggArray3] = mg_aggregate(array, groupIndex, @(x) sum(x, 1));
运行时间为0.079725秒

测试我们是否得到相同的答案:
norm(groups2-groups3)
返回
0
norm(aggArray2-aggArray3)
返回
2.3959e-15
。结果也与原始代码匹配

生成测试条件的代码:

array = rand(20006,10);
groupIndex = transpose([ones(1,5) 2*ones(1,6) sort(repmat((3:4001), [1 5]))]);
对于纯速度,GO MEX。如果编译C++代码/复杂性的想法太痛苦了,那么就去Divakar的答案。另外一个免责声明:我没有将我的功能应用到健壮的测试。

Mex方法2 让我有些惊讶的是,在某些情况下,此代码甚至比完整的Mex版本还要快(例如,在本测试中大约花费了0.05秒)。它使用a来计算组的索引。我认为这可能是因为我在完整的mex函数中复制数组的速度不如它可能快,和/或调用“feval”的开销。它的算法复杂性基本上与另一个版本相同

[unique_groups, map] = mg_getRowsWithKey(groupIndex);

results = zeros(length(unique_groups), size(array,2));

for iGr = 1:length(unique_groups)
   array_subset             = array(map{iGr},:);

   %// do your collapse function on array_subset. eg.
   results(iGr,:)           = sum(array_subset, 1);
end
当您执行
array(groups(1)=groupIndex,:)
以提取与完整组关联的数组项时,您将搜索整个groupIndex长度。如果您有数百万行项,这将完全是一个糟糕的操作。
array(map{1},:)
的效率要高得多


仍然存在不必要的内存复制和与对折叠函数调用“feval”相关的其他开销
function aggArray = aggregate(array, group, collapseFn)
    [m,~] = size(array);
    n = max(group);
    D = false(m,n); 
    row = (1:m)';
    idx = m*(group(:) - 1) + row;
    D(idx) = true;
    out = zeros(m,size(array,2));
    for ii = 1:n
        out(ii,:) = collapseFn(array(D(:,ii),:),1);
    end
end
function aggArray = aggregate_gnovice(array, groupIndex, collapseFn)

  [groups, ~, index] = unique(groupIndex, 'rows');
  numCols = size(array, 2);
  aggArray = nan(numel(groups), numCols);
  for col = 1:numCols
    aggArray(:, col) = accumarray(index, array(:, col), [], collapseFn);
  end

end
original | 1.127141
 gnovice | 0.002205