Python 2d array boolean reduction - python

I've got a 2D array comprised of boolean values (True,False). I'd like to consolidate the array to a 1D based on a logical function of the contents.
e.g.
Input:
[[True, True, False],
[False, False, False],
[True, True, True]]
Output (logical AND):
[False,
False,
True]
How would this be done without a loop ?

You can use Python's built-in all method with a list-comprehension:
[all(x) for x in my_list]
If that's still too loopy for you, combine it with map:
map(all, my_list)
Note that map doesn't return a list in Python 3. If you want a list as your result, you can call list(map(all, my_list)) instead.

You can do this without NumPy too. Here is one solution using list comprehension. Explanation: It will loop over sub-lists and even if one of the items in each sub-list is False, it outputs False else True.
inp = [[True, True, False],[False, False, False],[True, True, True]]
out = [False if False in i else True for i in inp]
print (out)
# [False, False, True]
Alternative (less verbose) as suggested by Jean below:
out = [False not in i for i in inp]

I'm assuming you want to apply logical ANDs to the rows. You can apply numpy.all.
>>> import numpy as np
>>> a = np.array([[True, True, False], [False, False, False], [True, True, True]])
>>> a
array([[ True, True, False],
[False, False, False],
[ True, True, True]])
>>>
>>> np.all(a, axis=1)
array([False, False, True])
For a solution without numpy, you can use operator.and_ and functools.reduce.
>>> from operator import and_
>>> from functools import reduce
>>>
>>> lst = [[True, True, False], [False, False, False], [True, True, True]]
>>> [reduce(and_, sub) for sub in lst]
[False, False, True]
edit: actually, reduce is a bit redundant in this particular case.
>>> [all(sub) for sub in lst]
[False, False, True]
does the job just as well.

You can do this with numpy with the numpy.all function:
>>> import numpy as np
>>> arr = np.array([[True, True, False],
... [False, False, False],
... [True, True, True]]
... )
>>> np.all(arr, axis=1)
array([False, False, True])
Here thus the i-th element is True if all elements of the i-th row are True, and False otherwise. Note that the list should be rectangular (all sublists should contain the same number of booleans).
In "pure" Python, you can use the all function as well, like:
>>> data = [[True, True, False], [False, False, False], [True, True, True]]
>>> list(map(all, data))
[False, False, True]
This approach will work as well if the "matrix" is not rectangular. Note that for an empty sublist, this will return True, since all elements in an empty sublist are True.

You can also do this with map and reduce:
from functools import reduce
l = [[True, True, False],
[False, False, False],
[True, True, True]]
final = list(map(lambda x: reduce(lambda a, b: a and b, x), l))
print(final)
# [False, False, True]
The benefit here is that you can change the reduce function to something else (say, an OR or something more adventurous).

Related

is there a more efficient way to make a grid for bool values

I am trying to make a grid to store bool variables kinda like mine sweeper and i would like to find a better way
So far i have a very inefficient way of just declaring like 15 lists with the values set to false like this
A = [False, False, False, False, False, False, False, False, False, False]
Is there a more efficient way to do this
You can efficiently create a list of the same value with:
A = [False]*15
However, more code is required to extend this into a grid. Instead, you could use NumPy to create a grid of False (True) values by using np.zeros (np.ones). For example, a 3x4 grid of False values can be created with:
grid = np.zeros((3, 4), dtype=bool)
>> [[False False False False]
>> [False False False False]
>> [False False False False]]
You might want to use a 2D array for that:
array = [
[False, False, False, False, False, False, False, False, False, False],
[False, False, False, False, False, False, False, False, False, False],
...
]
This can also be created using a list comp:
array = [[False] * 15 for _ in range(15)]

Combining boolean masks, why is in Python: [False, True] and [True, False] == [True, False] [duplicate]

This question already has answers here:
What is Truthy and Falsy? How is it different from True and False?
(8 answers)
Closed 2 years ago.
I was busy with combining masks and it strikes me that:
>>> [False, True] and [True, False]
[True, False]
and
>>> [True, False] and [False, True]
[False, True]
Why is this the case? Why shouldn't I expect it to be [False, False] in both cases?
I also think this is why np.logical_and() exists in Numpy:
>> np.logical_and([True, False], [False, False])
array([False, False])
This is the same reason why:
>>> (1,2) and (3,4)
(3, 4)
You need to understand that this is not doing element-wise comparison as opposed to np.logical_and.
The way and works is, if you have a and b, it checks whether a is False, if yes, return a else return b, does not matter what the value of b is.
In your case [False, True] is not False:
>>> bool([False, True])
True
Because it is a non-empty list, even [False, False] is True.
So in the case of [False, True] and [True, False], it checks to see whether [False, True] is False, which it is not, so it returns the second value. Same for the other case.
A python implementation of the and or logic would be:
def AND(first, second):
if bool(first) == True:
return second
else:
return first
def OR(first, second):
if bool(first) == True:
return first
else:
return second

