Return the maximun of a matrix - python

I want to return the max value of a matrix.
For example this is my matrix:
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
I want to return the max so here '10'
This is my code but I have an error:
max = 0
for i in range(len(matrix)+1):
for j in range(len(matrix[0])+1):
if matrix[i][j] > matrix[i+1][j+1]:
max = matrix[i][j]
print(max)
Thanks in advance

There are several issues with your code, I suggest you use the max function:
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
result = max(max(row) for row in matrix)
print(result)
Output
10

you can try this.
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
max1 = 0
for sub_list in matrix:
for item in sub_list:
if item>max1:
max1=item

Multiple ways to do it:
Fix your method. In Python, lists are zero-based so you need to only iterate from i = 0 to len(matrix) - 1. Doing for i in range(len(matrix)): does this for you. You don't need to do range(len(matrix) + 1)). Also, you should only replace the current maxval if the element you're looking at is greater than maxval.
So,
maxval = -9999999
for i in range(len(matrix)):
for j in range(len(matrix[i])):
if matrix[i][j] > maxval:
maxval = matrix[i][j]
print(maxval)
# Out: 10
Or, a more pythonic way is to iterate over the elements instead of accessing them through their indices
maxval = -9999999
for row in matrix:
for element in row:
if element > maxval:
maxval = element
# maxval: 10
Notice I use maxval instead of max so as not to shadow python's inbuilt max() function.
Use numpy (if you're already using it for other things). Like wim mentioned in their comment, a numpy array is a much better way to store matrices instead of lists of lists. Why? See this question
import numpy as np
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
maxval = np.max(matrix)
# maxval: 10
Iterate over rows, create a list of max values in each row. Then find the max of this list
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
rowmax = [max(row) for row in matrix]
maxval = max(rowmax)
# or in one line:
maxval = max(max(row) for row in matrix)
Use map. This is essentially the same as the previous method.
matrix = [[0, 1, 10, 0, 0], [0, 0, 6, 0, 1], [0, 1, 4, 0, 0]]
maxval = max(map(max, matrix))

Related

Replace all but the first 1 in an array with 0

I am trying to find a way to replace all of the duplicate 1 with 0. As an example:
[[0,1,0,1,0],
[1,0,0,1,0],
[1,1,1,0,1]]
Should become:
[[0,1,0,0,0],
[1,0,0,0,0],
[1,0,0,0,0]]
I found a similar problem, however the solution does not seem to work numpy: setting duplicate values in a row to 0
Assume array contains only zeros and ones, you can find the max value per row using numpy.argmax and then use advanced indexing to reassign the values on the index to a zeros array.
arr = np.array([[0,1,0,1,0],
[1,0,0,1,0],
[1,1,1,0,1]])
res = np.zeros_like(arr)
idx = (np.arange(len(res)), np.argmax(arr, axis=1))
res[idx] = arr[idx]
res
array([[0, 1, 0, 0, 0],
[1, 0, 0, 0, 0],
[1, 0, 0, 0, 0]])
Try looping through each row of the grid
In each row, find all the 1s. In particular you want their indices (positions within the row). You can do this with a list comprehension and enumerate, which automatically gives an index for each element.
Then, still within that row, go through every 1 except for the first, and set it to zero.
grid = [[0, 1, 0, 1, 0], [1, 0, 0, 1, 0], [1, 1, 1, 0, 1]]
for row in grid:
ones = [i for i, element in enumerate(row) if element==1]
for i in ones[1:]:
row[i] = 0
print(grid)
Gives: [[0, 1, 0, 0, 0], [1, 0, 0, 0, 0], [1, 0, 0, 0, 0]]
You can use cumsum:
(arr.cumsum(axis=1).cumsum(axis=1) == 1) * 1
this will create a cummulative sum, by then checking if a value is 1 you can find the first 1s

Find first n non zero values in in numpy 2d array

I would like to know the fastest way to extract the indices of the first n non zero values per column in a 2D array.
For example, with the following array:
arr = [
[4, 0, 0, 0],
[0, 0, 0, 0],
[0, 4, 0, 0],
[2, 0, 9, 0],
[6, 0, 0, 0],
[0, 7, 0, 0],
[3, 0, 0, 0],
[1, 2, 0, 0],
With n=2 I would have [0, 0, 1, 1, 2] as xs and [0, 3, 2, 5, 3] as ys. 2 values in the first and second columns and 1 in the third.
Here is how it is currently done:
x = []
y = []
n = 3
for i, c in enumerate(arr.T):
a = c.nonzero()[0][:n]
if len(a):
x.extend([i]*len(a))
y.extend(a)
In practice I have arrays of size (405, 256).
Is there a way to make it faster?
Here is a method, although quite confusing as it uses a lot of functions, that does not require sorting the array (only a linear scan is necessary to get non null values):
n = 2
# Get indices with non null values, columns indices first
nnull = np.stack(np.where(arr.T != 0))
# split indices by unique value of column
cols_ids= np.array_split(range(len(nnull[0])), np.where(np.diff(nnull[0]) > 0)[0] +1 )
# Take n in each (max) and concatenate the whole
np.concatenate([nnull[:, u[:n]] for u in cols_ids], axis = 1)
outputs:
array([[0, 0, 1, 1, 2],
[0, 3, 2, 5, 3]], dtype=int64)
Here is one approach using argsort, it gives a different order though:
n = 2
m = arr!=0
# non-zero values first
idx = np.argsort(~m, axis=0)
# get first 2 and ensure non-zero
m2 = np.take_along_axis(m, idx, axis=0)[:n]
y,x = np.where(m2)
# slice
x, idx[y,x]
# (array([0, 1, 2, 0, 1]), array([0, 2, 3, 3, 5]))
Use dislocation comparison for the row results of the transposed nonzero:
>>> n = 2
>>> i, j = arr.T.nonzero()
>>> mask = np.concatenate([[True] * n, i[n:] != i[:-n]])
>>> i[mask], j[mask]
(array([0, 0, 1, 1, 2], dtype=int64), array([0, 3, 2, 5, 3], dtype=int64))

How to assign value to an element of 2d array with dynamic size?

I want to create an adjacency matrix for a graph without using any libraries. The problem is the size of the graph is not static and it increases over time. So I can not use a command like:
adj = [ [None for i in range(5)] for j in range(4) ]
and for example, assign 4 to element (1,1):
adj[1][1]=4
I have created an empty list called adj:
adj = []
now each time a node is added to the graph I add a list to adj:
adj.append([])
How can I assign a value to a specific element of the matrix, as I did with q[1][1]=4 when the size was fixed?
You can start with any default size and then use extend to add elements to a sublist, or add a new sublist.
adj = [ [0 for i in range(2)] for j in range(2) ]
print(adj)
#[[0, 0], [0, 0]]
adj[0].extend([1, 1])
#[[0, 0, 1, 1], [0, 0]]
print(adj)
adj.extend([[0, 0, 0, 0, 0]])
print(adj)
#[[0, 0, 1, 1], [0, 0], [0, 0, 0, 0, 0]]
Once you resize your list based on requirement, then you can assign your elements.
adj[0][0] = 2
adj[1][1] = 3
adj[2][2] = 4
print(adj)
#[[2, 0, 1, 1], [0, 3], [0, 0, 4, 0, 0]]

How to sum up each element in array list?

Having a bit of writing out the code.
For example, if I have an array of:
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
if I want to add first element of each item,
as in to return a list of 0 + 0 + 0 + 1 + 0, 0 + 1 + 0, 0 + 0 ...
I wrote the code:
def test(lst):
sum = 0
test_lst = []
i = 0
while i in range(0, 4):
for j in range(0, len(lst)):
sum += lst[j][i]
test_lst.append(sum)
i += 1
return test_lst
I get index size error.
How can I go about this?
sum(zip(*a)[0])
zip is a function that takes any number of n-length sequences and returns n tuples (among other things). The first of these tuples has the elements that came first in the tuples passed to zip. sum adds them together.
EDIT:
In Python 3, the above doesn't work. Use:
sum(next(zip(*a)))
instead. For all such sums,
map(sum, zip(*a))
a = ([0, 0, 1, 2], [0, 1, 1, 0], [0, 0, 1, 0], [1, 0, 1, 3], [0, 1, 1, 3])
Try using list comprehensions:
sum([item[0] for item in a])
The line above takes the first element of each list in the tuple, then puts it into a temporary list. We then call sum on that temporary list, which yields the answer.

Set rows of scipy.sparse matrix that meet certain condition to zeros

I wonder what is the best way to replaces rows that do not satisfy a certain condition with zeros for sparse matrices. For example (I use plain arrays for illustration):
I want to replace every row whose sum is greater than 10 with a row of zeros
a = np.array([[0,0,0,1,1],
[1,2,0,0,0],
[6,7,4,1,0], # sum > 10
[0,1,1,0,1],
[7,3,2,2,8], # sum > 10
[0,1,0,1,2]])
I want to replace a[2] and a[4] with zeros, so my output should look like this:
array([[0, 0, 0, 1, 1],
[1, 2, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 0, 1],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 2]])
This is fairly straight forward for dense matrices:
row_sum = a.sum(axis=1)
to_keep = row_sum >= 10
a[to_keep] = np.zeros(a.shape[1])
However, when I try:
s = sparse.csr_matrix(a)
s[to_keep, :] = np.zeros(a.shape[1])
I get this error:
raise NotImplementedError("Fancy indexing in assignment not "
NotImplementedError: Fancy indexing in assignment not supported for csr matrices.
Hence, I need a different solution for sparse matrices. I came up with this:
def zero_out_unfit_rows(s_mat, limit_row_sum):
row_sum = s_mat.sum(axis=1).T.A[0]
to_keep = row_sum <= limit_row_sum
to_keep = to_keep.astype('int8')
temp_diag = get_sparse_diag_mat(to_keep)
return temp_diag * s_mat
def get_sparse_diag_mat(my_diag):
N = len(my_diag)
my_diags = my_diag[np.newaxis, :]
return sparse.dia_matrix((my_diags, [0]), shape=(N,N))
This relies on the fact that if we set 2nd and 4th elements of the diagonal in the identity matrix to zero, then rows of the pre-multiplied matrix are set to zero.
However, I feel that there is a better, more scipynic, solution. Is there a better solution?
Not sure if it is very scithonic, but a lot of the operations on sparse matrices are better done by accessing the guts directly. For your case, I personally would do:
a = np.array([[0,0,0,1,1],
[1,2,0,0,0],
[6,7,4,1,0], # sum > 10
[0,1,1,0,1],
[7,3,2,2,8], # sum > 10
[0,1,0,1,2]])
sps_a = sps.csr_matrix(a)
# get sum of each row:
row_sum = np.add.reduceat(sps_a.data, sps_a.indptr[:-1])
# set values to zero
row_mask = row_sum > 10
nnz_per_row = np.diff(sps_a.indptr)
sps_a.data[np.repeat(row_mask, nnz_per_row)] = 0
# ask scipy.sparse to remove the zeroed entries
sps_a.eliminate_zeros()
>>> sps_a.toarray()
array([[0, 0, 0, 1, 1],
[1, 2, 0, 0, 0],
[0, 0, 0, 0, 0],
[0, 1, 1, 0, 1],
[0, 0, 0, 0, 0],
[0, 1, 0, 1, 2]])
>>> sps_a.nnz # it does remove the entries, not simply set them to zero
10

Categories