just fill specific entrys of numpy array -> generating sparse matrix - python

I want to code a really big matrix with the following structure:
a = np.array([[1, 1, 1, 0, 0 ,0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 1, 1]])
Dimension of this array is (3,9) so basically the 1's depend on the dimension.
In my first row the first 3 entrys should be 1's, in my second row the entrys 3-5 should be 1's,
and so on...
How do I code this?

You can use the kronecker tensor product:
a = np.kron(np.eye(3),np.ones((1,3)))
# array([[1., 1., 1., 0., 0., 0., 0., 0., 0.],
# [0., 0., 0., 1., 1., 1., 0., 0., 0.],
# [0., 0., 0., 0., 0., 0., 1., 1., 1.]])

Related

How to pack matrices into cells and then form a diagonal matrix with python

I need to create a diagonal matrix in python from an X matrix which is repeated 3 times. In matlab I do it in the following way:
X=[1 2 3;
4 5 6;
7 8 9]
for i=1:1:3
Brep{i}=X;
end
Mdiag=blkdiag(Brep{:})
Mdiag =
1 2 3 0 0 0 0 0 0
4 5 6 0 0 0 0 0 0
7 8 9 0 0 0 0 0 0
0 0 0 1 2 3 0 0 0
0 0 0 4 5 6 0 0 0
0 0 0 7 8 9 0 0 0
0 0 0 0 0 0 1 2 3
0 0 0 0 0 0 4 5 6
0 0 0 0 0 0 7 8 9
But I don't know how to do this in Pyhton.
I would appreciate any help.
--------------------------------- ANSWER:--------------------------------------
Taking into account the answer provided by Fabrizio Bernini, I modified his code in order to do it more general. The code can now repeat the matrix X (any dimension), n times on the diagonal. For example:
import numpy as np
n=5
x = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
Mdiag = np.zeros((n*x.shape[0], n*x.shape[1]))
for i in range(n):
Mdiag[x.shape[0]*i:x.shape[0]*i+x.shape[0],x.shape[1]*i:x.shape[1]*i+x.shape[1]]= x
Mdiag =[1., 2., 3., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[7., 8., 9., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 2., 3., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 7., 8., 9., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 1., 2., 3., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 4., 5., 6., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 7., 8., 9., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 2., 3., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 4., 5., 6., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 7., 8., 9., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 2., 3.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 4., 5., 6.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 7., 8., 9.]
Thanks you all for the answers provided.
You just can use scipy.linalg.block_diag:
from scipy.linalg import block_diag
X=[[1, 2, 3],
[4,5,6],
[7, 8, 9]]
block_diag(X, X, X)
Output:
array([[1, 2, 3, 0, 0, 0, 0, 0, 0],
[4, 5, 6, 0, 0, 0, 0, 0, 0],
[7, 8, 9, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 2, 3, 0, 0, 0],
[0, 0, 0, 4, 5, 6, 0, 0, 0],
[0, 0, 0, 7, 8, 9, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 2, 3],
[0, 0, 0, 0, 0, 0, 4, 5, 6],
[0, 0, 0, 0, 0, 0, 7, 8, 9]], dtype=int32)
Another option, using np.bmat, np.asmatrix and np.asarray, could be this:
import numpy as np
X=np.asmatrix([[1, 2, 3],
[4,5,6],
[7, 8, 9]])
y = np.asmatrix(np.zeros((3, 3)))
r=np.asarray(np.bmat('X, y, y; y, X, y; y, y, X'))
print(r)
One way to do this is to create a big zero matrix and directly paste x into the diagonal locations:
N = 3
y = np.zeros((x.shape[0] * N, x.shape[1] * N))
for i in range(N):
y[i * x.shape[0] : (i + 1) * x.shape[0],
i * x.shape[1] : (i + 1) * x.shape[1]] = x
Another solution: create a horizontal "belt" of x and as many 0's as needed. Then stack three copies of that belt, shifted:
belt = np.hstack([x, np.zeros((x.shape[0], (x.shape[1] - 1) * N))])
np.vstack([np.roll(belt, i) for i in range(0, x.shape[0] * N, x.shape[0])])
You did not tag any "advanced" module (scipy, numpy, ...) so here we go:
You can create a function that does that yourself. Matrices are presented as lists of lists in python (unless you go into numpy etc.):
def diag_size(what, size = 4):
"""Create a diagonal matrix of size len(what)*size where the list of list
'what' is on the diagonal of the embiggended result"""
rv = [[]]
s = len(what) # quadratic => len(what) == len(what[0])
for row in range(size*s):
for col in range(size*s):
if row//s == col//s:
rv[-1].append(base[row%s][col%s])
else:
rv[-1].append(0)
rv.append([])
return rv[:-1]
n = 3 # size of the initial "matrix"
# create base case
base = [list(range(i+1,i+n+1)) for i in range(0,n*n,n)]
# create the diagonal one
print(*diag_size(base),sep="\n")
Output:
# with size=4 you get a 4 wide diagonal matrix
[1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[4, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 4, 5, 6, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 7, 8, 9, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 4, 5, 6, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 7, 8, 9, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 5, 6]
[0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 9]
you can do something like this using numpy:
import numpy
x = np.array([[1, 2, 3],[4, 5, 6],[7, 8, 9]])
Mdiag = np.zeros((9, 9))
for i in range(3):
Mdiag[3*i:3*i+3, 3*i:3*i+3] = x
you can also generate your initial matrix using np.reshape:
x = np.arange(1, 10)
x = x.reshape((3, 3))
More in general, if you have a nxn submatrix and want to create a MxM diagonal block matrix, where M = c*n, you can do:
import numpy
x = ... define here your nxn matrix
Mdiag = np.zeros((M, M))
for i in range(n):
Mdiag[n*i:n*i+n, n*i:n*i+n] = x
There are numpy in-built functions to copy block matrices and generate block matrices, but I am not aware of one generating a diagonal block matrix with just one command.
See also this for reference:
[1]: https://numpy.org/doc/stable/reference/generated/numpy.matlib.repmat.html#numpy.matlib.repmat and
[2]: https://numpy.org/doc/stable/reference/generated/numpy.block.html?highlight=block%20matrix
Try this code.
import numpy as np
X = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
M = np.zeros(shape = (9, 9))
for i in range(3):
M[3*i:3*(i+1), 3*i:3*(i+1)] = X

Remove all columns matching a value in Numpy

Let's suppose I have a matrix with a number of binary values:
matrix([[1., 1., 1., 0., 0.],
[0., 0., 1., 1., 1.],
[0., 0., 0., 1., 0.],
[0., 0., 0., 0., 1.]])
Using np.sum(M, 0) produces:
matrix([[1., 1., 2., 2., 2.]])
How do I remove all of the columns from the matrix that have only the value of 1?
Easier to have an array here:
M = M.A
Now using simple slicing:
M[:, np.sum(M, 0)!=1]
array([[1., 0., 0.],
[1., 1., 1.],
[0., 1., 0.],
[0., 0., 1.]])
You can convert the matrix to array. Then find the index with values 1 and then use those indexes to delete the values. For example you can do the following.
import numpy as np
M = np.matrix([[1, 1, 1, 0, 0], [0, 0, 1, 1, 1], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]])
M = np.sum(M, 0)
# conversion to array
array = np.squeeze(np.asarray(M))
index_of_elements_with_value_1 = [i for i, val in enumerate(array) if val == 1]
array = np.delete(array, index_of_elements_with_value_1)
print(array)

Create binary tensor from vector in tensorflow

I start with a 1D numpy array x (or tensorflow tensor) with N integer entries. Every entry is smaller or equal to N.
I now want to create a tensor Y of shape (N,N) (i.e. an NxN matrix) where Y[i,j]=0 if x[i]!=x[j] and Y[i,j]=1 if x[i]==x[j].
Example with numpy:
import numpy as np
x=np.array([1,2,1,2,3,4,2])
Y=np.zeros((x.shape[0],x.shape[0]))
for i in range(x.shape[0]):
for j in range(x.shape[0]):
if x[i]==x[j]:
Y[i,j]=1
Output
array([[ 1., 0., 1., 0., 0., 0., 0.],
[ 0., 1., 0., 1., 0., 0., 1.],
[ 1., 0., 1., 0., 0., 0., 0.],
[ 0., 1., 0., 1., 0., 0., 1.],
[ 0., 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 1., 0.],
[ 0., 1., 0., 1., 0., 0., 1.]])
How do I create the same function efficiently in pure tensorflow code?
And: What if I have an extra batch dimension, so that the input x has shape (B,N) and I expect as an ouput Y with shape (B,N,N). The batches are all independent of each other.
Reshape x to two different shapes, (B, 1, N) and (B, N, 1) so they can be properly broadcasted, then compare these two tensors, the result would be what you need with 1 being True and 0 being False:
import tensorflow as tf
import numpy as np
x=np.array([1,2,1,2,3,4,2])
t = tf.constant(x)
r = tf.cast(
tf.equal(
tf.reshape(t, (-1, 1, t.shape[-1].value)),
tf.reshape(t, (-1, t.shape[-1].value, 1))
), tf.int8)
sess = tf.Session()
sess.run(r)
#array([[[1, 0, 1, 0, 0, 0, 0],
# [0, 1, 0, 1, 0, 0, 1],
# [1, 0, 1, 0, 0, 0, 0],
# [0, 1, 0, 1, 0, 0, 1],
# [0, 0, 0, 0, 1, 0, 0],
# [0, 0, 0, 0, 0, 1, 0],
# [0, 1, 0, 1, 0, 0, 1]]], dtype=int8)
import tensorflow as tf
x = tf.constant([1,2,1,2,3,4,2])
x = tf.expand_dims(x, axis=0)
x = tf.tile(x, [x.shape[1], 1])
x_ = tf.transpose(x)
Y = tf.where(tf.equal(x,x_), tf.ones_like(x), tf.zeros_like(x))
There you have your vector x. You expand dims to have a matrix [1, x.shape]. Then you repeat it to have a copy of the same vector along the lines. x[i] == x[j] is therefore equivalent to x == x_ where x_ is the transposed of your matrix x.
tf.where is a conditional tensor. You give the condition (x == x_), and for each element, if it is true, it will take the first value (tf.ones_like) and if it is false it will take the second value (tf.zeros_like). Those *_like(x) functions are generating a tensor full of 0 or 1 with the same shape than x.

transform a numpy array of dimensions nx1 into a numpy array of dimensions nx10 [duplicate]

This question already has answers here:
Convert array of indices to one-hot encoded array in NumPy
(22 answers)
Closed 7 years ago.
I have a numpy array, A of size nx1 where each value is a number between 0 and 9.
I would like to create a new array, B of size nx10 such that in B[i] we store a numpy array that contains zeros and a 1 in position A[i].
For example:
A array
[[9]
[2]
[4]
[1]
[8]]
B array
[[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0]
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0]]
Is there an elegant way of doing this with numpy?
Create a new empty array using numpy.zeros, its size is going to be (arr.size, arr.max()), now fill the items on those positions using multi-dimensional indexing:
>>> arr = np.array([[9], [2], [4], [1], [8]])
>>> arr_ = np.zeros((arr.size, arr.max()))
>>> arr_[np.arange(arr.size), arr[:,0]-1] = 1
>>> arr_
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 1.],
[ 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 1., 0.]])
Something like this would do it:
A = [[9],[2],[4],[1],[8]]
B = [[1 if i == j[0] else 0 for i in range(10)] for j in A]
This is a list-based approach; you can simply use np.asarray on B to get the numpy matrix, or create a 10x10 matrix of zeros in numpy and fill 1s in the positions dictated by the A array.
The latter generalises to the case where A's elements might have more than one item.
You could do something like this, assuming an NP Nx1 array of X:
max_val = max(X)
length_arr = len(X)
new_arr = np.zeros((max_val,length_arr))
This will create the array of the right size that you want.
for i in range(len(X)):
new_arr[i][X[i]-1]=1
Should then assign the correct values in place?
Works fine in my test case.

Python function to expand image (NumPy array)

Say I have a greyscale image that is 3x3 and is represented by the numpy array below.
I want to increase the size and resolution of the image, similar to a resizing function in a normal picture editing software, but I don't want it to change any of the values of the pixels, just to expand them.
Is there a Python function that does the following conversion?
[0,0,0]
[0,1,0]
[0,0,0]
---->
[0,0,0,0,0,0]
[0,0,0,0,0,0]
[0,0,1,1,0,0]
[0,0,1,1,0,0]
[0,0,0,0,0,0]
[0,0,0,0,0,0]
You could use np.repeat along both axes of the 3x3 img array:
>>> img.repeat(2, axis=0).repeat(2, axis=1)
array([[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 0],
[0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0]])
Another way is to calculate the Kronecker product of img and an array of the appropriate shape filled with ones:
>>> np.kron(img, np.ones((2,2)))
array([[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 1., 1., 0., 0.],
[ 0., 0., 1., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0.]])
Here's a link to the documentation for np.kron:
So in the example above, each value x in img is multiplied by a 2x2 array of ones to create a 2x2 array of x values. These new 2x2 arrays make up the returned array.
This multiplication might be slower than simply repeating, however.

Categories