4
$\begingroup$

I have a 150 by 300 binary matrix. I would like to find the total amount of zeros in the matrix. I've been consulting online documentation for support, but am unable to use the "count" function properly (I only see how to apply it to a list). Perhaps there is also a better way to do this than using count. When providing a solution, I'd appreciate if you can state what the code is doing, so I can better understand. For the sake of simplicity, I will paste a smaller matrix (5 by 10), but the one I will be applying it to will be 150 by 300. Thanks in advance for your time.

binarym = ({
{1, 1, 1, 0, 0, 0, 0, 0, 1, 1},
{1, 1, 1, 1, 0, 0, 0, 1, 1, 1},
{1, 1, 0, 0, 0, 0, 1, 1, 1, 1},
{1, 1, 1, 1, 0, 0, 0, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0, 1, 1}})
$\endgroup$
  • $\begingroup$ In case of your matrix, Plus@@Flatten[binarym] should work. There may be faster ways using Trace or similar. Please note that your outer round parentheses do not actually do anything. $\endgroup$ – Yves Klett Jan 2 '18 at 3:12
  • 3
    $\begingroup$ Count can take a level specification (say 2, for a matrix): Count[binarym, 0, 2], while something like Total[1 - binarym, 2] might be faster in some cases. $\endgroup$ – ilian Jan 2 '18 at 3:12
  • 1
    $\begingroup$ Select all the zeros and then find out how many of them there are: Length@Select[Flatten[binarym], # == 0 &] This gives 17, which is the expected answer. $\endgroup$ – bill s Jan 2 '18 at 3:14
  • $\begingroup$ Times @@ Dimensions[binarym] - Total@Flatten@binarym $\endgroup$ – Bob Hanlon Jan 2 '18 at 3:25
  • $\begingroup$ Closely related: (9637), (38624), (157222). Possibly of interest: (19357) $\endgroup$ – Mr.Wizard Jan 3 '18 at 16:54
14
$\begingroup$
ClearAll[countZ]
countZ = 1 ## & @@ Dimensions @ # - Total[#, 2] &;
countZ@binarym

17

Timings:

SeedRandom[1]
binm = RandomInteger[{0, 1}, {10000, 10000}];

countZ @ binm // AbsoluteTiming

{0.23863, 49996224}

Wavelets`CountZeros@binm // AbsoluteTiming

{0.520381, 49996224}

(Length @ # - Total @ #) & @ Flatten @ binm // AbsoluteTiming (* Okkes Dulgerci *)

{1.02773, 49996224}

Tr[Flatten@binm] // AbsoluteTiming (* Yves Klett comment *)

{1.06958, 50003776}

Total[1 - binm, 2] // AbsoluteTiming (* illan comment *)

{2.1557, 49996224}

Count[binm, 0, 2] // AbsoluteTiming  (* eyeorbl *)

{6.14531, 49996224}

Times @@ Dimensions[binm] - Total@Flatten@binm // AbsoluteTiming (* Bob Hanlon  comment*)

{9.2004324, 49996224}

Plus @@ Flatten[binm] // AbsoluteTiming (* Yves Klett comment *)

{19.32956, 50003776}

Length @ DeleteCases[Flatten @ binm, 0] // AbsoluteTiming

{25.07808, 50003776}

Length @ Select[Flatten[binm], # == 0 &] // AbsoluteTiming  (* bill s *)

{54.19553, 49996224}

$\endgroup$
  • $\begingroup$ 1## & (for Times) from @Mr.Wizard somewhere on this site. $\endgroup$ – kglr Jan 2 '18 at 5:54
  • 2
    $\begingroup$ Slightly tangential, but if binm is given as a SparseArray then I get almost an order of magnitude speed up for countZ. $\endgroup$ – aardvark2012 Jan 2 '18 at 10:11
  • 2
    $\begingroup$ @aardvark2012 First, I was somewhat surprised but did you count in the conversion into a SparseArray? But thinking of it, I recalled that the constructor for sparse arrays has to count the nonzero values. So if you don't count in the construction time, then Times @@ Dimensions[binm] - Length[binm["NonzeroValues"] returns the result for arbitrary large SparseArrays that fit into memory. $\endgroup$ – Henrik Schumacher Jan 2 '18 at 16:25
  • $\begingroup$ This 1 ## & @@ in the code is really cool +1! $\endgroup$ – mgamer Jan 2 '18 at 18:31
  • $\begingroup$ @HenrikSchumacher No, I didn't count the conversion time (which is bad). I was thinking more that if the original binarym could be constructed as a SparseArray from the outset with no additional cost then it could be well worth it. OP didn't mention how the array was built, so that may not be possible (which is why my comment is "tangential"). I forgot about NonzeroValues, though, which would be a pretty awesome way to do this, if the OP could get it as a SparseArray. $\endgroup$ – aardvark2012 Jan 2 '18 at 22:17
4
$\begingroup$
Count[binarym, 0, 2]

Set the levelspec to 2 because you are interested in the 0s in the lists nested within the outer list.

There's a number of other ways to do this too:

(* Flatten it first *)
Count[Flatten[binarym], 0]

(* Find all of the zeros and then count how many there were *)
Length[Position[binarym, 0]]

(* Count the number of 0s in each row using an anonymous function
   and then total them up. *)
Total[Count[#,0]&/@binarym]

And several others, which have already been mentioned in the comments to your question. Unless you have very strict performance requirements, any of these should work on a 150 by 350 matrix.

$\endgroup$
4
$\begingroup$
(Length@# - Total@#) &@Flatten@binarym
$\endgroup$
2
$\begingroup$

Select all the zeros and then find out how many of them there are:

Length@Select[Flatten[binarym], # == 0 &] 

This gives 17, which is the expected answer.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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