Python comparing two matrices produces error - python

Hello I have the following code which transposes one matrix and compares it to the original matrix in order to check if the matrix is symetrical.
def sym(x):
mat = x
transpose = 0;
(m,n) = x.shape
if(m != n):
print("Matrix must be square")
return
else:
transpose = ([[x[j][i] for j in range(len(x))] for i in range(len(x[0]))])
print(transpose)
print(x)
if(transpose == mat):
print("Symetrical")
else:
print("Not symetrical")
return
A = np.random.rand(5,5)
SymMatrix = (A + A.T)/2
sym(SymMatrix)
I recieve the following data from the prints:
[[0.17439677739055337, 0.4578837676040824, 0.35842887026076997, 0.8610456087667133, 0.2967753611380975], [0.4578837676040824, 0.6694101430064164, 0.6718596412137644, 0.5107862111816033, 0.6429698779871544], [0.35842887026076997, 0.6718596412137644, 0.5387701626024015, 0.708555677626843, 0.5756758392540096], [0.8610456087667133, 0.5107862111816033, 0.708555677626843, 0.37095928395815847, 0.7062962356554356], [0.2967753611380975, 0.6429698779871544, 0.5756758392540096, 0.7062962356554356, 0.3807024190850993]]
[[0.17439678 0.45788377 0.35842887 0.86104561 0.29677536]
[0.45788377 0.66941014 0.67185964 0.51078621 0.64296988]
[0.35842887 0.67185964 0.53877016 0.70855568 0.57567584]
[0.86104561 0.51078621 0.70855568 0.37095928 0.70629624]
[0.29677536 0.64296988 0.57567584 0.70629624 0.38070242]]
along with this error:
The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
The first issue i see is that the transposes matrix has extra decimals in each value which i dont understand and I am not sure if this is the cause of the error. Any help on this would be appreciated. Thanks!

What you are doing is trying to compare two ndarrays, which results in something like this:
transpose == mat
array([[ True, True, True, True, True],
[ True, True, True, True, True],
[ True, True, True, True, True],
[ True, True, True, True, True],
[ True, True, True, True, True]])
The 'if' statement does not know which boolean he should pick. Should it be Trueif any of the values are True, or only if all values are True?
To indicate that all values should be True, add: .all() to your statement:
if((transpose == mat).all())
This results in a single boolean (in this case: True).

Related

How do I convert this nested for loop to a map or list comprehension in python?

Note: this is a working program, I just need to make it faster.
This is the nested for loop:
taf = []
for i in range(len(piou)):
counter = 0
for j in range(len(piou[i])):
if piou[i][j] == True:
counter = counter + 1
if counter == len(piou[i]):
taf.append(i)
I tried doing this:
taf = [i for i in range(len(piou))
if counter == len(piou[i])
for j in range(len(piou[i]))
if piou[i][j] == True]
but I can't figure out how to put the counter variable in between along with its increment.
Note: piou is a 2D tensor with boolean values and I am trying to find and append all the rows (i) index values to taf list which have all "true" column values.
piou looks like this:
tensor([[ True, True, True, True, False, False],
[ True, True, True, True, True, True],
[False, False, True, True, True, True],
[ True, True, False, False, True, True],
[ True, True, True, True, True, True]], device='cuda:0')
A loop where you're just incrementing a number can be replaced with sum(), but where that summation is just going to be compared with the length of the list, use all().
As well, avoid for i in range(len(seq)) ... i, seq[i], use for i, x in enumerate(seq) instead.
taf = [i for i, row in enumerate(piou) if all(row)]

Find out different lengths with values in a two-dimensional list, depending on the number given as a parameter

