# Counting negative values in list

I would like to count the negative values of a list.

My approach was Count[data, -_] which doesn't work.

How can I tell Mathematica to count all numbers with a negative sign?

-

I assume that you have numeric values. A much more efficient way would be

-Total[UnitStep[data] - 1]]

or

Total[1-UnitStep[data]]

Note: While the second notation is certainly a bit more compact, it is about 35% slower than the double-minus notation. I have no idea why. On my system, it takes on average 0.22 sec vs 0.30 sec.

Compare timings between the faster UnitStep version and the pattern matching approach:

data = RandomReal[{-10, 10}, 10^7];

Timing[-Total[UnitStep[data] - 1]]
(* ==> {0.222, 5001715} *)

Timing[Count[data, _?Negative]]
(* ==> {6.734, 5001715} *)
-
Total[1 - UnitStep[data]] is more compact, no? –  Guess who it is. Aug 20 '12 at 13:28
@J.M. Clever!!! I will edit according to your comment. However, it seams to make the code slightly slower. Any idea why? –  Thomas Aug 20 '12 at 13:29
I get the same timings on my machine. Did you notice that it turns around for shorter data? (Try 100 or so.) –  sebhofer Aug 20 '12 at 18:02
The faster version does two negations but both applied to numbers, while the slow version negates a whole list –  Rojo Aug 21 '12 at 3:51

I've found the fastest way to do this sort of thing is to use a very simple procedural Do loop compiled to C.

f2 = Compile[{{numbers, _Real, 1}},
Block[{count = 0}, Do[If[number < 0., count++], {number, numbers}];
count], CompilationTarget -> "C", "RuntimeOptions" -> "Speed"]
-

Lots of nice answers. Here's another, but I'm afraid it's quite slow.

Total[Select[data, # < 0 &]]

Though this totals all the negative numbers. To count them you could do:

-Total[Sign[Select[data, # < 0 &]]]

Then I got to thinking, "how would I program this in Matlab?"

Total[1 - Sign[data]]/2
-
For the last one, this would be significantly faster: (Length[data] - Total[Sign[data]])/2, for the same reasons Rojo stated in Thomas' answer. –  ecoxlinux Aug 22 '12 at 17:27
good point -- thanks –  bill s Aug 23 '12 at 3:55

This seems competitive in terms of speed:

Total@Clip[list, {0, 0}, {1, 0}]

Testing:

SetAttributes[timeAvg, HoldFirst]
\$HistoryLength = 0;
timeAvg[func_] :=
Do[If[# > 0.3, Return[#/5^i]] & @@ Timing@Do[func, {5^i}], {i, 0, 15}]
neg = Length@# - Tr@UnitStep@# &;
list = RandomReal[1*^7 {-1, 1}, 1*^7];

Total@Clip[list, {0, 0}, {1, 0}] // timeAvg
-Total[UnitStep[list] - 1] // timeAvg
Length[list] - Total[UnitStep[list]] // timeAvg
neg@list // timeAvg

(* 0.1594, 0.375, 0.1812, 0.197 *)
-
Interesting, although in my machine this new one is still significantly slower than the last two. –  ecoxlinux Aug 22 '12 at 17:37

For numeric values, the following:

Length[data] - Total[UnitStep[data]]

is 50% faster than Thomas' solution.

Update: An even faster approach will be to compile to C, as shown in the following function f:

ClearAll[f];
f = Compile[{{vector, _Real, 1}, {bound, _Real}},
Module[{t = 0, i = 1, len = Length[vector]},
For[i = 1, i <= len, i++, t += Boole[vector[[i]] < bound]]; t],
CompilationTarget -> "C", "RuntimeOptions" -> "Speed"]

Using the timeAvg function, as defined in Mr. Wizard's answer, we have:

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

data = RandomReal[{-10, 10}, 10^7];

{-Total[UnitStep[data] - 1] // timeAvg,
Length[data] - Total[UnitStep[data]] // timeAvg,
Length[data] - Tr[UnitStep[data]] // timeAvg,
f[data, 0.] // timeAvg}

(* ==> {0.105993, 0.0431972, 0.0422639, 0.0141324} *)

Note that the function f defined above will work for any upper bound, and not just 0. And would be significantly faster (at least in my machine) than the corresponding Length[data]- Tr[UnitStep[data - bound]] approach when bound is not zero.

For the dangers with the use of "RuntimeOptions"->"Speed", see the Mathematica help: RuntimeOptions.

-

Use _?Negative:

list = RandomInteger[{-9, 9}, 30]

Count[list, _?Negative]

Your pattern will match an object with an explicit negative sign:

Count[{a, -b, c, a, -a, a, -b}, -_]

3

You could combine the patterns to match either:

Count[{-1, -2, 3, 4, -a, b, -c}, -_ | _?Negative]

4

Since this has become a speed competition (which is fine by me), rather than the beginner's question I took it to be, here is my own variation, using Tr for fast packed array summing:

neg = Length@# - Tr@UnitStep@# &;

Timings:

SetAttributes[timeAvg, HoldFirst]

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

list = RandomInteger[1*^7 {-1, 1}, 1*^8];

-Total[UnitStep[list] - 1] // timeAvg

Length[list] - Total[UnitStep[list]] // timeAvg

neg @ list // timeAvg

0.592

0.234

0.1278

-
Perhaps you should mention that the latter solution only works for variables with an added minus, not for values. –  Sjoerd C. de Vries Aug 20 '12 at 11:49
Okay, so expanding on this question, are the easiest ways to find all values in the list less than, say, 5 Length[list] - Total[UnitStep[list - 5]] using the UnitStep method? Or is there another pattern match to use? –  kale Aug 21 '12 at 1:47
@kalewallace pattern matching methods are easier, more declarative and more general, but when everything is numeric, the other methods are way faster. Count[list, i_/;i<5] –  Rojo Aug 21 '12 at 3:54
@kalewallace you may find this answer of interest. But, as Rojo states there is a trade-off, with patterns being more general and often conceptually simpler, while numeric approaches are usually faster given the right data (packed arrays of machine size reals or integers). –  Mr.Wizard Aug 21 '12 at 9:03
@Anastasiia your comment: "this doesn't work if one wants to count complex numbers" doesn't make much sense as complex numbers are not simply positive or negative. Perhaps you just want Count[dat, _Complex] to count all complex numbers in dat, or Count[cr, _?(Im@# > 0 &)] to count all numbers with an imaginary part greater than zero? –  Mr.Wizard Sep 19 '12 at 15:24