String MATLAB:字符串单元格数组之间的单词匹配

String MATLAB:字符串单元格数组之间的单词匹配,string,algorithm,matlab,comparison,vectorization,String,Algorithm,Matlab,Comparison,Vectorization,我正在尝试解决以下问题,我需要尽可能高效地解决(即尽可能避免循环) 我有两个单元格数组,即A和B。A和B的每个单元格都包含一个字符串。这些字符串的长度是可变的。比如说: A={‘life is wonderful’, ‘matlab makes your dreams come true’}; B={‘life would be meaningless without wonderful matlab’, ‘what a wonderful world’, ‘the shoemaker mak

我正在尝试解决以下问题,我需要尽可能高效地解决(即尽可能避免循环)

我有两个单元格数组,即A和B。A和B的每个单元格都包含一个字符串。这些字符串的长度是可变的。比如说:

A={‘life is wonderful’, ‘matlab makes your dreams come true’};

B={‘life would be meaningless without wonderful matlab’, ‘what a wonderful world’, ‘the shoemaker makes shoes’, ‘rock and roll baby’};
此外,单元阵列B的元素数量比单元阵列A的元素数量大约大三个数量级

我的目标是找出A中每个字符串的多少个单词也出现在B的每个字符串中

对于上一个示例,合适的结果可能是:

match = [2 1 0 0
1 0 1 0]
第一行表示A的第一个字符串中有多少个单词出现在B的四个字符串中。第二行表示A的第二个字符串中有多少个单词

双环实现非常简单,但非常耗时,特别是因为单元阵列B的长度(超过300万个单元)

有什么想法吗?多谢各位


Xavier

让我先发布“简单”的解决方案(至少其他人有一个比较基准):

结果是:

>> count
count =
     2     1     0     0
     1     0     1     0

更好的算法可能是建立某种索引或哈希表…

解决方案并不复杂

用下列句子分开句子:

a_words = regexp(A,'(\w+)','match')
b_words = regexp(B,'(\w+)','match')
然后在循环中进行比较:

match = nan(numel(a_words),numel(b_words));
for i = 1:numel(a_words)
    for j = 1:numel(b_words)
        match(i,j) = sum(ismember(a_words{i},b_words{j}));
    end
end
但是为了更快,我不太确定。 您完全可以将内部循环放入parfor中,该parfor应该与之并行。 如果真的有很多单词,可以把它们放到数据库里。这将为您建立索引。

您可以利用它,它为您提供了一个高效的基于词典的结构:

对于每个单词,保存向量,显示每个字符串中出现的情况:

A = {'life is wonderful', 'matlab makes your dreams come true'};
B = {'life would be meaningless without wonderful matlab', 'what a wonderful world', 'the shoemaker makes shoes', 'rock and roll baby'};

mapA = containers.Map();
sizeA = size(A,2);
for i = 1:size(A,2)         % for each string
    a = regexpi(A(i),'\w+','match');
    for w = a{:}                % for each word extracted
        str = cell2mat(w);
        if(mapA.isKey(str))     % if word already indexed
            occ = mapA(str);
        else                    % new key
            occ = zeros(1,sizeA);
        end
        occ(i) = occ(i)+1;
        mapA(str) = occ;
    end
end

% same for B
mapB = containers.Map();
sizeB = size(B,2);
for i = 1:size(B,2) 
    a = regexpi(B(i),'\w+','match');
    for w = a{:}
        str = cell2mat(w);
        if(mapB.isKey(str))
            occ = mapB(str);
        else
            occ = zeros(1,sizeB);
        end
        occ(i) = occ(i)+1;
        mapB(str) = occ;
    end
end
然后,对于在A中找到的每个唯一单词,计算与B的匹配

match = zeros(size(A,2),size(B,2));
for w = mapA.keys
    str = cell2mat(w);
    if (mapB.isKey(str))
        match = match + diag(mapA(str))*ones(size(match))*diag(mapB(str));
    end
end
结果:

match =

     2     1     0     0
     1     0     1     0
这样你就有了一个复杂的#wordsA+#wordsB+#singleWordsA而不是#wordsA*#wordsB

编辑:或者,如果您不喜欢
映射
,可以按字母顺序向量保存单词出现向量。然后可以同时检查两个向量来查找匹配项:

(假设我们使用的结构中,
w
属性是单词字符串,
occ
是出现向量)

i=1;j=1;

然而(我知道你是不是在用@Amro的解决方案计时?它的时钟似乎是一样的,即使有一个更大的数据集
match =

     2     1     0     0
     1     0     1     0
i = 1; j = 1;
while(i<=size(wordsA,2) && i<=size(wordsB,2))
if(strcmp(wordsA(i).w, wordsB(j).w))
    % update match
else
    if(before(wordsA(i).w, wordsA(i).w)) % before: fancy function returning 1 if the first argument comes (alphabetically) before the second one (no builtin function comes to my mind)
        i = i+1;
    else
        j = j+1;
    end
end