MATLAB: ismember vs isequal



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

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

上面的行计算为一个table(或dataset,取决于A的类),由那些与somecols中指定的列中的某行BA行匹配的行组成。

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

可以这样做:

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

我对此的主要争论是它不是"语义清楚的",因为ismember实际上被用来测试平等性。

如果能写,语义会更清晰

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

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

我的问题是,正确生成与问题"这行A是否与somecols处的引用行匹配"相对应的逻辑向量的谓词是什么?

对于table数据类型,您也可以使用innerjoin,但在这种情况下ismember相当清楚。考虑tableAtBt,其中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的第二个输出参数IA给出了A中行的索引,这些行也在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

我同意使用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)),:);

相关内容

  • 没有找到相关文章

最新更新