Suppose I have a two-dimensional list mixed with True and False. I would like to create a function that gives me an additional parameter, which should be the number of elements to be output. The output should be like this:
For example, if I enter 3 as a number, the row and column in which 3 x True are located one after the other should be displayed.
So just the row and the first column
For example, in the list below:
3 x True in row: 1 and col: 3
lst = [[False, True, False, True, True, False],
[False, True, False, True, True, True],
[True, False, True, True, True]]
I've tried several options, but never found a solution. I have another small example here, but of course I get the wrong output:
def baz(count):
for row in range(len(lst)):
for col in range(len(lst[row])):
if lst[row][col] == lst[row][(col + count) % len(lst[row])] and lst[row][col] is True:
return (row, col)
print(baz(3))
You can use all to simplify the code, it returns True if all values in the iterable are True otherwise False.
lst = [[False, True, False, True, True, False],
[False, True, False, True, True, True],
[True, False, True, True, True]]
def baz(count):
for row in range(len(lst)):
if len(lst[row]) < count:
continue
for col in range(len(lst[row])-count+1):
if all(lst[row][col:col+count]):
return (row, col)
return None
print(baz(3))
print(baz(2))
prints -
(1, 3)
(0, 3)
Note that there can be multiple matches for a given count, so the function returns the first match found.
Also, for high values of count, above code is not optimal(since in each step we are doing O(count) work when we call all(). So in case you are worried about performance you can use the below function instead -
def baz(count):
for row in range(len(lst)):
if len(lst[row]) < count:
continue
prev_true = -1
for col in range(len(lst[row])):
if not lst[row][col]:
prev_true = col
continue
if col - prev_true == count:
return (row, col-count+1)
return None

How to apply conditions for rows in a tensor where there is boolean values

I have the following tensor:
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
I applied conditions along the axis like below.
new_pred= []
if predictions == ([True,False,False]):
new_pred = torch.Tensor(0)
if predictions == ([False,False,True]):
new_pred = torch.Tensor(2)
if predictions == ([False,True,True]):
new_pred = torch.Tensor(2)
So I want the final output (new_pred) to be:
tensor([0, 2, 2, 0])
But I am getting a blank [] for the new_pred tensor. I think my logic must be flawed since nothing is getting stored in the new_pred. Can someone help me write this logic accurately?
The type of predictions is torch.Tensor while ([True, False, False]) is a list, first, you have to make sure both sides have the same type.
predictions == torch.tensor([True,False,False])
>>> tensor([[ True, True, True],
[False, True, False],
[False, False, False],
[True, True, True]])
Then, you are still comparing a 2d tensor to a 1d tensor, which is ambiguous in an if statement, an easy way to fix this would be to write a for loop, compare each row of the predictions to the conditions and append the result to the new_pred list. Note that you will be comparing two booleans tensors with the size of three, therefore, you have to make sure the result of the comparison is True for all of the cells.
predictions = torch.tensor([[ True, False, False],
[False, False, True],
[False, True, True],
[ True, False, False]])
conditions = torch.tensor([[True,False,False],
[False,False,True],
[False,True,True]])
new_predict = []
for index in range(predictions.size(0)):
if (predictions[index] == conditions[0]).all():
new_predict.append(0)
# ...
Alternatively, you can use slicing to achieve your expected result without any for loop.

Finding False-True transitions in a numpy array

Given a numpy array:
x = np.array([False, True, True, False, False, False, False, False, True, False])
How do I find the number of times the values transitions from False to True?
For the above example, the answer would be 2. I don't want to include transitions from True to False in the count.
From the answers to How do I identify sequences of values in a boolean array?, the following produces the indices at which the values are about to change, which is not what I want as this includes True-False transitions.
np.argwhere(np.diff(x)).squeeze()
# [0 2 7 8]
I know that this can be done by looping through the array, however I was wondering if there was a faster way to do this?
Get one-off slices - x[:-1] (starting from the first elem and ending in second last elem) and x[1:] (starting from the second elem and going on until the end), then look for the first slice being lesser than the second one, i.e. catch the pattern of [False, True] and finally get the count with ndarray.sum() or np.count_nonzero() -
(x[:-1] < x[1:]).sum()
np.count_nonzero(x[:-1] < x[1:])
Another way would be to look for the first slice being False and the second one as True, the idea again being to catch that pattern of [False, True] -
(~x[:-1] & x[1:]).sum()
np.count_nonzero(~x[:-1] & x[1:])
I kind of like to use numpy method "roll" for this kind of problems...
"roll" rotates the array to left some step length : (-1,-2,...) or to right (1,2,...)
import numpy as np
np.roll(x,-1)
...this will give x but shifted one step to the left:
array([ True, True, False, False, False, False, False, True, False, False],
dtype=bool)
A False followed by a True can then be expressed as:
~x & np.roll(x,-1)
array([ True, False, False, False, False, False, False, True, False, False],
dtype=bool)

Mask with numpy isin

I want to make a mask with numpy array. I've found a function, but it doesn't make what I want. Here is the code example:
np.isin([1,2,3,4,5,8,6,1,1],[1,2,3,5,1])
This code returns this:
array([ True, True, True, False, True, False, False, True, True], dtype=bool)
But I want the same output except the last value of the output array to be False. Because I need exact mask of the sequence ([1,2,3,5,1]) in this order and no longer than its length.
You can turn elements after certain amount of Trues to zero with:
mask[mask.cumsum() > 5] = False
# ^ length of the second array
import numpy as np
mask = np.isin([1,2,3,4,5,8,6,1,1],[1,2,3,5,1])
mask[mask.cumsum() > 5] = False
mask
# array([ True, True, True, False, True, False, False, True, False], dtype=bool)

Categories

Resources