Fill a matrix from a matrix of indices - python

I want to fill a matrix from an array of indices :
import numpy as np
indx = [[0,1,2],[1,2,4],[0,1,3],[2,3,4],[0,3,4]]
x = np.zeros((5,5))
for i in range(5):
x[i,indx[i]] = 1.
The result is :
array([[ 1., 1., 1., 0., 0.],
[ 0., 1., 1., 0., 1.],
[ 1., 1., 0., 1., 0.],
[ 0., 0., 1., 1., 1.],
[ 1., 0., 0., 1., 1.]])
As desired.
Question
Is there a way to do this in pure python/numpy without looping ?

Use advanced-indexing after intialization -
x[np.arange(len(indx))[:,None], indx] = 1

Related

Generate all n choose k binary vectors python

Is there any efficient way (numpy style) to generate all n choose k binary vectors (with k ones)?
for example, if n=3 and k=2, then I want to generate (1,1,0), (1,0,1), (0,1,1).
Thanks
I do not know how efficient this is, but here is a way:
from itertools import combinations
import numpy as np
n, k = 5, 3
np.array(
[
[1 if i in comb else 0 for i in range(n)]
for comb in combinations(np.arange(n), k)
]
)
>>>
array([[1., 1., 1., 0., 0.],
[1., 1., 0., 1., 0.],
[1., 1., 0., 0., 1.],
[1., 0., 1., 1., 0.],
[1., 0., 1., 0., 1.],
[1., 0., 0., 1., 1.],
[0., 1., 1., 1., 0.],
[0., 1., 1., 0., 1.],
[0., 1., 0., 1., 1.],
[0., 0., 1., 1., 1.]])

How to fill numpy array of zeros with ones given indices/coordinates

Given a numpy array of zeros, say
arr = np.zeros((5, 5))
and an array of indices that represent vertices of a polygon, say
verts = np.array([[0, 2], [2, 0], [2, 4]])
1) What is the elegant way of doing
for v in verts:
arr[v[0], v[1]] = 1
such that the resulting array is
In [108]: arr
Out[108]:
array([[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 1., 0., 0., 0., 1.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
2) How can I fill the array with ones such that the output array is
In [158]: arr
Out[158]:
array([[ 0., 0., 1., 0., 0.],
[ 0., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
To answer the first part of your question: arr[tuple(verts.T)] = 1
verts.T transposes your indices to a (2, n) array, where the two rows correspond to the row and column dimensions of arr. These are then unpacked into a tuple of (row_indices, col_indices), which we then use to index into arr.
We could write this a bit more verbosely as:
row_indices = verts[:, 0]
col_indices = verts[:, 1]
arr[row_indices, col_indices] = 1
For the second part, one method that will work for arbitrary polygons would be to use matplotlib.Path.contains_points, as described here:
from matplotlib.path import Path
points = np.indices(arr.shape).reshape(2, -1).T
path = Path(verts)
mask = path.contains_points(points, radius=1e-9)
mask = mask.reshape(arr.shape).astype(arr.dtype)
print(repr(mask))
# array([[ 0., 0., 1., 0., 0.],
# [ 0., 1., 1., 1., 0.],
# [ 1., 1., 1., 1., 1.],
# [ 0., 0., 0., 0., 0.],
# [ 0., 0., 0., 0., 0.]])

Numpy: Replace every n element in the first half of an array

If I have a numpy array and want to replace every nth element to 0 in the first half of the array( no change in the second half), how can I do this efficiently? Now my code is not efficient enough:
for i in xrange(1,half,n):
s[i] = 0
Just use a[:a.size//2:n] = 0. e.g.:
a = np.ones(10)
a[:a.size//2:2] = 0
a
array([ 0., 1., 0., 1., 0., 1., 1., 1., 1., 1.])
Another example:
a = np.ones(20)
n = 3
a[:a.size//2:n] = 0
a
array([ 0., 1., 1., 0., 1., 1., 0., 1., 1., 0., 1., 1., 1.,
1., 1., 1., 1., 1., 1., 1.])
You could slice the array by doing something like:
import numpy as np
# make an array of 11 elements filled with zeros
my_arr = np.zeros(11)
# get indexes to change in the array. range is: range(start, stop[, step])
a = range(0, 5, 2)
# print the original array
print my_arr
# Change the array
my_arr[a] = 1
# print the changes
print my_arr
Outputs:
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
array([ 0., 1., 0., 1., 0., 0., 0., 0., 0., 0., 0.])

"Trailing" One-Hot Encode

I am trying to do something similar to One-Hot-Encoding but instead of the selected class being 1 and the rest zero, I want all the classes up to (and including the selected class) to be 1. Say I have a training batch with labels (5 possible class labels; 0, 1, 2, 3, 4)
y = np.array([0,2,1,3,4,1])
I can one-hot-encode with
def one_hot_encode(arr, num_classes):
return np.eye(num_classes)[arr]
which gives
>>> one_hot_encode(y, 5)
array([[ 1., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 1., 0., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.],
[ 0., 1., 0., 0., 0.]])
I liked to get
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])
Anyone know how to do this?
You could achieve this by using a lower-triangular matrix instead of an identity matrix in your function definition:
def many_hot_encode(arr, num_classes):
return np.tril(np.ones(num_classes))[arr]
many_hot_encode(y,5)
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])
You can also use broadcasting -
out = (y[:,None] >= np.arange(num_classes)).astype(float)
Sample run -
In [71]: y = np.array([0,2,1,3,4,1])
In [72]: num_classes = 5
In [73]: (y[:,None] >= np.arange(num_classes)).astype(float)
Out[73]:
array([[ 1., 0., 0., 0., 0.],
[ 1., 1., 1., 0., 0.],
[ 1., 1., 0., 0., 0.],
[ 1., 1., 1., 1., 0.],
[ 1., 1., 1., 1., 1.],
[ 1., 1., 0., 0., 0.]])

Scipy boundary conditions on a sparse matrix pattern

My system is best described by a diagonal sparse matrix (Poisson). I have my diagonal sparse matrix, however, I want to change the boundary conditions (ie the "edges" of my matrix) to zero. It must be a common situation where a modeler wants to describe a system in a sparse diagonal matrix with distinct boundary conditions, is there a best practice for doing this?
[[0,0,0,0,..0],
[0,2,1,0,..0],
[0,1,2,1,..0],
...
[0,0,0,0,..0]]
It depends on which sparse matrix format you use. Apparently lil_matrix and dok_matrix can use slice assignments.
To construct a matrix efficiently, use either lil_matrix (recommended)
or dok_matrix. The lil_matrix class supports basic slicing and fancy
indexing with a similar syntax to NumPy arrays.
Which makes this rather easy:
In : x = scipy.sparse.lil_matrix(np.ones((6,6)))
In : x.todense()
Out:
matrix([[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.],
[ 1., 1., 1., 1., 1., 1.]])
In : x[:, 0] = 0
In : x[:, -1] = 0
In : x[0, :] = 0
In : x[-1, :] = 0
In : x.todense()
Out:
matrix([[ 0., 0., 0., 0., 0., 0.],
[ 0., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 0.],
[ 0., 1., 1., 1., 1., 0.],
[ 0., 0., 0., 0., 0., 0.]])
PS: FYI, your matrix is called tridiagonal, not diagonal.

Categories

Resources