如何根据第一个条目中的值从矩阵中提取行?

时间:2011-09-21 21:47:54

标签: wolfram-mathematica

这是Mathematica中另一个简单的“矩阵”问题。我想说明我是如何做到的,并询问是否有更好的答案。

我想根据第一列中的值(或任何列,我在这里使用第一列作为示例)从矩阵中选择所有'行'。

比如说,在这个例子中找到第一个位置的条目< = 4的所有行:

    list = {{1, 2, 3},
           {4, 5, 8},
           {7 , 8, 9}}

所以,结果应该是

            {{1,2,3},
             {4,5,8}}

嗯,问题是我需要使用Position,因为Position返回的结果可以直接由Extract使用。 (但不能被Part或[[]]使用,所以这就是为什么我只是看着Position [])。

但我不知道怎么告诉Position请将'搜索'模式限制为只有'第一列'所以我可以在一行中完成。

当我输入

pos = Position[list, _?(# <= 4 &)]

返回&lt; = 4的所有条目的位置。

{{1, 1}, {1, 2}, {1, 3}, {2, 1}}

如果我第一次获得第一列,则在其上应用“位置”,它可以使用

  list = {{1, 2, 3},
          {4, 5, 8},
          {7 , 8, 9}};
   pos = Position[list[[All, 1]], _?(# <= 4 &)]
   Extract[list, pos]
   -->       {{1, 2, 3}, {4, 5, 8}}

我也尝试过这个:

pos = Position[list, _?(# <= 4 &)];
pos = Select[pos, #[[2]] == 1 &]  (*only look at ones in the 'first' column*)

{{1, 1}, {2, 1}}---> 

这给了我第一栏中的正确位置。要使用它来查找所有行,我做了

pos = pos[[All, 1]] (* to get list of row positions*)
---> {1, 2}

list[[ pos[[1]] ;; pos[[-1]], All]]
{{1, 2, 3}, 
 {4, 5, 8}}

所以,要总结,把它们放在一起,这就是我所做的:

方法1

 list = {{1, 2, 3},
         {4, 5, 8},
         {7 , 8, 9}};
 pos = Position[list[[All, 1]], _?(# <= 4 &)]
 Extract[list, pos]
  -->       {{1, 2, 3}, {4, 5, 8}}

方法2

list = {{1, 2, 3},
      {4, 5, 8},
      {7 , 8, 9}}

pos = Position[list, _?(# <= 4 &)];
pos = Select[pos, #[[2]] == 1 &];
pos = pos[[All, 1]];
list[[ pos[[1]] ;; pos[[-1]], All]]

{{1, 2, 3}, 
{4, 5, 8}}

 The above clearly is not too good. 

方法1是否采用“正确”的功能方式?

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

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

EDU>> A( A(:,1)<=4 , :)

     1     2     3
     4     5     8

我正在尝试改进我在Mathematica命令中使用矩阵的“功能”处理,这是一个我觉得我不擅长使用列表的领域。我发现使用矩阵更容易。

问题是:Mathematica中是否有更短/更实用的方法?

感谢

5 个答案:

答案 0 :(得分:7)

您可以按如下方式使用Pick[]

Pick[list, list[[All, 1]], _?(# <= 4 &)]

答案 1 :(得分:5)

以下情况如何?

In[1]:= list = {{1, 2, 3}, {4, 5, 8}, {7, 8, 9}};

In[2]:= Select[list, First[#] <= 4 &]

Out[2]= {{1, 2, 3}, {4, 5, 8}}

这是matlab代码的简单翻译:

list[[Flatten[Position[Thread[list[[All, 1]] <= 4], True]]]]

(当然,如果我使用Flatten代替Extract),则不需要Part

答案 2 :(得分:4)

使用SparseArray的方法比已经提出的方法更快。它是:

list ~Extract~
  SparseArray[UnitStep[4 - list[[All, 1]]]]["NonzeroPositions"]

以下是与其他方法的速度比较。我不得不修改WReach的方法来处理其他位置规范。

f1[list_, x_] := Cases[list, {Sequence @@ Table[_, {x - 1}], n_, ___} /; n <= 4]
f2[list_, x_] := Select[list, #[[x]] <= 4 &]
f3[list_, x_] := Pick[list, (#[[x]] <= 4 &) /@ list]
f4[list_, x_] := Pick[list, UnitStep[4 - list[[All, x]]], 1]
f5[list_, x_] := Pick[list, Thread[list[[All, x]] <= 4]]
f6[list_, x_] := list ~Extract~
                   SparseArray[UnitStep[4 - list[[All, x]]]]["NonzeroPositions"]

对于包含少量行和多列的表(比较位置7):

a = RandomInteger[99, {250, 150000}];
timeAvg[#[a, 7]] & /@ {f1, f2, f3, f4, f5, f6} // Column
0.02248
0.0262
0.312
0.312
0.2808
0.0009728

对于列数较少且行数较多的表(比较位置7):

a = RandomInteger[99, {150000, 12}];
timeAvg[#[a, 7]] & /@ {f1, f2, f3, f4, f5, f6} // Column
0.0968
0.1434
0.184
0.0474
0.103
0.002872

答案 3 :(得分:3)

如果您想要符合条件的行,请使用Cases

Cases[list, {n_, __} /; n <= 4]

(* {{1, 2, 3}, {4, 5, 8}} *)

如果您想要列表中的位置而不是行本身,请使用Position代替Cases(仅限于第一级):

Position[list, {n_, __} /; n <= 4, {1}]

(* {{1}, {2}} *)

答案 4 :(得分:2)

如果你想变得非常聪明:

Pick[list, UnitStep[4 - list[[All, 1]]], 1]

这也避免了解压缩,这意味着它会更快并且使用更少的内存。