【问题标题】:MATLAB: ismember vs isequalMATLAB:ismember vs isequal
【发布时间】:2014-02-27 17:49:10
【问题描述】:

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

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

上面的行计算为table(或dataset,取决于A 的类),由A 的行组成,这些行与B 中指定的列处的B 的某些行匹配@。

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

可以这样做:

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

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

如果能写的话语义上会更清晰

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

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

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

【问题讨论】:

  • 正如@MrAzzaman 下面的回答所暗示的,如果您想索引A 的行,您需要eq (==),而不是isequal。这些不是等价的。不幸的是,eq 没有为表类型编写(可能与cellstruct 等不支持它的原因相同)。如果这些看起来笨拙,您可以考虑为自己制作一组实用函数来简化您需要编写的代码。

标签: matlab matlab-table


【解决方案1】:

对于table data type,您也可以使用innerjoin,但在这种情况下ismember 相当清楚。考虑tables 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 的第二个输出参数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

【讨论】:

    【解决方案2】:

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

    【讨论】:

    • 仅供参考,bsxfuneq 不幸的是没有为 table 数据类型定义,因此如果不转换为另一种格式,您的代码 sn-ps 都不会工作(这并不总是可能的)。
    • table 是一个新的 MATLAB 命令吗?我仍在运行 R2012a,但它对我来说似乎不存在。
    • 我认为是new as of R2013b。我以为有以前的东西,但我找不到。统计工具箱中有dataset,即supposed to be similar
    • Tables 似乎也为聚会带来了rowfun(),这是这种方法在语义上更加清晰的版本
    • @Notlikethat:很好的发现!还有varfun。所有table 方法/属性都列在here
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-11
    • 2021-12-10
    • 1970-01-01
    • 1970-01-01
    • 2014-04-17
    • 2018-10-12
    相关资源
    最近更新 更多