I want to check if a data set of size $10^{10}$ contains any non-positive elements. Positive[Name of dataset] returns a list of True and False of length $10^{10}$. I want only a single True if all terms of that dataset are positive and False otherwise.
4 Answers
$\begingroup$ $\endgroup$
4 Alternate solution:
list = RandomReal[1, 10^6]; Min[list] >= 0 - 3$\begingroup$ ...i.e.
NonNegative[Min[list]]. $\endgroup$J. M.'s missing motivation– J. M.'s missing motivation2019-03-27 16:08:29 +00:00Commented Mar 27, 2019 at 16:08 - 3$\begingroup$ Very good solution! This avoids lists of Booleans and hence allows for vectorization. (Boolean arrays cannot be packed.) $\endgroup$Henrik Schumacher– Henrik Schumacher2019-03-27 18:01:28 +00:00Commented Mar 27, 2019 at 18:01
- 2$\begingroup$ This is about 100 times faster than any of the other solutions. Impressive! $\endgroup$Roman– Roman2019-03-27 20:03:52 +00:00Commented Mar 27, 2019 at 20:03
- $\begingroup$ Thank you very much. $\endgroup$a b– a b2019-03-28 08:40:49 +00:00Commented Mar 28, 2019 at 8:40
$\begingroup$ $\endgroup$
8 Since you have a very large list, you should look at the timing
list = RandomReal[1, 10^6]; (And @@ Positive[list]) // AbsoluteTiming (* Hanlon *) (* {0.050573, True} *) VectorQ[list, Positive] // AbsoluteTiming (* J.M. *) (* {0.261642, True} *) (AnyTrue[list, Negative] // Not) // AbsoluteTiming (* Morbo *) (* {0.324062, True} *) And @@ (list /. {x_?Negative -> False, x_?Positive -> True}) // AbsoluteTiming (* Alrubaie *) (* {1.00664, True} *) EDIT: As suggested by mjw, encountering a nonpositive value early in the list significantly alters the results.
list2 = ReplacePart[list, 1000 -> -1]; (And @@ Positive[list2]) // AbsoluteTiming (*Hanlon*) (* {0.277642, False} *) VectorQ[list2, Positive] // AbsoluteTiming (*J.M.*) (* {0.000223, False} *) (AnyTrue[list2, Negative] // Not) // AbsoluteTiming (*Morbo*) (* {0.000262, False} *) And @@ (list2 /. {x_?Negative -> False, x_?Positive -> True}) // AbsoluteTiming (*Alrubaie*) (* {1.43026, False} *) - $\begingroup$ Looks like your method is five times faster than the next best! Can you give some insight into why this is? Thanks! $\endgroup$mjw– mjw2019-03-27 15:34:36 +00:00Commented Mar 27, 2019 at 15:34
- 1$\begingroup$ Also, and I guess this depends on the probability of any entry being negative, it may make sense for the algorithm to stop as soon as it finds a negative (or non-positive) element in the list. $\endgroup$mjw– mjw2019-03-27 15:37:18 +00:00Commented Mar 27, 2019 at 15:37
- 1$\begingroup$ @mjw,
And[]does short-circuit evaluation. $\endgroup$J. M.'s missing motivation– J. M.'s missing motivation2019-03-27 15:41:58 +00:00Commented Mar 27, 2019 at 15:41 - 1$\begingroup$ @Bob, Thank you for your edit. Why, though, does it take longer for your method to work when there is a negative entry? I would have thought that in each case, it would take the same amount of time to go through the whole list. $\endgroup$mjw– mjw2019-03-27 16:03:04 +00:00Commented Mar 27, 2019 at 16:03
- 1$\begingroup$ @Roman, I do not believe that any lazy evaluation is being done. My comment was more to point out that an evaluation like
And[True, True, False, True, True, ... True]will finish at once (and similar remarks apply forOr[]). Perhaps one can judiciously useCatch[]/Throw[]if an early-return test for long lists is desired. $\endgroup$J. M.'s missing motivation– J. M.'s missing motivation2019-03-27 16:06:54 +00:00Commented Mar 27, 2019 at 16:06
$\begingroup$ $\endgroup$
4 Ah, maybe this is too simple, but works for exactly what you're doing:
data = Table[RandomReal[{-1,1}],{i,1,1000}]; AnyTrue[data,Negative] // Not (*False*) data2 = Table[RandomReal[], {i, 1, 10^2}]; AnyTrue[data2, Negative] // Not (*True*) - $\begingroup$
AllTrue[data, Positive]to get the sign right. Or useNoton your solution. $\endgroup$Roman– Roman2019-03-27 14:55:32 +00:00Commented Mar 27, 2019 at 14:55 - $\begingroup$ @Roman - the poster is using
AnyTruenotAllTrue$\endgroup$Bob Hanlon– Bob Hanlon2019-03-27 15:00:23 +00:00Commented Mar 27, 2019 at 15:00 - 1$\begingroup$ Yes @BobHanlon . In order to invert his solution to what the OP wants you have to either
Not@AnyTrue[data,Negative]or (simpler)AllTrue[data,Positive]orAllTrue[data,NonNegative]. $\endgroup$Roman– Roman2019-03-27 15:04:23 +00:00Commented Mar 27, 2019 at 15:04 - $\begingroup$ ah, signs are reversed, missed that part. I updated the code to reflect questioners exact question. $\endgroup$DrMrstheMonarch– DrMrstheMonarch2019-03-27 15:04:27 +00:00Commented Mar 27, 2019 at 15:04
$\begingroup$ $\endgroup$
0 list = {1, 2, 3, 4, -5, -6, -7}; list /. {x_?Negative -> True, x_?Positive -> False}
VectorQ[list, Positive]? $\endgroup$Applyas inAnd @@ Positive[list]$\endgroup$Positive), or do you need all terms to be zero or positive (useNonNegative)? $\endgroup$