开发者

Efficient way to pick/delete a list of rows/columns in a matrix in Mathematica

This question is in a way a continuation of the question I asked here:Simple way to delete a matrix column in Mathematica to which @belisarius and @Daniel provided very helpful answers.

What I am generally trying to do is to extract from a matrix A specific lines and columns OR what remains after what those specified are removed. So this can be formally writtewn as, find TakeOperator and Drop Operator such that:

TakeOperator[A,{i1,..,开发者_Go百科ip},{j1,...,jq}]=(A[[ik]][[jl]]) (1<=k<=p, 1<=l<=q) =Table[A[[ik]][[jl]],{k,p},{l,q}]

We note Ic={i'1,...,i'p'}=Complement[{1,...,Length[A]},{i1,...,ip}];Jc={j'1,...,j'q'}=Complement[{1,...,Length[A]},{j1,...,jq}];

DropOperator[A,{i1,..,ip},{j1,...,jq}]=(A[[ik]][[jl]]) (1<=k'<=p', 1<=l'<=q') =Table[A[[ik']][[jl']],{k',p'},{l','q}]

While Table as described above does the trick, it is highly inefficient to use Table in that manner.

Just to give an idea, I took @ belisarius example:

In: First@Timing[a = RandomInteger[1000, {5000, 5000}];]

Out:0.218

In:Clear[b,c]

In:First@Timing[
  b = Table[
    If[i < 100, If[j < 100, a[[i]][[j]], a[[i]][[j + 1]]], 
     If[j < 100, a[[i + 1]][[j]], a[[i + 1]][[j + 1]]]], {i, 
     4999}, {j, 4999}]]

Out:140.807

In:First@Timing[c = Drop[a, {100}, {100}]]

Out:0.093

In:c===b

Out:True

Note: With respect to the use of Drop in the earlier post, I thought about using it as well, but when I checked the documentation, there was no suggestion of getting it done the way @belisarius and @daniel suggested. If the documentation could be updated in that direction in future releases, it would be helpful.


Part directly supports lists of indices when slicing arrays. The following definitions exploit that:

takeOperator[a_?MatrixQ, rows_List, cols_List] :=
  a[[rows, cols]]

dropOperator[a_?MatrixQ, rows_List, cols_List] :=
 a[[##]]& @@ complementaryIndices[a, rows, cols]

complementaryIndices[a_?MatrixQ, rows_List, cols_List] :=
  Complement @@@ Transpose @ {Range /@ Dimensions @ a, {rows, cols}}

Example use:

a = RandomInteger[1000, {5000, 5000}];
First @ Timing @ takeOperator[a, Range[1, 5000, 2], Range[1, 5000, 2]]
(* 0.016 *)

First @ Timing @ dropOperator[a, Range[1, 5000, 2], Range[1, 5000, 2]]
(* 0.015 *)


You can also use explicit ranges in a way that is fairly efficient. They may provide some more flexibility. Here is your example.

a = RandomInteger[1000, {5000, 5000}];

Timing[b = Drop[a, {101}, {101}];]

Out[66]= {0.041993, Null}

Timing[
  c = a[[Join[Range[100], Range[102, 5000]], 
   Join[Range[100], Range[102, 5000]]]];]

Out[67]= {0.061991, Null}

c == b

Out[62]= True

I would also suggest use of Span except offhand I do not see how to get it to work in this setting.

Daniel Lichtblau Wolfram Research

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