In Python, how do I rotate a matrix 90 degrees counterclockwise? - python

>>> def rotate_matrix( k: List[List[int]]):
"""
For example, if I have:
m = [[1,2,3],
[2,3,3],
[5,4,3]]
rotate_matrix(m) should give me [[3,3,3],[2,3,4],[1,2,5]].
"""
Edit: Preferably without numpy.

Here is the counter clockwise matrix rotation as one line in pure python (i.e., without numpy):
new_matrix = [[m[j][i] for j in range(len(m))] for i in range(len(m[0])-1,-1,-1)]
If you want to do this in a function, then
def rotate_matrix( m ):
return [[m[j][i] for j in range(len(m))] for i in range(len(m[0])-1,-1,-1)]
and either way, the result for
m = [ [1,2,3], [2,3,3], [5,4,3]]
is
[[3, 3, 3], [2, 3, 4], [1, 2, 5]]
Aside, if you want the usual transpose, then the simple one line pure python version is
[[m[j][i] for j in range(len(m))] for i in range(len(m[0]))]

You could use the numpy function rot90
import numpy as np
m = np.array([[1,2,3],
[2,3,3],
[5,4,3]])
def rotate_matrix(mat):
return np.rot90(mat)

#solution1
print(list(list(x) for x in zip(*m))[::-1])
#solution2
print([[x[i] for x in m] for i in range(len(m))][::-1])
#solution3
r = []
i = 0
for row in m:
listToAdd = [item[i] for item in m]
r.append(listToAdd)
i +=1
print(r[::-1])

def rotate_90_degree_anticlckwise(matrix):
new_matrix = []
for i in range(len(matrix[0]), 0, -1):
new_matrix.append(list(map(lambda x: x[i-1], matrix)))
return new_matrix
def rotate_90_degree_clckwise(matrix):
new_matrix = []
for i in range(len(matrix[0])):
li = list(map(lambda x: x[i], matrix))
li.reverse()
new_matrix.append(li)
return new_matrix
def rotate_90_degree_clckwise_by_zip_method(matrix):
return list(list(x)[::-1] for x in zip(*matrix))

