I am attempting to iteratively create a block matrix within a for loop in python. Is there a way to use simple indexing in which the index corresponds to the matrix index instead of a scalar index. For example, imagine the following as two 2x2 matrices in a block matrix:
4 5 6 7
1 2 3 4
Is there a way to index the sub-matrices such that:
block_matrix[0,0] =
4 5
1 2
block_matrix[0,1] =
6 7
3 4
My end goal is to have a for loop to stack these. For example:
for i in range(3):
for j in range(3):
mat = single_matrix
block_matrix[i,j] = mat
block_matrix =
matrix_1_1 matrix_1_2 matrix_1_3
matrix_2_1 matrix_2_2 matrix_2_3
matrix_3_1 matrix_3_2 matrix_3_3
Using numpy with slicing would be one good way to go.
import numpy as np
block_matrix = np.zeros((9,9)) # shape (9,9)
mat = np.reshape(np.arange(9), (3,3)) # shape (3,3)
for i in range(3):
for j in range(3):
block_matrix[i*3:i*3+3,j*3:j*3+3] = mat
# block_matrix =
# mat mat mat
# mat mat mat
# mat mat mat
There, of course I just created a simple matrix of shape (3,3) and used it for all sub-parts of block_matrix but I hope you get the gist.
I believe the functions you want are numpy.reshape and numpy.swapaxes
https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html
https://docs.scipy.org/doc/numpy/reference/generated/numpy.swapaxes.html
import numpy as np
a = np.array([[4,5,6,7],[1,2,3,4]])
b = np.reshape(a, (2,2,2), order="C")
c = np.swapaxes(b, 0, 1)
print(c)
Output:
[[[4 5]
[1 2]]
[[6 7]
[3 4]]]
Edit
Here is a version that should work for your case, including what the loop does:
import numpy as np
a = np.random.random((6,6))
b = np.reshape(a, (3,2,3,2), order="C")
c = np.swapaxes(b, 2, 1)
print(a)
print(c[0,1])
Output:
[[0.14413028 0.32553884 0.84321485 0.52101265 0.39548678 0.04210311]
[0.06844168 0.37270808 0.0523836 0.66408026 0.29857363 0.9086674 ]
[0.30052066 0.85342026 0.42354871 0.20516629 0.47962509 0.31865669]
[0.92307636 0.36024872 0.00109126 0.66277798 0.70634145 0.02647658]
[0.18408546 0.79832633 0.92462421 0.8060224 0.51464245 0.88324207]
[0.24439081 0.61620587 0.66114919 0.50045374 0.93085541 0.85732735]]
[[0.84321485 0.52101265]
[0.0523836 0.66408026]]
Related
In python, how to write program that create two 4 * 4 matrices A and B whose elements are random numbers. Then create a matrix C that looks like
C = ⎡A B⎤
⎣B A⎦
Find the diagonal of the matrix C. The diagonal elements are to be presented in a 4 * 2 matrix.
import numpy as np
matrix_A = np.random.randint(10, size=(4, 4))
matrix_B = np.random.randint(10, size=(4, 4))
matrix_C = np.array([[matrix_A, matrix_B], [matrix_B, matrix_A]])
d= matrix_C.diagonal()
D=d.reshape(2,4)
print(f'This is matrix C:\n{matrix_C}')
print(f'These are the diagonals of Matrix C:\n{D}')
The construction
matrix_C = np.array([[matrix_A, matrix_B], [matrix_B, matrix_A]])
does not concatenate matrices, but creates 4th order tensor (put matrices inside matrix). You can check that by
print(matrix_C.shape) # (2, 2, 4, 4)
To lay out blocks call np.block, then all other parts of your code should work fine:
matrix_C = np.block([[matrix_A, matrix_B], [matrix_B, matrix_A]])
print(matrix_C.shape) # (8, 8)
d= matrix_C.diagonal()
D=d.reshape(2,4) # np.array([matrix_A.diagonal(), matrix_A.diagonal()])
How can I select specific rows, where these rows equal to another row in another parallel array?
in other words; can I vectorize code? here p, y are ndarray withe the same shape
for inx,val in enumerate(p):
if val ==y[inx]:
pprob.append(1)
else:
pprob.append(0)
I just ran this in a python shell in Python 3.9.4
import numpy as np
x = np.array([1,2,3,4,5])
y = np.array([1,1,3,3,5])
matching_idx = np.where(x == y) # (array([0, 2, 4]),)
x[matching_idx] # array([1, 3, 5])
Seems like x[matching_idx] is what you want
The key to this is np.where(), explained here
import numpy as np
a = np.random.normal(size=(10, 5))
b = np.random.normal(size=(10, 5))
a[1] = b[1]
a[7] = b[7]
rows = np.all(a == b, axis=1).astype(np.int32)
rows = rows.tolist() # if you really want the result to be a list
print(rows)
Result as expected
[0 1 0 0 0 0 0 1 0 0]
If you could be dealing with more than two dimensions, change the following (works for 2d as well):
# this
np.all(a == b, axis=1)
# to this
np.all(a == b, axis=tuple(range(len(a.shape)))[1:])
Consider a NumPy array of shape (8, 8).
My Question: What is the index (x,y) of the 50th element?
Note: For counting the elements go row-wise.
Example, in array A, where A = [[1, 5, 9], [3, 0, 2]] the 5th element would be '0'.
Can someone explain how to find the general solution for this and, what would be the solution for this specific problem?
You can use unravel_index to find the coordinates corresponding to the index of the flattened array. Usually np.arrays start with index 0, you have to adjust for this.
import numpy as np
a = np.arange(64).reshape(8,8)
np.unravel_index(50-1, a.shape)
Out:
(6, 1)
In a NumPy array a of shape (r, c) (just like a list of lists), the n-th element is
a[(n-1) // c][(n-1) % c],
assuming that n starts from 1 as in your example.
It has nothing to do with r. Thus, when r = c = 8 and n = 50, the above formula is exactly
a[6][1].
Let me show more using your example:
from numpy import *
a = array([[1, 5, 9], [3, 0, 2]])
r = len(a)
c = len(a[0])
print(f'(r, c) = ({r}, {c})')
print(f'Shape: {a.shape}')
for n in range(1, r * c + 1):
print(f'Element {n}: {a[(n-1) // c][(n-1) % c]}')
Below is the result:
(r, c) = (2, 3)
Shape: (2, 3)
Element 1: 1
Element 2: 5
Element 3: 9
Element 4: 3
Element 5: 0
Element 6: 2
numpy.ndarray.faltten(a) returns a copy of the array a collapsed into one dimension. And please note that the counting starts from 0, therefore, in your example 0 is the 4th element and 1 is the 0th.
import numpy as np
arr = np.array([[1, 5, 9], [3, 0, 2]])
fourth_element = np.ndarray.flatten(arr)[4]
or
fourth_element = arr.flatten()[4]
the same for 8x8 matrix.
First need to create a 88 order 2d numpy array using np.array and range.Reshape created array as 88
In the output you check index of 50th element is [6,1]
import numpy as np
arr = np.array(range(1,(8*8)+1)).reshape(8,8)
print(arr[6,1])
output will be 50
or you can do it in generic way as well by the help of numpy where method.
import numpy as np
def getElementIndex(array: np.array, element):
elementIndex = np.where(array==element)
return f'[{elementIndex[0][0]},{elementIndex[1][0]}]'
def getXYOrderNumberArray(x:int, y:int):
return np.array(range(1,(x*y)+1)).reshape(x,y)
arr = getXYOrderNumberArray(8,8)
print(getElementIndex(arr,50))
I am trying to create a random square matrix of nxn random numbers with numpy. Of course I am able to generate enough random numbers but I am having trouble using numpy to create a matrix of variable length. This is as far as I have gotten thus far:
def testMatrix(size):
a = []
for i in range(0, size*size):
a.append(randint(0, 5))
How can I put this list into an array of size x size?
Try
np.random.randint(0, 5, size=(s, s))
Your test matrix is currently one dimensional. If you want to create a random matrix with numpy, you can just do:
num_rows = 3
num_columns = 3
random_matrix = numpy.random.random((num_rows, num_columns))
The result would be:
array([[ 0.15194989, 0.21977027, 0.85063633],
[ 0.1879659 , 0.09024749, 0.3566058 ],
[ 0.18044427, 0.59143149, 0.25449112]])
You can also create a random matrix without numpy:
import random
num_rows = 3
num_columns = 3
random_matrix = [[random.random() for j in range(num_rows)] for i in range(num_columns)]
The result would be:
[[0.9982841729782105, 0.9659048749818827, 0.22838327707784145],
[0.3524666409224604, 0.1918744765283834, 0.7779130503458696],
[0.5239230720346117, 0.0224389713805887, 0.6547162177880549]]
Per the comments, I've added a function to convert a one dimensional array to a matrix:
def convert_to_matrix(arr, chunk_size):
return [arr[i:i+chunk_size] for i in range(0, len(arr), chunk_size)]
arr = [1,2,3,4,5,6,7,8,9]
matrix = convert_to_matrix(arr, 3)
# [[1, 2, 3], [4, 5, 6], [7, 8, 9]] is the output
How do I use the numpy accumulator and add functions to add arrays column wise to make a basic accumulator?
import numpy as np
a = np.array([1,1,1])
b = np.array([2,2,2])
c = np.array([3,3,3])
two_dim = np.array([a,b,c])
y = np.array([0,0,0])
for x in two_dim:
y = np.add.accumulate(x,axis=0,out=y)
return y
actual output: [1,2,3]
desired output: [6,6,6]
numpy glossary says the sum along axis argument axis=1 sums over rows: "we can sum each row of an array, in which case we operate along columns, or axis 1".
"A 2-dimensional array has two corresponding axes: the first running vertically downwards across rows (axis 0), and the second running horizontally across columns (axis 1)"
With axis=1 I would expect output [3,6,9], but this also returns [1,2,3].
Of Course! neither x nor y are two-dimensional.
What am I doing wrong?
I can manually use np.add()
aa = np.array([1,1,1])
bb = np.array([2,2,2])
cc = np.array([3,3,3])
yy = np.array([0,0,0])
l = np.add(aa,yy)
m = np.add(bb,l)
n = np.add(cc,m)
print n
and now I get the correct output, [6,6,6]
I think
two_dim.sum(axis=0)
# [6 6 6]
will give you what you want.
I don't think accumulate is what you're looking for as it provides a running operation, so, using add it would look like:
np.add.accumulate(two_dim)
[[1 1 1]
[3 3 3] # = 1+2
[6 6 6]] # = 1+2+3
reduce is more like what you've descibed:
np.add.reduce(two_dim)
[6 6 6]