如何从矩阵中选择具有特定列中唯一条目的行?

时间:2011-08-31 09:17:42

标签: wolfram-mathematica

我尝试使用功能方式解决这个问题,但我没有取得多大成功。

假设有一个列表列表,并且只需要选择其中具有特定位置唯一条目的列表。

例如,假设有一个矩阵,我们只想选择第一列中具有唯一元素的行。

以下是一个例子:

INPUT:

list= {{ 1,2}, {1,3},{4,5}}

我希望输出为

list={{1,2},{4,5}}

删除哪个“行”并不重要,第一个是好的,但任何一个都没问题。

我尝试过Select,DeleteCases,DeleteDuplicates,Union等等,但是无法让它工作。我不知道如何告诉Mathematica只寻找'独特'元素。联盟接近但它完整列表。即我不知道为标准写什么,如

DeleteDuplicates[list, <now what?> ]

作为参考,这就是我在Matlab中执行上述操作的方法:

EDU>> A=[1 2;1 3;4 5]

A =
     1     2
     1     3
     4     5

EDU>> [B,I,J]=unique(A(:,1));
EDU>> A(I,:)

ans =
     1     3
     4     5

感谢

2 个答案:

答案 0 :(得分:8)

这是一种方式:

DeleteDuplicates[list, First@#1 === First@#2 &]

编辑

请注意,下面的时间安排和讨论基于M7

经过反思,我找到了一个解决方案,对于大型列表来说(至少)数量级会快一些,对于这种特殊情况,有时会快两个数量级(可能,更好的方法就是下面的解决方案将具有不同的计算复杂度):

Clear[delDupBy];
delDupBy[nested_List, n_Integer] :=
  Module[{parts = nested[[All, n]], ord, unpos},
    ord = Ordering[parts];
    unpos = Most@Accumulate@Prepend[Map[Length, Split@parts[[ord]]], 1];
    nested[[Sort@ord[[unpos]]]]];

基准:

In[406]:= 
largeList = RandomInteger[{1,15},{50000,2}];

In[407]:= delDupBy[largeList,1]//Timing
Out[407]= {0.016,{{13,4},{12,1},{1,6},{6,13},{10,12},{7,15},{8,14},
            {14,4},{4,1},{11,9},{5,11},{15,4},{2,7},{3,2},{9,12}}}

In[408]:= DeleteDuplicates[largeList,First@#1===First@#2&]//Timing
Out[408]= {1.265,{{13,4},{12,1},{1,6},{6,13},{10,12},{7,15},{8,14},{14,4},
      {4,1},{11,9},{5,11},{15,4},{2,7},{3,2},{9,12}}}

这一点尤为引人注目,因为DeleteDuplicates是一个内置函数。我可以盲目猜测,DeleteDuplicates用户定义的测试使用二次时成对比较算法,而delDupByn*log n列表的大小。

我认为这是一个重要的教训:在使用自定义测试时,应该注意内置函数,例如UnionSortDeleteDuplicates等。我在this Mathgroup主题中更广泛地讨论了它,其中还有其他有见地的回复。

最后,让我提一下,在here之前,已经提出了这个问题(强调效率)。我将在这里重现一个解决方案,当第一个(或通常是n - th)元素是正整数时,我给出了一个解决方案(推广到任意整数很简单)。:

Clear[sparseArrayElements];
sparseArrayElements[HoldPattern[SparseArray[u___]]] := {u}[[4, 3]]

Clear[deleteDuplicatesBy];
Options[deleteDuplicatesBy] = {Ordered -> True, Threshold -> 1000000};
deleteDuplicatesBy[data_List, n_Integer, opts___?OptionQ] := 
  Module[{fdata = data[[All, n]], parr, 
  rlen = Range[Length[data], 1, -1], 
  preserveOrder =  Ordered /. Flatten[{opts}] /. Options[deleteDuplicatesBy], 
  threshold =  Threshold /. Flatten[{opts}] /. Options[deleteDuplicatesBy], dim},
  dim = Max[fdata];
  parr = If[dim < threshold, Table[0, {dim}], SparseArray[{}, dim, 0]];
  parr[[fdata[[rlen]]]] = rlen;
  parr = sparseArrayElements@If[dim < threshold, SparseArray@parr, parr];
  data[[If[preserveOrder, Sort@parr, parr]]]
];

这种方法的工作方式是使用第一个(或通常是n - 个)元素作为某些位置 我们预先分配的巨大表,利用它们是正整数)。在某些情况下,这个可以给我们疯狂的表现。观察:

In[423]:= hugeList = RandomInteger[{1,1000},{500000,2}];

In[424]:= delDupBy[hugeList,1]//Short//Timing
Out[424]= {0.219,{{153,549},{887,328},{731,825},<<994>>,{986,150},{92,581},{988,147}}}

In[430]:= deleteDuplicatesBy[hugeList,1]//Short//Timing
Out[430]= {0.032,{{153,549},{887,328},{731,825},<<994>>,{986,150},{92,581},{988,147}}}

答案 1 :(得分:0)

列昂尼德提供了一个长期而彻底的答案,就像他经常做的那样。但是,我认为值得指出的是,可以采用以下方式提供一种有效而简洁的解决方案:

First /@ GatherBy[hugeList, #[[1]] &]

其中1是要比较的列索引。

在我的系统上,这比delDupBy快,但不如deleteDuplicatesBy快。