Look at this code. This is the way to rotate any matrix by 90 degrees using scratch
[This is the code to have a matrix rotated by 90 degrees][1]
n = input("enter input:")
l =[]
while (n !=""):
l.append(n.split(" "))
n = input("enter input:")
l1=[]
for i in range(len(l[0])):
l1.append([])
for j in range (len(l1)):
for p in range(len(l)):
l1[j].append(l[p][-(j+1)])
for s in l1:
print(*s)
'''
[1]: https://i.stack.imgur.com/c8jHC.png

Just flip the matrix vertically, then switch the upper-right triangle with the lower-left triangle
def rotate_matrix_ccw(mat):
if mat is None:
return None
n = len(mat)
if n == 1:
return mat
for i in range(n):
if len(mat[i]) != n:
raise Exception("Matrix must be square")
# flip the matrix vertically
for j in range(n // 2):
for i in range(n):
mat[i][j], mat[i][n - 1 - j] = mat[i][n - 1 - j], mat[i][j]
# switch the upper-right triangle with the lower-left triangle
for i in range(n):
for j in range(i):
mat[i][j], mat[j][i] = mat[j][i], mat[i][j]
return mat

You can loop through the original matrix and create a new one. This is my approach for counterclockwise, for the other way it would be similar.
This doesn't require it to be a square.
def left_rotate(mat):
if not mat: return []
colcount = len(mat[0])
# Initialize empty lists
new = [list() for _ in range(colcount)]
# Go through the rows, append elements one by one
for row in mat:
for j in range(colcount):
new[j].append(row[colcount - 1 - j])
return new
Example:
>>> print(left_rotate([[1, 2], [3, 4], [5, 6]]))
[[2, 4, 6], [1, 3, 5]]

flip vertically (left to right) then transpose:
m = [[1,2,3],
[2,3,3],
[5,4,3]]
print([list(x) for x in zip(*[x[::-1] for x in m])])

def rotateMatrix(self, matrix):
for i in range(len(matrix)):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
matrix.reverse()

Rotate matrix anti-clockwise 90deg (In-place)
def rotate(matrix):
for i in range(len(matrix) - 1, -1, -1):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]
matrix.reverse()
Rotate matrix clockwise 90deg (In-place)
def rotate(matrix):
matrix.reverse()
for i in range(len(matrix)):
for j in range(i):
matrix[i][j], matrix[j][i] = matrix[j][i], matrix[i][j]

In case you're working with square matrixes (rows == cols) then you can use this:
list(zip(*reversed(a))) # 90 degrees clockwise
list(zip(*reversed(a)))[::-1] # 90 degrees counter-clockwise

def rotated_array(array):
new_array = np.zeros([array.shape[0], array.shape[1]])
for i in range(array.shape[0]):
for j in range(array.shape[1]):
t = array.shape[0]-j-1 # To Start with last row and first column
new_array[i, j] = array[t, i]
return new_array

Related

Combine two numpy arrays into matrix with a two-argument function

Roughly I want to convert this (non-numpy) for-loop:
N = len(left)
M = len(right)
matrix = np.zeros(N, M)
for i in range(N):
for j in range(M):
matrix[i][j] = scipy.stats.binom.pmf(left[i], C, right[j])
It's sort of like a dot product but of course mathematically not a dot product. How would I normally vectorize or make something like this pythonic/numpythonic?
scipy.stats.binom.pmf already is vectorized. However, you have to broadcast your inputs in order to get your desired result.
broadcast_out = scipy.stats.binom.pmf(left[:, None], C, right)
Validation
np.random.seed(314)
left = np.arange(5, dtype=float)
right = np.random.rand(5)
C = 5
broadcast_out = scipy.stats.binom.pmf(left[:, None], C, right)
N = len(left)
M = len(right)
matrix = np.zeros((N, M))
for i in range(N):
for j in range(M):
matrix[i][j] = scipy.stats.binom.pmf(left[i], C, right[j])
print(np.array_equal(matrix, broadcast_out))
True

evaluate many monomials at many points

The following problem concerns evaluating many monomials (x**k * y**l * z**m) at many points.
I would like to compute the "inner power" of two numpy arrays, i.e.,
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = numpy.ones((10, 5))
for i in range(10):
for j in range(5):
for k in range(3):
out[i, j] *= a[i, k]**b[k, j]
print(out.shape)
If instead the line would read
out[i, j] += a[i, k]*b[j, k]
this would be a a number of inner products, computable with a simple dot or einsum.
Is it possible to perform the above loop in just one numpy line?
What about thinking of it in terms of logarithms:
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = np.exp(np.matmul(np.log(a), b))
Since c_ij = prod(a_ik ** b_kj, k=1..K), then log(c_ij) = sum(log(a_ik) * b_ik, k=1..K).
Note: Having zeros in a may mess up the result (also negatives, but then the result wouldn't be well defined anyway). I have given it a try and it doesn't seem to actually break somehow; I don't know if that behavior is guaranteed by NumPy but, to be safe, you can add something at the end like:
out[np.logical_or.reduce(a < eps, axis=1)] = 0
You can use broadcasting after extending those arrays to 3D versions -
(a[:,:,None]**b[None,:,:]).prod(axis=1)
Simply put -
(a[...,None]**b[None]).prod(1)
Basically, we are keeping the last axis and first axis from the two arrays aligned, while performing element-wise powers between the first and last axes from the two inputs. Schematically put using the given sample on shapes -
10 x 3 x 1
1 x 3 x 5
Two more solutions:
Inlining
numpy.array([
numpy.prod([a[:, i]**bb[i] for i in range(len(bb))], axis=0)
for bb in b.T
]).T
and using power.outer:
numpy.prod([numpy.power.outer(a[:, k], b[k]) for k in range(len(b))], axis=0)
Both are a bit slower than the broadcasting solution.
Even with some logic to accommodate for zero and negative values, the exp-log solution takes the cake.
Code to reproduce the plot:
import numpy
import perfplot
def loop(data):
a, b = data
m = a.shape[0]
n = b.shape[1]
out = numpy.ones((m, n))
for i in range(m):
for j in range(n):
for k in range(3):
out[i, j] *= a[i, k]**b[k, j]
return out
def broadcasting(data):
a, b = data
return (a[..., None]**b[None]).prod(1)
def log_exp(data):
a, b = data
neg_a = numpy.zeros(a.shape, dtype=int)
neg_a[a < 0.0] = 1
odd_b = numpy.zeros(b.shape, dtype=int)
odd_b[b % 2 == 1] = 1
negative_count = numpy.dot(neg_a, odd_b)
out = (-1)**negative_count * numpy.exp(
numpy.matmul(
numpy.log(abs(a), where=abs(a) > 0.0),
b
))
zero_a = numpy.zeros(a.shape, dtype=int)
zero_a[a == 0.0] = 1
pos_b = numpy.zeros(b.shape, dtype=int)
pos_b[b > 0] = 1
zero_count = numpy.dot(zero_a, pos_b)
out[zero_count > 0] = 0.0
return out
def inline(data):
a, b = data
return numpy.array([
numpy.prod([a[:, i]**bb[i] for i in range(len(bb))], axis=0)
for bb in b.T
]).T
def outer_power(data):
a, b = data
return numpy.prod([
numpy.power.outer(a[:, k], b[k]) for k in range(len(b))
], axis=0)
perfplot.show(
setup=lambda n: (
numpy.random.rand(n, 3) - 0.5,
numpy.random.randint(0, 10, (3, n))
),
n_range=[2**k for k in range(11)],
repeat=10,
kernels=[
loop,
broadcasting,
inline,
log_exp,
outer_power
],
logx=True,
logy=True,
xlabel='len(a)',
)
import numpy
a = numpy.random.rand(10, 3)
b = numpy.random.rand(3, 5)
out = [[numpy.prod([a[i, k]**b[k, j] for k in range(3)]) for j in range(5)] for i in range(10)]

Recursive function to calculate matrix multiplication

I'm trying to write a recursive function to calculate matrix multiplication.
EDITED :
This is the code :
def mult_mat(x, nbr):
result = [[2, 4],
[1, 3]]
if nbr == 1:
return result
else:
for i in range(len(x)):
for j in range(len(result[0])):
for k in range(len(result)):
result[i][j] += x[i][k] * result[k][j]
mult_mat(result, nbr-1)
return result
m = [[2, 4],
[1, 3]]
# the number of times m1 will be multiplied
n = 3
res = mult_mat(m, n)
for r in res:
print(r)
As an example, for n = 3 I am trying to get the result:
m1 * m1 will be [[8, 20], [5, 3]] = result and result * m1 will be [[36, 92], [23, 59]] and so on.
the output of this code is:
[10, 24]
[44, 108]
and what i want is this :
[36, 92]
[23, 59]
Okay, let's understand conceptually what you want to achieve with recursion. You want to multiply a matrix, M, with itself. mult_mat(M, 2) will give M * M, therefore, mult_mat(M, 1) just returns M itself.
In the multiplication, you have 3 matrices going on. x and y are the two matrices you're multiplying together, which you store in result. Now, let's look what happens for the first few multiplications.
x * x # n = 2
x * (x * x) # n = 3
# here, we initially calculate x * x,
# which we pass as y in the next stack for x * y
As you can see, for n = 2, you multiply x by itself, but for n > 2, y is different than x, so you must pass it on to the function somehow. We can code this idea as follows.
def mult_mat(x, nbr, y=None):
if nbr == 1:
# if y is None, it means we called `mult_mat(x, 1)`, so return `x`
if y is not None:
return y
return x
if y is None:
y = x
result = [[0, 0],
[0, 0]]
for i in range(len(x)):
for j in range(len(result[0])):
for k in range(len(result)):
result[i][j] += x[i][k] * y[k][j]
return mult_mat(x, nbr-1, result)
m = [[2, 4],
[1, 3]]
# the number of times m1 will be multiplied
n = 3
res = mult_mat(m, n)
for r in res:
print(r)
It's may look like ugly code and that's probably because there are better ways to achieve what you want without recursion. However, I couldn't think of a different way while implementing recursion. My solution logically flowed from the points I laid out at the beginning.

Vectorized Computation of Compositional Variance

Given an n X m matrix with entries xi, j, the compositional variance is an m X m matrix, with the i, j entry including the expression
∑k = 1n [ ln2(xk, i / xk, j)]
(it includes other, easily calculated, expressions).
This is very easy to calculate in a loop, but how can it be calculated using vectorization?
Here is the crappy loop code:
x = np.array([[1, 2, 3], [4, 5, 6]], dtype=float)
v = np.zeros((3, 3))
for i in range(3):
for j in range(3):
for k in range(2):
v[i, j] += np.log(x[k, i] / x[k, j])**2
Assuming you meant something like (np.log(x[k, i] / x[k, j])**2) in NumPy terms, being summed over for k = 1:n, one vectorized approach could be suggested with broadcasting -
((np.log(x[:,:,None]/x[:,None])**2)).sum(0)

Nearest neighbors

I am writing a piece of code to print the nearest neighbors for the elements of a matrix. I get an
"invalid index" error
when I try to print the list of the neighbours (last line). Can you spot why?
Here's the code:
neighbours = ndarray((ran_x-2, ran_y-2,8),int)
for i in range(0, ran_x):
for j in range(0, ran_y):
if 1 < i < ran_x-1:
if 1 < j < ran_y-1:
neighbours = ([matrix[i-1,j-1],matrix[i-1,j],matrix[i-1,j+1],matrix[i,j-1],matrix[i,j+1],matrix[i+1,j-1],matrix[i+1,j],matrix[i+1,j+1]])
neighbours = np.array(neighbours)
for l in range(1, ran_x-1):
for m in range(1, ran_y-1):
print neighbours[l,m]
Look at the size of your array, it's a (ran_x - 2) * (ran_y - 2) elements array:
neighbours = ndarray((ran_x-2, ran_y-2,8),int)
And you try to access the elements at index ran_x-1 and ran_y-1 which are out of bound.
sliding window stride_tricks is great for this (https://stackoverflow.com/a/11000193/541038)
import numpy as np
from numpy.lib.stride_tricks import as_strided
def sliding_window(arr, window_size):
""" Construct a sliding window view of the array"""
arr = np.asarray(arr)
window_size = int(window_size)
if arr.ndim != 2:
raise ValueError("need 2-D input")
if not (window_size > 0):
raise ValueError("need a positive window size")
shape = (arr.shape[0] - window_size + 1,
arr.shape[1] - window_size + 1,
window_size, window_size)
if shape[0] <= 0:
shape = (1, shape[1], arr.shape[0], shape[3])
if shape[1] <= 0:
shape = (shape[0], 1, shape[2], arr.shape[1])
strides = (arr.shape[1]*arr.itemsize, arr.itemsize,
arr.shape[1]*arr.itemsize, arr.itemsize)
return as_strided(arr, shape=shape, strides=strides)
def cell_neighbors(arr, i, j, d):
"""Return d-th neighbors of cell (i, j)"""
w = sliding_window(arr, 2*d+1)
ix = np.clip(i - d, 0, w.shape[0]-1)
jx = np.clip(j - d, 0, w.shape[1]-1)
i0 = max(0, i - d - ix)
j0 = max(0, j - d - jx)
i1 = w.shape[2] - max(0, d - i + ix)
j1 = w.shape[3] - max(0, d - j + jx)
return w[ix, jx][i0:i1,j0:j1].ravel()
x = np.arange(8*8).reshape(8, 8)
print x
for d in [1, 2]:
for p in [(0,0), (0,1), (6,6), (8,8)]:
print "-- d=%d, %r" % (d, p)
print cell_neighbors(x, p[0], p[1], d=d)
The problem is you continuously reassign neighbours to a 1D array with length 8. Instead you should assign the neighbour data to a slice of the array you had already created:
for i in range(1, ran_x-1):
for j in range(1, ran_y-1):
neighbours[i-1,j-1,:] = [matrix[i-1,j-1],matrix[i-1,j],matrix[i-1,j+1],matrix[i,j-1],matrix[i,j+1],matrix[i+1,j-1],matrix[i+1,j],matrix[i+1,j+1]]
Note that I changed the ranges so you don't need the if statements. Your code would be faster and (arguably) neater as the following:
neighbours = np.empty((ran_x-2, ran_y-2, 8), int)
# bool array to extract outer ring from a 3x3 array:
b = np.array([[1,1,1],[1,0,1],[1,1,1]], bool)
for i in range(ran_x-2):
for j in range(ran_y-2):
neighbours[i,j,:] = matrix[i:i+3, j:j+3][b]
Of course it would be faster still to immediately print the neighbours without storing them at all, if that's all you need.

Categories