96

Can I use ~A to invert a numpy array of booleans, instead of the rather awkward functions np.logical_and() and np.invert()?

Indeed, ~ seems to work fine, but I can't find it in any nympy reference manual, and - more alarmingly - it certainly does not work with scalars (e.g. bool(~True) returns True !), so I'm a little bit worried ...

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Rolf Bartstra
  • 1,643
  • 1
  • 16
  • 19
  • 4
    See http://stackoverflow.com/questions/13600988/python-tilde-unary-operator-as-negation-numpy-bool-array – NPE Dec 05 '12 at 17:18
  • Does this answer your question? [python tilde unary operator as negation numpy bool array](https://stackoverflow.com/questions/13600988/python-tilde-unary-operator-as-negation-numpy-bool-array) – AMC Feb 15 '20 at 02:08

2 Answers2

76

short answer: YES

Ref:

http://docs.scipy.org/doc/numpy/reference/generated/numpy.invert.html

Notice:

Computes the bit-wise NOT of the underlying binary representation of the integers in the input arrays. This ufunc implements the C/Python operator ~.

and

bitwise_not is an alias for invert:

>> np.bitwise_not is np.invert
>> True
squid
  • 2,597
  • 1
  • 23
  • 19
  • 26
    However, be careful that this will not work with an array of 0's and 1's! It will only work with an array of booleans. If you need to handle that kind of flexibility, use numpy.logical_not instead – tvt173 Dec 15 '15 at 19:45
  • 6
    @tvt173 Yes, `boolean not` and `logic not` are always different. Both the question and the answer are about `boolean not`. Thanks for reminding anyway. – squid Dec 18 '15 at 10:19
  • Note that, this actually only works when the array's `dtype=bool`. I just stumbled upon the edge case of an array full of `True` and `False` objects with `dtype=object`. These are converted like `~True => -2` and `~False => -1`. See the duplicate target linked in the question comments. – Joooeey Jan 03 '23 at 17:41
1

You can use the tilde if the array's dtype is boolean and you are sure that this won't change as the software matures. However, np.logical_not has two advantages:

  • It also works for object arrays, which can easily show up if np.nans or other objects make it into your array.
  • Its meaning is clear to anyone with a little background in logics.

There is also np.invert but it doesn't work with object arrays and the word is ambiguous.

~np.array([False, True], dtype=bool)
Out[7]: array([ True, False])

~np.array([False, True], dtype=object)
Out[9]: array([-1, -2], dtype=object)

np.invert([True, False])
Out[4]: array([False,  True])

np.invert((np.array([True, False], dtype=object)))
Out[5]: array([-2, -1], dtype=object)

np.logical_not(np.array([False, True], dtype=bool))
Out[8]: array([ True, False])

np.logical_not(np.array([False, True], dtype=object))
Out[10]: array([True, False], dtype=object)
Joooeey
  • 3,394
  • 1
  • 35
  • 49