Message Boards Message Boards

[✓] Pick columns or rows of a matrix?

GROUPS:

I work with random matrices made of 0 and 1. Once generated, I want to remove the columns that contains only zero's. I can easily identify these columns (as a list), and I can remove one column at a time. How to do it in one operation ? Here is how the nb starts:

m = 100; n = 10

A = RandomInteger[1, {m, n}]

Position [A, Table[0, n]] 

...

An alternative would be to exclude from the start columns with only zero's.

Thanks for suggestions. Pierre Dehez, University of Louvain, Louvain-la-Neuve

POSTED BY: Pierre Dehez
Answer
1 month ago

You can do the detection and removal at once:

m = 100; n = 4
A = RandomInteger[1, {m, n}]
Count[A, {0, 0, 0, 0}]
A = A /. {0..} :> Nothing
Count[A, {0, 0, 0, 0}]

Basically, it replaces rows that are made up of only repetitions of 0 with Nothing (if you have an older version substitute Nothing with Sequence[])

POSTED BY: Sander Huisman
Answer
1 month ago

Thanks! Elegant. Pierre

POSTED BY: Pierre Dehez
Answer
1 month ago

You could also use:

m = 100; n = 4
A = RandomInteger[1, {m, n}]
Position[A, Table[0, n]]
Delete[A, %]

Delete can accept multiple 'deletions' at the same time…

POSTED BY: Sander Huisman
Answer
1 month ago

Even simpler, thanks! I had overlooked the Delete command.

POSTED BY: Pierre Dehez
Answer
1 month ago

The function DeleteCases could be used. Create a matrix where 0 is twice as likely to occur as 1:

In[1]:= matrix = RandomChoice[{50, 25} -> {0, 1}, {20, 3}]

Out[1]= {{1, 0, 0}, {0, 0, 0}, {0, 0, 1}, {1, 1, 1}, {0, 0, 0}, 
{1, 0, 0}, {1, 0, 1}, {0, 0, 1}, {0, 0, 0}, {0, 0, 0}, 
{0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 1, 0}, {0, 0, 1}, 
{0, 1, 1}, {1, 0, 0}, {1, 1, 0}, {1, 0, 0}, {0, 1, 0}}

In[2]:= Length@matrix

Out[2]= 20

Then DeleteCases could remove the rows that does not have at least one nonzero element:

In[3]:= matrixCleanedOfAllZeroRows = DeleteCases[matrix, {0 ..}]

Out[3]= {{1, 0, 0}, {0, 0, 1}, {1, 1, 1}, {1, 0, 0}, {1, 0, 1}, 
{0, 0,1}, {0, 1, 0}, {0, 0, 1}, {0, 1, 1}, {1, 0, 0}, 
{1, 1, 0}, {1, 0,  0}, {0, 1, 0}}

In[4]:= Length@matrixCleanedOfAllZeroRows

Out[4]= 13
POSTED BY: Hans Milton
Answer
1 month ago

Great also because you suggest a way to produce matrices with few 1's, what I needed.

POSTED BY: Pierre Dehez
Answer
1 month ago

To sum up, there are at least a dozen ways of doing it, and you can come up with a couple dozen more if one wants…

Select[A, Positive@*Total]
Select[A, AnyTrue@Positive] 
Select[A, Not@*AllTrue[PossibleZeroQ]] 
A /. {0 ..} :> Nothing 
A /. {0 ..} :> Sequence[] 
Delete[A, Position[A, Table[0, n]]] 
Delete[A, Position[A, {0 ..}]] 
DeleteCases[A, {0 ..}] 
Cases[A, Except[{0 ..}]] 
Select[A, MemberQ[1]] 
Pick[A, Positive@*Total /@ A, True] 
Pick[A, NoneTrue[Positive] /@ A, False] 
Reap[Scan[If[MemberQ[#, 1], Sow[#]] &, A]][[2, 1]]
Reap[If[MemberQ[#, 1], Sow[#]] & /@ A][[2, 1]]

good luck studying them…

POSTED BY: Sander Huisman
Answer
1 month ago

I knew that there would be several ways... but not that many. Yet I vote for DeleteCases, most direct. Thanks!

POSTED BY: Pierre Dehez
Answer
1 month ago

One way to find which columns in a 0/1 matrix mat are zero vectors is to examine Total[mat], which gives the number of ones in each column, or Unitize[Total[mat]], which will be a 0/1 list in which a 0 means the corresponding column is all zeros.

If the matrix is mostly zeros, then using SparseArray is worth considering. Here is an example with a random number of ones (5 in the example shown).

nn = 10;
ones = RandomInteger[{1, 2 nn}];  (* a random number of ones *)
mat = SparseArray[RandomInteger[{1, nn}, {ones, 2}] -> 1, {nn, nn}];

mat // MatrixForm 

enter image description here

The following shows which columns have a one and which no ones at all:

TableForm[
 Unitize@Total@mat,
 TableHeadings -> Automatic, TableDirections -> Row
 ]

enter image description here

SparseArray has a built-in method that picks the columns indices of the nonzero entries. They do not necessarily come ordered and there may be repeated indices. We can sort and remove the duplicates with Union. Compare the indices below with the positions of 1 in the table above:

Union @@ mat["ColumnIndices"]
(*  {2, 3, 5, 9, 10}  *)

We can use these indices to get the columns with at least one 1 with Part and All:

newmat = mat[[All, Union @@ mat["ColumnIndices"]]];
newmat // MatrixForm

enter image description here

POSTED BY: Michael Rogers
Answer
1 month ago

Group Abstract Group Abstract