【问题标题】:Fast way to store different length Matrix rows into Cell将不同长度的矩阵行存储到单元格中的快速方法
【发布时间】:2016-12-12 08:56:11
【问题描述】:

我有三个矩阵:

Values = [200x7] doubles
numOfStrings = [82    78    75    73    72    71    70] %(for example)
numOfColumns = [1 4] 

numOfColumns 可以包含从 1 到 7 的任意一组不同的值。例如 [1 2 3] 或 [4 7] 或 [1 5 6 7]。显然,最大的numOfColumns 可以是[1 2 3 4 5 6 7]。

numOfColumns 显示我想要获取的列。 numOfStrings 显示了我需要的那些列的行。 IE。在我的示例中,我想获取列 1 和 4。因此,我想从1 列获取82 第一行,从4th 获取73 第一行。

即如果numOfColumns = [1 4] 那么

myCell{1} = Values( 1:82,1); % Values(numOfStrings(numOfColumn(1)), numOfColumn(1))
myCell{2} = Values( 1:73,4); % Values(numOfStrings(numOfColumn(2)), numOfColumn(2))

附:没有必要将其保存到单元格数组中。如果您能提供任何其他解决方案,我将不胜感激。


我正在寻找最快的方法来做到这一点,这可能是避免for 循环并使用矢量化。

我对@9​​87654342@ 函数想了很多。但我不知道如何返回不同大小的数组!因为myCell{1} - [82x1] 和myCell{2} - [73x1]。我想我不能使用bsxfun 或arrayfun。


结果:

  1. 使用for 循环类似@Will 's answer:

    for jj = 1:numel(numOfColumns)
        myCell{rowNumber(numOfColumns(jj)),numOfColumns(jj)} = Values( 1:numOfStrings(numOfColumns(jj)),numOfColumns(jj));
    end
    

    经过的时间是 157 秒

  2. 使用arrayfun 类似@Yishai E 's answer:

    myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = arrayfun( @(nOC) Values( 1:numOfStrings(nOC),nOC), numOfColumns, 'UniformOutput', false);
    

    经过的时间是 179 秒

  3. 使用bsxfun 类似@rahnema1 's answer:

    idx = bsxfun(@ge,numOfStrings , (1:200).');
    extracted_values = Values (idx);
    tempCell = mat2cell(extracted_values,numOfStrings);
    myCell(sub2ind(size(myCell),rowNumber(numOfColumns),numOfColumns)) = myCell(numOfColumns)';
    

    经过的时间是 204 秒

所以,我得到了很多可行的答案,其中一些按照我的要求进行了矢量化,但 for 循环仍然最快!

【问题讨论】:

  • 您无法避免 for 使用元胞数组循环。但是,最新版本的 MATLAB 对 JIT 进行了改进得多,因此与更标准的矢量化方法相比,循环更具竞争力。
  • 我认为基准不正确
  • @rayryeng 三个答案中有两个没有使用for。但我认为for-solution 更快,因为我无法正确实现矢量化代码...
  • @rahnema1Yep,恐怕我无法有效地实现您的代码 - 我使用了很多辅助功能......但仍然无法弄清楚如何避免它们
  • 我无法弄清楚时间是如何花费 179 s 的。你能提供一个带有实际尺寸的完整例子吗? rowNumber 是什么?试试这个:numcols_logical = false(1,numel(numOfColumns)); numcols_logical(numOfColumns) = true; extracted_values = Values(bsxfun(@ge, numOfStrings .* numcols_logical , (1:200).')); result= mat2cell(extracted_values,numOfStrings(numcols_logical));

标签: arrays matlab loops vectorization cell-array


【解决方案1】:

这应该可以解决您的问题,使用 arrayfun,它“矢量化”索引函数的应用程序。不是真的,但它不会为 numOfColumns 中的每个条目调用解释器。有趣的是,这比其他答案中的非矢量化代码慢! (对于 1e5 个条目,0.95 秒对 0.23 秒...)

arrayfun(@(nOC)Values(1:numOfStrings(nOC), nOC), numOfColumns, 'UniformOutput', false)

【讨论】:

  • 有用且足够快的代码!谢谢!如果我避免在我的任务中使用sub2ind,它可能会像for 循环一样快。我在我的问题中添加了结论!
【解决方案2】:
% Get number of elements in NUMOFCOLUMNS
n = numel(numOfColumns);

% Set up output
myCell = cell(1,n);    

% Loop through all NUMOFCOLUMNS values, storing to cell
for i = 1:n

    myCell{i} = Values(1:numOfStrings(numOfColumns(i)), numOfColumns(i));

end 

你的例子给出了输出

myCell = 

[82x1 double]    [73x1 double]

【讨论】:

  • 是的,这行得通!谢谢!但是您知道矢量化视图中的任何解决方案吗?只是为了避免循环,就像我问的那样?
  • @Mikhail_Sam 你能解释一下为什么需要矢量化解决方案吗?
  • @Mikhail_Sam 同意,但我的上述代码在 0.05 秒内运行......它是否被多次调用或用于比上面给出的更大的示例,在这种情况下优化是关键?
  • 没错!我将选择 500 万行数组并将其划分为一组不相等的数组,例如 myCell。所以这种情况下计算速度很重要
  • 威尔,看起来你的答案是最快的!谢谢!我在我的问题中添加了结论!
【解决方案3】:

您可以创建逻辑索引以提取所需元素:

idx = bsxfun(@ge,numOfStrings , (1:200).');

在 MATLAB R2016b 或 Octave 中(感谢广播/扩展)可以写成:

idx = numOfStrings >= (1:200).';

提取值:

extracted_values = Values (idx);

然后使用mat2cell 将数据转换为单元格:

myCell = mat2cell(extracted_values,numOfStrings);

一条龙:

myCell = mat2cell(Values (numOfStrings >= (1:200).'), numOfStrings);

如果您想使用不同大小的不同numOfColumns 来提取单元格的元素,您可以每次都这样做:

result = myCell(numOfColumns);

如果numOfStrings 和numOfColumns 都发生变化并且您需要计算一次结果,请执行以下操作:

%convert numOfColumns to logical index:
numcols_logical = false(1,7);
numcols_logical(numOfColumns) = true;
extracted_values = Values ((numOfStrings .* numcols_logical) >= (1:200).');

如果需要元胞数组

result= mat2cell(extracted_values,numOfStrings(numcols_logical));

【讨论】:

  • 完美运行!不知道R2016b这个功能,但是我还是用R2016a,所以用了bsxfun。也许它在 2016b 中运行得更快。总之谢谢!我在我的问题中添加了结论!
猜你喜欢
  • 2011-03-04
  • 1970-01-01
  • 2012-10-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多