How can i do the transpose of a matrix in python? [duplicate] - python

This question already has answers here:
Basic matrix transpose in python
(5 answers)
Closed 6 months ago.
I am making a function in python in which when taking a matrix A, it returns a matrix B with swapped rows and columns, example:
if i enter this matrix:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
Should return
1 5 9 13
2 6 10 14
3 7 11 15
4 8 12 16
but what I get is:
array([[ 1, 5, 9, 13],
[ 5, 6, 10, 14],
[ 9, 10, 11, 15],
[13, 14, 15, 16]])
I don't understand why, could someone help me understand this error and how can I solve it?
my code:
def transpose(matrix):
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix[i][j] = matrix[j][i]
return matrix
(I can't use default functions like transpose, I have to code)

This line
matrix[i][j] = matrix[j][i]
is your issue.
For example, when i = 1 and j = 2, you set matrix[1][2] to 10 because matrix[2][1] is 10. When you come around the next time to i = 2 and j = 1, you set matrix[2][1] to 10 because matrix[1][2] was set to 10 even though it was originally 7, it doesn't keep a memory of the previous value.
Depending on if you want the function to mutate the original matrix or return a new matrix with changes values (but keep the original) will change how you create this function.
To mutate the original
def transpose(matrix):
matrix2 = numpy.copy(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix[i][j] = matrix2[j][i]
return matrix
To return a new array
def transpose(matrix):
matrix2 = numpy.copy(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
matrix2[i][j] = matrix[j][i]
return matrix2

zip can do this for you. Unpack the list and pass sub lists as arguments to the zip:
lst = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16],
]
transposed = list(zip(*lst))
for i in transposed:
print(i)
output:
(1, 5, 9, 13)
(2, 6, 10, 14)
(3, 7, 11, 15)
(4, 8, 12, 16)

You can use numpy.transpose to transpose a matrix.
As for why your code is not working is because your program does the follow assignments in a loop:
matrix[0][2] = matrix[2][0] # writes 9
...
matrix[2][0] = matrix[0][2] # writes 9 instead of 3 because matrix[0][2] has previously been updated
So to fix this you can use an intermediate variable like output_matrix in this example:
def transpose(matrix):
output_matrix = np.zeros_like(matrix)
for i in range(matrix.shape[0]):
for j in range(matrix.shape[1]):
output_matrix[i][j] = matrix[j][i]
return output_matrix

Related

Array rotation(Juggling method) in python - List Index out of range

Array rotation can be done by slicing in python or even some other easier way too. But, I found a method in GFG - which has the following procedure to rotate an array:
Instead of moving one by one, divide the array into different sets where a number of sets are equal to GCD of n and d and move the elements within sets.
If GCD is 1, then, for example, array (n = 7 and d =2), then elements will be moved within one set only, we just start with temp = arr[0] and keep moving arr[I+d] to arr[I] and finally store temp at the right place.
Here is an example for n =12 and d = 3. GCD is 3 and
Let arr[] be {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
a) Elements are first moved in first set –
arr[] after this step --> {4 2 3 7 5 6 10 8 9 1 11 12}
b)Then in second set.
arr[] after this step --> {4 5 3 7 8 6 10 11 9 1 2 12}
c)Finally in the third set.
arr[] after this step --> {4 5 6 7 8 9 10 11 12 1 2 3}
I tried to implement this method in python:
arr = [9,8,0,3,4,5,6,7,8]
d=3
for i in range(d):
for j in range(i,len(arr),d):
if j+1 == len(arr)-d+(i+1):
break
temp = arr[j]
arr[j]=arr[j+d]
arr[j+d] = temp
print(arr)
I don't know where I have gone wrong with the code. For this particular array as well as d value(rotation value) - I get the perfect output : [3, 4, 5, 6, 7, 8, 9, 8, 0]
But, when I give the value of d=2,
I get this error:
File ".\array_rotation.py", line 114, in <module>
arr[j]=arr[j+d]
IndexError: list index out of range
The same goes for different arrays too, I get a correct answer for the array according to the 'd' value.
The other array: arr = [1,2,3,4,5,6,7,8,9,10,11,12], d=2 -> I get perfect answer: [3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 1, 2]
But with d=5 -> Again, I get list index out of range error.
I don't know where I have gone wrong - some test cases work and some do not.

