I would like to change diagonal elements from a 2d matrix. These are both main and non-main diagonals.
numpy.diagonal()
In NumPy 1.10, it will return a read/write view, Writing to the returned
array will alter your original array.
numpy.fill_diagonal(), numpy.diag_indices()
Only works with main-diagonal elements
Here is my use case: I want to recreate a matrix of the following form, which is very trivial using diagonal notation given that I have all the x, y, z as arrays.
Try this:
>>> A = np.zeros((6,6))
>>> i,j = np.indices(A.shape)
>>> z = [1, 2, 3, 4, 5]
Now you can intuitively access any diagonal:
>>> A[i==j-1] = z
>>> A
array([[ 0., 1., 0., 0., 0., 0.],
[ 0., 0., 2., 0., 0., 0.],
[ 0., 0., 0., 3., 0., 0.],
[ 0., 0., 0., 0., 4., 0.],
[ 0., 0., 0., 0., 0., 5.],
[ 0., 0., 0., 0., 0., 0.]])
In the same way you can assign arrays to A[i==j], etc.
You could always use slicing to assign a value or array to the diagonals.
Passing in a list of row indices and a list of column indices lets you access the locations directly (and efficiently). For example:
>>> z = np.zeros((5,5))
>>> z[np.arange(5), np.arange(5)] = 1 # diagonal is 1
>>> z[np.arange(4), np.arange(4) + 1] = 2 # first upper diagonal is 2
>>> z[np.arange(4) + 1, np.arange(4)] = [11, 12, 13, 14] # first lower diagonal values
changes the array of zeros z to:
array([[ 1., 2., 0., 0., 0.],
[ 11., 1., 2., 0., 0.],
[ 0., 12., 1., 2., 0.],
[ 0., 0., 13., 1., 2.],
[ 0., 0., 0., 14., 1.]])
In general for a k x k array called z, you can set the ith upper diagonal with
z[np.arange(k-i), np.arange(k-i) + i]
and the ith lower diagonal with
z[np.arange(k-i) + i, np.arange(k-i)]
Note: if you want to avoid calling np.arange several times, you can simply write ix = np.arange(k) once and then slice that range as needed:
np.arange(k-i) == ix[:-i]
Here is another approach just for fun. You can write your own diagonal function to return of view of the diagonal you need.
import numpy as np
def diag(a, k=0):
if k > 0:
a = a[:, k:]
elif k < 0:
a = a[-k:, :]
shape = (min(a.shape),)
strides = (sum(a.strides),)
return np.lib.stride_tricks.as_strided(a, shape, strides)
a = np.arange(20).reshape((4, 5))
diag(a, 2)[:] = 88
diag(a, -2)[:] = 99
print(a)
# [[ 0 1 88 3 4]
# [ 5 6 7 88 9]
# [99 11 12 13 88]
# [15 99 17 18 19]]
Related
Let's say I have the following code:
# define a 3x3 array
A = np.array([[-2, 1, 1], [1,-2,1], [1,1,-2]])
# define a 1D array of scalars to multiply A with
test = np.arange(10)
for i in range(len(test)):
matrix = scipy.linalg.expm(A*test[i])
I want to see if there is a way to do this multiplication without using a for loop. I am not trying to multiply the two arrays using matrix multiplication. I am treating the test array as a bank of scalar values that I want to multiply A with one by one. There has got to be some kind of sneaky numpy way of doing this. Any ideas?
Here's an answer to the question "how to scale a matrix by multiple scalars without a for-loop". This disregards the matrix exponentiation, since I don't think there's a way to do that without the for-loop, but the question doesn't seem to be asking about the exponentiation step.
You can use 3D arrays to use numpy's vectorized multiplication.
import numpy as np
A = np.array([[[-2, 1, 1], [1,-2,1], [1,1,-2]]])
test = np.arange(10).reshape(-1,1,1)
result = test*A
scipy.linalg.expm cannot be applied with a not squared matrix:
ValueError: expected a square matrix
so I think the easiest thing is to do:
list_result = list(map(lambda i: scipy.linalg.expm(A*i), range(10)))
An then if you want only one array:
np.concatenate(list_result) #for 2D
or
np.stack(list_result) #for 3D
You can do the trick building a special matrix by stacking the identity matrix multiplied by the values you want to use.
I will use a 3x3 matrix as an example, but the idea is the same for an arbitrary matrix:
Imagine we want to multiply the matrix:
A = np.array([
[1,0,1],
[0,1,0],
[0,0,1]
])
By [2, 3, and 5]. Without loops.
We can build a special matrix contatenating the identity to do this:
[ 2 * np.eye(3), 3 * np.eye(3), 5 * np.eye(3)]
[ 0 0 2 ] [ 0 0 3] [ 0 0 5 ]
[ 0 2 0 ] [ 0 3 0] [ 0 5 0 ]
[ 2 0 0 ] [ 3 0 0] [ 5 0 0 ]
We can do this with a list comprehension:
multiply_values = [2,3,5]
special_matrix = np.concatenate( [ x * eye(3) for x in multiply_values ], axis=1)
# special_matrix is:
# array([[2., 0., 0., 3., 0., 0., 5., 0., 0.],
# [0., 2., 0., 0., 3., 0., 0., 5., 0.],
# [0., 0., 2., 0., 0., 3., 0., 0., 5.]])
Now we can multiply the matrix in one step:
result = np.dot( , special_matrix)
# result is
array([[2., 0., 0., 3., 0., 0., 5., 0., 0.],
[0., 2., 0., 0., 3., 0., 0., 5., 0.],
[0., 0., 2., 0., 0., 3., 0., 0., 5.]])
Probably this large wide matrix is not what we need.
We can get the partial results slicing the resulting product:
result[:,0:3]
# array([[2., 0., 2.],
# [0., 2., 0.],
# [0., 0., 2.]])
We can process the slices with another comprehension:
[ special_matrix[:,x:x+3] for x in [0,3,6] ]
# or in a more general way
[ special_matrix[:,x:x+A.shape[0]] for x in list(range(0,A.shape[0]**2,A.shape[0] ]
I have the following list of indices [2 4 3 4] which correspond to my target indices. I'm creating a matrix of zeroes with the following line of code targets = np.zeros((features.shape[0], 5)). Im wondering if its possible to slice in such a way that I could update the specific indices all at once and set those values to 1 without a for loop, ideally the matrix would look like
([0,0,1,0,0], [0,0,0,0,1], [0,0,0,1,0], [0,0,0,0,1])
I believe you can do something like this:
targets = np.zeros((4, 5))
ind = [2, 4, 3, 4]
targets[np.arange(0, 4), ind] = 1
Here is the result:
array([[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 1.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.]])
I have a sparse 2D matrix, typically something like this:
test
array([[ 1., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 2., 1., 0.],
[ 0., 0., 0., 1.]])
I'm interested in all nonzero elements in "test"
index = numpy.nonzero(test) returns a tuple of arrays giving me the indices for the nonzero elements:
index
(array([0, 2, 2, 3]), array([0, 1, 2, 3]))
For each row I would like to print out all the nonzero elements, but skipping all rows containing only zero elements.
I would appreciate hints for this.
Thanks for the hints. This solved the problem:
>>> test
array([[ 1., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 2., 1., 0.],
[ 0., 0., 0., 1.]])
>>> transp=np.transpose(np.nonzero(test))
>>> transp
array([[0, 0],
[2, 1],
[2, 2],
[3, 3]])
>>> for index in range(len(transp)):
row,col = transp[index]
print 'Row index ',row,'Col index ',col,' value : ', test[row,col]
giving me:
Row index 0 Col index 0 value : 1.0
Row index 2 Col index 1 value : 2.0
Row index 2 Col index 2 value : 1.0
Row index 3 Col index 3 value : 1.0
Given
rows, cols = np.nonzero(test)
you could also use so-called advanced integer indexing:
test[rows, cols]
For example,
test = np.array([[ 1., 0., 0., 0.],
[ 0., 0., 0., 0.],
[ 0., 2., 1., 0.],
[ 0., 0., 0., 1.]])
rows, cols = np.nonzero(test)
print(test[rows, cols])
yields
array([ 1., 2., 1., 1.])
Use array indexing:
test[test != 0]
There is no array operation to do this per-row (instead of for the entire matrix), as that would return a variable number of elements per row. You can use something like
[row[row != 0] for row in test]
to achieve that.
Just wondering if there is an off-the-shelf function to perform the following operation; given a matrix X, holding labels (that can be assumed to be integer numbers 0-to-N) in each entry e.g.:
X = [[0 1 1 2 2 3 3 3],
[0 1 1 2 2 3 3 4],
[0 1 5 5 5 5 3 4]]
I want its adjacency matrix G i.e. G[i,j] = 1 if i,j are adjacent in X and 0 otherwise.
For example G[1,2] = 1, because 1,2 are adjacent in (X[0,2],X[0,3]), (X[1,2],X[1,3]) etc..
The naive solution is to loop through all entries and check its neighbors, but I'd rather avoid loops for performance reason.
You can use fancy indexing to assign the values of G directly from your X array:
import numpy as np
X = np.array([[0,1,1,2,2,3,3,3],
[0,1,1,2,2,3,3,4],
[0,1,5,5,5,5,3,4]])
G = np.zeros([X.max() + 1]*2)
# left-right pairs
G[X[:, :-1], X[:, 1:]] = 1
# right-left pairs
G[X[:, 1:], X[:, :-1]] = 1
# top-bottom pairs
G[X[:-1, :], X[1:, :]] = 1
# bottom-top pairs
G[X[1:, :], X[:-1, :]] = 1
print(G)
#array([[ 1., 1., 0., 0., 0., 0.],
# [ 1., 1., 1., 0., 0., 1.],
# [ 0., 1., 1., 1., 0., 1.],
# [ 0., 0., 1., 1., 1., 1.],
# [ 0., 0., 0., 1., 1., 0.],
# [ 0., 1., 1., 1., 0., 1.]])
Example:
given a random list, say a1 = [1.5], or a2=[2,3,-1], or a3=[5,6,7,2,3,1]
How can you fill the lower triangle of a corresponding matrix, like so...
array([[ 1., 0., 0.],
[ 0., 1., 0.],
[ 0., 0., 1.]])
to
array([[ 1., 0., 0.],
[ 2., 1., 0.],
[ 3., -1., 1.]])
or,
array([[ 1.,0.],
[ 0, 1.]])
to
array([[ 1.,0.],
[ 1.5, 1.]])
I tried several times to solve this problem but my code is very complicated and ultimately wrong. Even worse I can't paste the code without getting an error saying my formatting is wrong. Here is a picture of part of the code.
I can't post a picture because I dont have the needed reputation points.
CODE WORKS NOW! Look below!
# n is the length of your list (i.e. n =len(numbers))
for j in range(n-1):
for i in range(1+j,n):
matrix[i][j]=numbers.pop(0)
You could use numpy.tril_indices or numpy.triu_indices, depending on how you want to order the entries. The following example will additionally take care not to set diagonal entries:
import numpy as np
size = 4
m = np.eye(size) # identity matrix
j, i = np.triu_indices(size, 1)
the_list = np.arange(size * (size - 1) / 2)[::-1] + 1 # The list of entries
print the_list # yields [6, 5, 4, 3, 2, 1]
# Set the entries
m[i, j] = the_list
print m
# yields
# array([[ 1., 0., 0., 0.],
# [ 6., 1., 0., 0.],
# [ 5., 3., 1., 0.],
# [ 4., 2., 1., 1.]])
Note that if you want to set in line order, you can use i, j = np.tril_indices(size, -1). If you would like to set the diagonal as well, then remove the second argument in np.triu_indices.