MATLAB:ismember vs isequal

时间:2014-02-04 00:53:46

标签: matlab matlab-table

如果AB是具有相同列(并且顺序相同)的表(或数据集),那么像ismember(A(:, somecols), B(:, somecols))这样的表达式将生成一个适合的布尔数组用于索引A,如

A(ismember(A(:, somecols), B(:, somecols)), :)

上面的一行评估为table(或dataset,具体取决于A的类),其中A行与B的某一行匹配1}}在somecols

中指定的列

但现在假设B只有一行。更现实的是,假设从A中选择行的标准只是匹配 B的这一行,比如第一行。

可以这样做:

A(ismember(A(:, somecols), B(1, somecols)), :)

我对此的主要狡辩是它不是“语义清晰”,因为实际上使用ismember来测试相等性。

如果可以写

,那将在语义上更清晰
A(isequal(A(:, somecols), B(1, somecols)), :)

但这确实不会产生预期的效果。 (具体而言,即使A(:, ...)包含与B(1, ...)匹配的行,也不返回任何匹配项。)

我的问题是,什么是正确生成与问题相对应的逻辑向量的谓词“A这一行匹配 参考行somecols” ?

2 个答案:

答案 0 :(得分:3)

对于table data type,您也可以使用innerjoin,但ismember在这种情况下非常明确。考虑table s AtBt,其中Bt有两个常见行和一个唯一行:

>> A = randi(7,4,5);
>> commonRows = [1 3];
>> B = [A(commonRows,:); randi(2,1,5)+7];
>> At = array2table(A,'VariableNames',sprintfc('C%d',1:size(A,2)))
At = 
    C1    C2    C3    C4    C5
    __    __    __    __    __
    4     1     5     7     7 
    2     6     5     1     4 
    4     4     6     7     4 
    2     7     7     5     6 
>> Bt = array2table(B,'VariableNames',sprintfc('C%d',1:size(A,2)))
Bt = 
    C1    C2    C3    C4    C5
    __    __    __    __    __
    4     1     5     7     7 
    4     4     6     7     4 
    8     8     9     9     9 

innerjoin的第二个输出参数IAA中的B中的行提供了索引。如您的示例所示,请考虑由somecols指定的列的子集:

>> somecols = [2 5]
somecols =
     2     5
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(1,somecols))
Ct = 
    C2    C5
    __    __
    1     7 
IA =
     1
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(2,somecols))
Ct = 
    C2    C5
    __    __
    4     4 
IA =
     3
>> [Ct,IA] = innerjoin(At(:,somecols), Bt(3,somecols))
Ct = 
   empty 0-by-2 table
IA =
     []

如果IA为空(或不是)是合适的测试:

>> [~,IA] = innerjoin(At, Bt(3,:));
>> isempty(IA)
ans =
     1
>> [~,IA] = innerjoin(At, Bt(2,:));
>> isempty(IA)
ans =
     0

或者只测试第一个输出,即公共表行:

>> isempty(innerjoin(At, Bt(3,:)))
ans =
     1
>> isempty(innerjoin(At, Bt(1,:)))
ans =
     0

答案 1 :(得分:1)

我同意使用ismember选项可能无法立即明确您的意图(尽管它没有任何问题)。你可以做的另一种方法,我猜可能在语义上更清晰(虽然可能效率较低)是使用bsxfun,如下所示:

all(bsxfun(@eq,A(:,somecols),B(1,somecols)),2);

如果你要将其扩展到本质上正在发生的事情,那就像是:

a = A(:,somecols);
b = repmat(B(1,somecols),size(A,1),1);
abeq = all(a == b,2);
A(abeq,:);

基本上,您正在复制一个B行,使其与A(:,somecols)的大小相同,然后比较每个数组中的每个值。最后,您要检查哪一行有true整行(使用all),这表示它与B的单行匹配。

编辑:对不起,显然我误解了这个问题 - 如果你使用的是table数据类型(几分钟前我实际上并不知道 - 感谢horchler),那么这种方法可能会胜出'工作。

EDIT2:Notlikethat指出函数rowfun的存在,它作用于表中的每一行。我无法测试这个(我的MATLAB版本不够新)但我认为像这样的东西会做你想要的:

A(rowfun(@(x) isequal(B(1,somecols),x),A(:,somecols)),:);