Split a numpy array into 8-elements arrays and invert each of them

Well, I have a numpy array like that:
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
My desired output is:
b=['87654321','161514131211109','2423222120191817']
For it, I need first to split "a" into arrays of 8 elements and then I have a list like that:
np.split(a) = [array([1, 2, 3, 4, 5, 6, 7, 8], dtype=int8),
array([9, 10, 11, 12, 13, 14, 15, 16], dtype=int8),
array([17, 18, 19, 20, 21, 22, 23, 24], dtype=int8)]
so, I need to invert each array into it and join the numbers to make like a list of joint numbers.
No need for numpy, though it will work for an array as well. One way:
>>> [''.join(str(c) for c in a[x:x+8][::-1]) for x in range(0, len(a), 8)]
['87654321', '161514131211109', '2423222120191817']
Try this. You reshape your data and then convert it to string elements. Loop it and append it to new list.
import numpy as np
a=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
lst = list(np.array(a).reshape(3,8).astype("U"))
my_lst = []
for i in lst:
my_lst.append("".join(i[::-1]))
print(my_lst)
The simplest way is first to reverse the original array (or create a reversed copy), and then to split:
a = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24]
acopy = a[::-1]
splitted = np.array_split(acopy, 3)
print(splitted[0]) # [24 23 22 21 20 19 18 17]
print(splitted[1]) # [16 15 14 13 12 11 10 9]
print(splitted[2]) # [8 7 6 5 4 3 2 1]
Now when lists are reversed, you can join elements of each list to make strings:
str1 = ''.join(str(x) for x in splitted[0]) # '2423222120191817'
str2 = ''.join(str(x) for x in splitted[1]) # '161514131211109'
str3 = ''.join(str(x) for x in splitted[2]) # '87654321'

Numpy where() using a condition that changes with the items position in the array

