20
$\begingroup$

The built-in function "Drop" can delete a Matrix's row and column. Typical syntax for "Drop" is as follows:

Drop[list,seq1,seq2...]

But what if I want to drop a matrix in a way that the indices of the columns to be deleted is not a well ordered sequence?

For example the matrix is 10x10, And I want to drop 3,4,7,9 rows and columns in a single time, then how to do it quickly?

$\endgroup$
6
  • 2
    $\begingroup$ Try matrix[[All, Complement[Range[10], {3, 4, 7, 9}]]] $\endgroup$
    – Silvia
    Feb 26, 2013 at 6:42
  • $\begingroup$ @Mr.Wizard Will a one-line answer OK? I mean I'm right now in a condition not able to type too many words.. $\endgroup$
    – Silvia
    Feb 26, 2013 at 6:52
  • $\begingroup$ @Mr.Wizard +1. Much better than just one line :) $\endgroup$
    – Silvia
    Feb 26, 2013 at 6:54
  • $\begingroup$ @Silvia In the future go ahead and post the one line answer, if it does in fact answer the question. Sometimes I'll flesh out such answers when I see them; I would have in this case. $\endgroup$
    – Mr.Wizard
    Feb 26, 2013 at 6:56
  • $\begingroup$ @Mr.Wizard Got it. Sometimes there will be very interesting answers to those at-first-sight basic questions, so I liked to put simple direct answer in comments. $\endgroup$
    – Silvia
    Feb 26, 2013 at 7:03

2 Answers 2

23
$\begingroup$

I'm sure this question is a duplicate but I cannot find it; I think it may only be duplicated on StackOverflow (I know one duplicate is there).

Basic idea

A key statement in your question is:

I want to drop 3,4,7,9 rows and columns in a single time, then how to do it quickly?

I believe this calls for Part which can extract (and by inverse, drop) rows and columns at the same time. You must extract the parts you don't want to drop so use Complement.

m = Partition[Range@100, 10];

ranges = Complement[Range@#, {3, 4, 7, 9}] & /@ Dimensions[m]

new = m[[##]] & @@ ranges;

new // MatrixForm

Mathematica graphics

As a self-contained function

This is written to handle arrays of arbitrary depth.

drop[m_, parts__List] /; Length@{parts} <= ArrayDepth[m] :=
 m[[##]] & @@ MapThread[Complement, {Range @ Dimensions[m, Length @ {parts}], {parts}}]

drop[m, {3, 4, 7, 9}, {4, 5, 6}] // MatrixForm

Mathematica graphics


Timings

user asked how to test the performance of the solutions presented. Here is a very basic series of tests that one might start with. First a custom timing function based on code from Timo:

SetAttributes[timeAvg, HoldFirst]
timeAvg[func_] := Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]

Then the functions to test:

dropCarlos[m_, rows_, cols_] /; ArrayDepth[m] > 1 :=
 Delete[Delete[m, List /@ rows]\[Transpose], List /@ cols]\[Transpose]

(* copy drop from above *)

Then a test function with three parameters. (The parameters are the number of randomly selected rows and columns to drop and dimensions of the array.)

test[n_, r_, c_] :=
 With[{
    a = RandomReal[9, {r, c}],
    rows = RandomSample[Range@r, n],
    cols = RandomSample[Range@c, n]
    },
  {#, timeAvg @ #[a, rows, cols]} & /@ {dropCarlos, drop}
 ] // TableForm

We can now probe a few shapes and sizes of data. (Another option would be plotting these tests but that's best left to a separate question if there is interest.)

test[5, 1000, 1000] (* delete only 5 rows and columns from a 1000x1000 array *)
dropCarlos    0.006608
drop          0.001248
test[900, 1000, 1000] (* delete all but 100 rows and columns from a 1000x1000 array *)
dropCarlos    0.00047904
drop          0.00017472
test[50, 10000, 100] (* delete 50 from a very tall array *)
dropCarlos    0.005368
drop          0.001072
test[50, 100, 10000] (* delete 50 from a very wide array *)
dropCarlos    0.002496
drop          0.0008992

These tests cover a variety of cases to see if the relative performance of the functions under test change significantly; if they do a method may have hidden strengths or weaknesses.

A final test that must be included in the suite is using non-packed data (all the test above were with packed arrays). This is because there are often significant internal optimizations for packed arrays that cannot be used on unpacked data. Because of this a function that is fast on packed arrays might become suddenly slow elsewhere. For this test replace the expression RandomReal[9, {r, c}] with RandomChoice["a" ~CharacterRange~ "z", {r, c}] in the definition of test. This creates an array of strings which cannot be packed. Now run another test:

test[250, 1000, 1000]  (* this time with an unpacked String array *)
dropCarlos    0.009232
drop          0.00424

Notice that while my function is still faster it is not as much faster; this is because Part is particularly well optimized for packed arrays.

$\endgroup$
11
  • $\begingroup$ Thank you, Seems very powerful. But I need time to understand those lines with #,@,&.... , I wish I could read these codes just like reading novels... $\endgroup$
    – matheorem
    Feb 26, 2013 at 7:09
  • $\begingroup$ @user15964 I'm happy to explain any part of it you don't understand. I prefer not to make my answers needlessly long (and take the time to do that) unless someone asks for an explanation. A few points: f @ x is the same as f[x]. f /@ {1, 2, 3} creates {f[1], f[2], f[3]}. f @@ {1, 2, 3} creates f[1, 2, 3]. Range has attribute Listable therefore: Range @ {1, 2, 3} creates {{1}, {1, 2}, {1, 2, 3}}. Also look up Slot and SlotSequence in the help. $\endgroup$
    – Mr.Wizard
    Feb 26, 2013 at 7:12
  • $\begingroup$ A question: Carlos gives a rather easy and understandable method to do this using "Delete", but it involves "Transpose". I am intersted about the efficiency of the two method, yours or Carlos'? $\endgroup$
    – matheorem
    Feb 26, 2013 at 7:20
  • $\begingroup$ @user15964 usually the best thing to do it run timings in your own application, which can be assisted by this function. I'll also run a couple of Timing passes and tell you the result. By the way, one difference is that I set up my drop function to extend to arrays of greater depth; doing the same thing with Transpose (manually that is) would end up difficult I believe. $\endgroup$
    – Mr.Wizard
    Feb 26, 2013 at 7:23
  • $\begingroup$ Yeah, yours is more general! I got it. $\endgroup$
    – matheorem
    Feb 26, 2013 at 7:28
9
$\begingroup$

I would use Delete[] for the purpose of deleting selected rows:

Delete[Array[C, {4, 4}], {{2}, {3}}]
(* {{C[1, 1], C[1, 2], C[1, 3], C[1, 4]}, {C[4, 1], C[4, 2], C[4, 3], C[4, 4]}} *)

To delete columns, you could do a preliminary transposition first...

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.