将不同长度的矩阵行存储到单元格中的快速方法

Fast way to store different length Matrix rows into Cell

我有三个矩阵:

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。在我的示例中,我想获取列 14。因此,我想从 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))

P.S。没有必要将它保存到元胞数组中。如果您能提供任何其他解决方案,我将不胜感激。


我正在寻找最快的方法,这可能是通过避免 for 循环和使用矢量化。

我对 sub2ind 函数想了很多。但是我不知道如何 return 不同大小的数组!因为 myCell{1} - [82x1]myCell{2} - [73x1]。我想我不能使用 bsxfunarrayfun.


结果:

  1. 使用 for 相似的循环 :

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

    经过的时间是 157 秒

  2. 使用arrayfun相似:

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

    经过的时间是 179 秒

  3. 使用bsxfun相似:

    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 循环仍然是最快的!

% 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]

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

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

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

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

在 MATLAB R2016b 或 Octave 中(感谢 broadcasting/expansion)可以写成:

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);

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

%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));