I'm trying to build a grid world using numpy.
The grid is 4*4 and laid out in a square.
The first and last squares (i.e. 1 and 16) are terminal squares.
At each time step you can move one step in any direction either: up, down , left or right.
Once you enter one of the terminal squares no further moves are possible and the game terminates.
The first and last columns are the left and right edges of the square whilst the first and last rows represent the top and bottom edges.
If you are on an edge, for example the left one and attempt to move left, instead of moving left you stay in the square you started in. Similarly you remain in the same square if you try and cross any of the other edges.
Although the grid is a square I've implemented it as an array.
States_r calculates the position of the states after a move right. 1 and 16 stay where they are because they are terminal states (note the code uses zero based counting so 1 and 16 are 0 and 15 respectively in the code).
The rest of the squares are in increased by one. The code for states_r works however those squares on the right edge i.e. (4, 8, 12) should also stay where they are but states_r code doesn't do that.
State_l is my attempt to include the edge condition for the left edge of the square. The logic is the same the terminal states (1, 16) should not move nor should those squares on the left edge (5, 9, 13). I think the general logic is correct but it's producing an error.
states = np.arange(16)
states_r = states[np.where((states + 1 <= 15) & (states != 0), states + 1, states)]
states_l = states[np.where((max(1, (states // 4) * 4) <= states - 1) & (states != 15), states - 1, states)]
The first example states_r works, it handles the terminal state but does not handle the edge condition.
The second example is my attempt to include the edge condition, however it is giving me the following error:
"The truth value of an array with more than one element is ambiguous."
Can someone please explain how to fix my code?
Or alternatively suggest another solution,ideally I want the code to be fast (so I can scale it up) so I want to avoid for loops if possible?
If I understood correctly you want arrays which indicate for each state where the next state is, depending on the move (right, left, up, down).
If so, I guess your implementation of state_r is not quit right. I would suggest to switch to a 2D representation of your grid, because a lot of the things you describe are easier and more intuitive to handle if you have x and y directly (at least for me).
import numpy as np
n = 4
states = np.arange(n*n).reshape(n, n)
states_r, states_l, states_u, states_d = (states.copy(), states.copy(),
states.copy(), states.copy())
states_r[:, :n-1] = states[:, 1:]
states_l[:, 1:] = states[:, :n-1]
states_u[1:, :] = states[:n-1, :]
states_d[:n-1, :] = states[1:, :]
# up [[ 0, 1, 2, 3],
# left state right [ 0, 1, 2, 3],
# down [ 4, 5, 6, 7],
# [ 8, 9, 10, 11]]
#
# [[ 0, 0, 1, 2], [[ 0, 1, 2, 3], [[ 1, 2, 3, 3],
# [ 4, 4, 5, 6], [ 4, 5, 6, 7], [ 5, 6, 7, 7],
# [ 8, 8, 9, 10], [ 8, 9, 10, 11], [ 9, 10, 11, 11],
# [12, 12, 13, 14]] [12, 13, 14, 15]] [13, 14, 15, 15]]
#
# [[ 4, 5, 6, 7],
# [ 8, 9, 10, 11],
# [12, 13, 14, 15],
# [12, 13, 14, 15]]
If you want to exclude the terminal states, you can do something like this:
terminal_states = np.zeros((n, n), dtype=bool)
terminal_states[0, 0] = True
terminal_states[-1, -1] = True
states_r[terminal_states] = states[terminal_states]
states_l[terminal_states] = states[terminal_states]
states_u[terminal_states] = states[terminal_states]
states_d[terminal_states] = states[terminal_states]
If you prefer the 1D approach:
import numpy as np
n = 4
states = np.arange(n*n)
valid_s = np.ones(n*n, dtype=bool)
valid_s[0] = False
valid_s[-1] = False
states_r = np.where(np.logical_and(valid_s, states % n < n-1), states+1, states)
states_l = np.where(np.logical_and(valid_s, states % n > 0), states-1, states)
states_u = np.where(np.logical_and(valid_s, states > n-1), states-n, states)
states_d = np.where(np.logical_and(valid_s, states < n**2-n), states+n, states)
Another way of doing it without preallocating arrays:
states = np.arange(16).reshape(4,4)
states_l = np.hstack((states[:,0][:,None],states[:,:-1],))
states_r = np.hstack((states[:,1:],states[:,-1][:,None]))
states_d = np.vstack((states[1:,:],states[-1,:]))
states_u = np.vstack((states[0,:],states[:-1,:]))
To get them all in 1-D, you can always flatten()/ravel()/reshape(-1) the 2-D arrays.
[[ 0 1 2 3]
[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
[[ 0 0 1 2] [[ 0 1 2 3] [[ 1 2 3 3]
[ 4 4 5 6] [ 4 5 6 7] [ 5 6 7 7]
[ 8 8 9 10] [ 8 9 10 11] [ 9 10 11 11]
[12 12 13 14]] [12 13 14 15]] [13 14 15 15]]
[[ 4 5 6 7]
[ 8 9 10 11]
[12 13 14 15]
[12 13 14 15]]
And for corners you can do:
states_u[-1,-1] = 15
states_l[-1,-1] = 15

matrix: move n-th row by n position efficiently

I have a numpy 2d array and I need to transform it in a way that the first row remains the same, the second row moves by one position to right, (it can wrap around or just have zero padded to the front). Third row shifts 3 positions to the right, etc.
I can do this through a "for loop" but that is not very efficient. I am guessing there should be a filtering matrix that multipled by the original one will have the same effect, or maybe a numpy trick that will help me doing this? Thanks!
I have looked into numpy.roll() but I don't think it can work on each row separately.
import numpy as np
p = np.array([[1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16]])
'''
p = [ 1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16]
desired output:
p'= [ 1 2 3 4
0 5 6 7
0 0 9 10
0 0 0 13]
'''
We can extract sliding windows into a zeros padded version of the input to have a memory efficient approach and hence performant too. To get those windows, we can leverage np.lib.stride_tricks.as_strided based scikit-image's view_as_windows. More info on use of as_strided based view_as_windows.
Hence, the solution would be -
from skimage.util.shape import view_as_windows
def slide_by_one(p):
m,n = p.shape
z = np.zeros((m,m-1),dtype=p.dtype)
a = np.concatenate((z,p),axis=1)
w = view_as_windows(a,(1,p.shape[1]))[...,0,:]
r = np.arange(m)
return w[r,r[::-1]]
Sample run -
In [60]: p # generic sample of size mxn
Out[60]:
array([[ 1, 5, 9, 13, 17],
[ 2, 6, 10, 14, 18],
[ 3, 7, 11, 15, 19],
[ 4, 8, 12, 16, 20]])
In [61]: slide_by_one(p)
Out[61]:
array([[ 1, 5, 9, 13, 17],
[ 0, 2, 6, 10, 14],
[ 0, 0, 3, 7, 11],
[ 0, 0, 0, 4, 8]])
We can leverage the regular rampy pattern to have a more efficient approach with a more raw usage of np.lib.stride_tricks.as_strided, like so -
def slide_by_one_v2(p):
m,n = p.shape
z = np.zeros((m,m-1),dtype=p.dtype)
a = np.concatenate((z,p),axis=1)
s0,s1 = a.strides
return np.lib.stride_tricks.as_strided(a[:,m-1:],shape=(m,n),strides=(s0-s1,s1))
Another one with some masking -
def slide_by_one_v3(p):
m,n = p.shape
z = np.zeros((len(p),1),dtype=p.dtype)
a = np.concatenate((p,z),axis=1)
return np.triu(a[:,::-1],1)[:,::-1].flat[:-m].reshape(m,-1)
Here is a simple method based on zero-padding and reshaping. It is fast because it avoids advanced indexing and other overheads.
def pp(p):
m,n = p.shape
aux = np.zeros((m,n+m-1),p.dtype)
np.copyto(aux[:,:n],p)
return aux.ravel()[:-m].reshape(m,n+m-2)[:,:n].copy()

Iterate over array and make calculation on elements

I have an array that I want to sum specific elements while iterating through it. I struggle to find a way to do this with loop.
The array shape is (25,25)
array
[ 92843, 86851, 91950, 98232, 83329, 94591, 88962, 97020,
107113, 98452, 103242, 106442, 123032, 119063, 112971, 114715,
108654, 114856, 109872, 124583, 120518, 112815, 120780, 127831,
147174],
[132633, 124073, 131357, 140331, 119041, 135131, 127089, 138601,
153019, 140647, 147489, 152061, 175761, 170090, 161388, 163879,
155221, 164080, 156960, 177976, 172169, 161165, 172544, 182617,
210249],
[159159, 148887, 157629, 168397, 142849, 162157, 152507, 166321,
183623, 168776, 176986, 182473, 210913, 204108, 193665, 196655,
186265, 196896, 188352, 213571, 206602, 193398, 207052, 219140,
252298]
I want to print out results like below for each iteration
print(array[23][0]+array[23][1]) # 159159 + 148887 = 308046
print(array[22][0]+array[22][1]+array[22][2]) #132633 + 124073 + 131357 = 388063
print(array[21][0]+array[21][1]+array[21][2]+array[21][3]) # 92843 + 86851 + 91950 + 98232 = 369876
Presenting each element as array[i][j], as you can see in each iteration i - 1, and the "length" of j increased one.
Is there anyway I can use loop to do this task ? Thanks!
Try this:
for i, sub in enumerate(reversed(array)):
print(sum(sub[:i]))
For example, if
array = [[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10],
[11, 12, 13, 14, 15],
[16, 17, 18, 19, 20],
[21, 22, 23, 24, 25]]
the output would be
0 # last row, no elements summed
16 # 16 = 16
23 # 11 + 12 = 23
21 # 6 + 7 + 8 = 21
10 # 1 + 2 + 3 + 4 = 10
You may simply want the np.tril, followed by a np.sum(_, axis=0). This will give the sum of each row of the lower triangle of the matrix. Easily altered to give the upper triangle, if that's what you need.
print(np.sum(np.tril(array), axis=0))
In [661]: arr = np.arange(1,17).reshape(4,4)
In [662]: arr
Out[662]:
array([[ 1, 2, 3, 4],
[ 5, 6, 7, 8],
[ 9, 10, 11, 12],
[13, 14, 15, 16]])
In [666]: for i in range(3,-1,-1):
...: c = arr[i,:4-i]
...: print(c.sum(), c)
...:
13 [13]
19 [ 9 10]
18 [5 6 7]
10 [1 2 3 4]

Categories

Resources