Combine Boolean Matrix

I’m trying to create a combine boolean matrix function, using the following code.
def AndCombine(array1, array2):
if array1.shape != array2.shape:
return 'Matrix size not equal.'
else:
Product= np.where(array1==1, True, np.where(array2==1, True, False))
print (Product)
return Product
The matrices I’m testing to combine are:
arr1= np.array([[True, False], [False, True]])
arr2= np.array([[False, True],[True, True]])
When I run my AndCombine(arr1, arr2) function, I expect to see a product of [[False, False],[False, True]], however the output I receive is [[True, True],[True, True]] and I’m unsure as to why this is happening.
Any help or suggestions would be appreciated!
Why not just use the & operator?
>>> arr1 & arr2
array([[False, False],
[False, True]], dtype=bool)

Generate Truth Tables with some variables already set in python

My requirement is to generate the truth tables for n variables, for which i can use itertables. However, in this requirement I have some variables already set to True/False
For eg sample input is [True, False, Undefined, True, Undefined]
What I want to generate is
[True, False, True, True, True]
[True, False, True, True, False]
[True, False, False, True, True]
[True, False, False, True, False]
Is there any easy way to do this?
Sure; we simply need to construct a list with all the options we're choosing from for each element. For example:
>>> from itertools import product
>>> vv = [True, False, None, True, None]
>>> choose_from = [[True, False] if x is None else [x] for x in vv]
>>> pp = product(*choose_from)
>>> for p in pp:
... print(p)
...
(True, False, True, True, True)
(True, False, True, True, False)
(True, False, False, True, True)
(True, False, False, True, False)
Create a list of lists like this:
possible = [[True],[False],[True,False],[True],[True,False]]
Then use itertools.product:
for table in itertools.product(*possible):
....

options for applying conditions to numpy arrays

I want to apply conditions to a numpy array and I feel like there is a better way out there. As a toy example say I want to know where the elements are equal to 2 or 3.
import numpy as np
a = np.arange(5)
one way would be to construct my condition piece by piece with numpy functions like so
result = np.logical_or(a == 2, a == 3)
One can see how this could get unwieldy with more complicated conditions though. Another option would be to use list comprehensions
result = np.array([x for x in a if x == 2 or x==3])
which is nice because now all my conditional logic can live together in one place but feels a little clunky because of the conversion to and from a list. It also doesn't work too well for multidimensional arrays.
Is there a better alternative that I am missing?
It's useful to point out that in the first example, you have a logical array, not the array [2, 3] (like you get in the second example). To recover the result from the second answer, you'd need
result = a[result]
However, in this case, since you're using boolean masks (True/False approximately equivalent to 1/0), you can actually use bitwise or to do the same thing as logical_or:
result = a[(a==2) | (a==3)]
A word of caution here -- Make sure you use parenthesis. Otherwise, operator precedence can be a bit nasty in these expressions (| binds tighter than ==).
you can remove elements form numpy array with delete
np.delete(a,[0,1,4])
or if you want to keep with the complement,
np.delete(a,np.delete(a,[2,3]))
You can & together views to get arbitrarily complex results:
>>> A = np.random.randint(0, 100, 25).reshape(5,5)
>>> A
array([[98, 4, 46, 40, 24],
[93, 75, 36, 19, 63],
[23, 10, 62, 14, 59],
[99, 24, 57, 78, 74],
[ 1, 83, 52, 54, 27]])
>>> A>10
array([[ True, False, True, True, True],
[ True, True, True, True, True],
[ True, False, True, True, True],
[ True, True, True, True, True],
[False, True, True, True, True]], dtype=bool)
>>> (A>10) & (A<20)
array([[False, False, False, False, False],
[False, False, False, True, False],
[False, False, False, True, False],
[False, False, False, False, False],
[False, False, False, False, False]], dtype=bool)
>>> (A==19) | (A==14) # same output
You can also write a function and use map to call the function on each element. Inside the function have as many tests as you wish:
>>> def test(ele):
... return ele==2 or ele==3
...
>>> map(test,np.arange(5))
[False, False, True, True, False]
You can use numpy.vectorize:
>>> def test(x):
... return x>10 and x<20
...
>>> v=np.vectorize(test)
>>> v(A)
array([[False, False, False, False, False],
[False, False, False, True, False],
[False, False, False, True, False],
[False, False, False, False, False],
[False, False, False, False, False]], dtype=bool)

Categories

Resources