【问题标题】:Matlab comparison of two large matricies两个大矩阵的Matlab比较
【发布时间】:2017-10-27 11:26:14
【问题描述】:

我正在尝试检索两个大型矩阵之间的完全匹配(特定于行)的索引。我有一个 n x 61 矩阵 A 包含从 0 到 9 的值和另一个 n x 61 矩阵 B ,而这里的每一行包含从 0 到 9 但主要是 NaN 的值(矩阵 B 的每一行中只有 2 到 8 列包含实际数字)。矩阵 A 预计有 150 万到 300 万行,而矩阵 B 大约有 0.2 到 50 万行。以下是设置示例:

% create matrix a with random data

dataSample = [0 9];
numRows = 1000000;
numCols = 61;
A = randi(dataSample,numRows,numCols);

% create matrix B with random data
numRows = 100000;
numCols = 61;
numColsUse = 2:8;
dataRange = 0:9;
B = NaN(numRows,numCols);
for i = 1:size(B,1)

    % randomly selet number of columns to fill
    numColsFill = datasample(numColsUse,1);

    % randomly select column index from available columns
    colIdx = datasample([1:numCols],numColsFill);

    % randomly select values from 0 to 9
    numFill = datasample([0:9],numColsFill);

    % insert numbers at respective column in matrix B
    B(i,colIdx) = numFill;

end

我想将矩阵 A 的每一行与整个矩阵 B 进行比较并找到完全匹配,其中矩阵 B 的数量与矩阵 A 在其各自位置(列)的数量相匹配 - 因此矩阵 B 中的 NaN 是被忽略。

我可以使用 cellfun 实现所需的结果,我将矩阵 A 分割成几个子集,然后使用自定义函数将子集的行与矩阵 B 中的每一行进行比较,如下所示:

% put all rows of matrix B in single cell
cellB = {B};

% take subset of matrix A and convert to cell array
subA = A(1000:5000,:);
subA = num2cell(subA,2);

% prepare cellB to meet cellfun conditions
cellB = repmat(cellB, [size(subA,1) 1]);

% apply cellfun to retrieve index of each exact match
idxContainer = cellfun(@findMatch, cellB, subA, 'UniformOutput', false);

函数 findMatch 如下所示:

function [ idx ] = LTableEval( cellB,  subA )

    idxCheckLT = lt(cellB, repmat(subA, [size(cellB,1) 1]));
    idxCheckGT = gt(cellB, repmat(subA, [size(cellB,1) 1]));
    idxCheck = idxCheckLT + idxCheckGT;
    idxSum = sum(idxCheck,2);
    idx = find(idxSum == 0);

end

这种方法有效,但似乎效率很低,尤其是在 RAM 方面,因为 cellfun 要求所有输入具有相同的大小,因此需要乘以相同的数据集。关于如何以更有效的方式解决这个问题的任何想法?非常感谢!

【问题讨论】:

  • 矩阵减法?
  • A-B==0?减法似乎是可行的方法
  • 我同意,减法对于实际比较来说很有意义,并且比我目前的方法要好得多。但是,这并不能解决我更基本的问题,即我想找到一种有效的方法来用每一行 B 减去 A 的每一行。在这方面有什么想法吗?谢谢!

标签: matlab matrix indexing comparison


【解决方案1】:

mathworks 论坛向我提供了以下解决方案:

matches = cell(size(B, 1), 1);
for Brow = 1:size(B, 1)
    Bcols = find(~isnan(B(Brow, :)));
    fdsmatchedrows = find(all(A(:, Bcols) == B(Brow, Bcols), 2));
    matches{Brow} = [matchedrows, repmat(Brow, size(matchedrows))];
end
matches = cell2mat(matches);

这仅适用于 R2016a 及更高版本。或者,将 for 循环中的第二行替换为以下行:

matches{Brow} = find(all(bsxfun(@eq, A(:, Bcols), B(Brow, Bcols)), 2));

结果与 Jed 提供的解决方案相同,但我认为通过使用 bsxfun 更快一点。希望对您有所帮助!

【讨论】:

    【解决方案2】:

    这个怎么样:

    for br = 1:size(B,1)
      abs_diff = abs(repmat(B(br,:),[size(A,1) 1]) - A);
      abs_diff(isnan(abs_diff)) = 0;
      match = abs_diff == 0;
      ind = find(sum(match,2)==size(match,2));
      matches{br} = [repmat(br,[length(ind) 1]) ind];
    end
    matches = cell2mat(matches');
    

    【讨论】:

    • 嗨,杰德,感谢您的建议。这已经工作得更好了,我喜欢循环遍历 B 的每一行而不是 A 的想法,并且不需要将 A “切片”成子部分。但是,对我来说,循环的单次迭代仍然高于 1 秒,所以即使我使用 parfor,我也在考虑很长的计算时间......还有什么进一步的想法吗?谢谢!
    • 是的...使用 mex 函数。
    猜你喜欢
    • 2010-10-30
    • 1970-01-01
    • 1970-01-01
    • 2013-08-08
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多