Python: Fill out edges of binary array - python

I'm using the following code to generate an array based on coordinates of edges:
verts = np.array(list(itertools.product((0,2), (0,2))))
arr = np.zeros((5, 5))
arr[tuple(verts.T)] = 1
plt.imshow(arr)
which gives me
or, as a numeric array:
[[1., 0., 1., 0., 0.],
[0., 0., 0., 0., 0.],
[1., 0., 1., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]
Now, I would like to fill out the spaces in between the corners (ie. yellow squares):
so that I get the following array:
[[1., 1., 1., 0., 0.],
[1., 1., 1., 0., 0.],
[1., 1., 1., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]

Replace (0,2) using range(0,3) (3 as ranges are inclusive-exclusive) that is
import itertools
import numpy as np
verts = np.array(list(itertools.product(range(0,3), range(0,3))))
arr = np.zeros((5, 5))
arr[tuple(verts.T)] = 1
print(arr)
output
[[1. 1. 1. 0. 0.]
[1. 1. 1. 0. 0.]
[1. 1. 1. 0. 0.]
[0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0.]]

Related

how to access a matrix and increase specific column?

For example, I have this matrix, and I need to access the second column and increase it by 2:
m = [[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
You can do that just by accessing the 2nd column and incrementing the value. You can do that by doing this : m[:, 1] = m[:, 1] + 2
It means that you are ignoring all the rows and specifying the columns. Here, 1 refers to the 2nd column.
You can do this by using numpy library which allows you to easily do such thing.
Import numpy as import numpy as np
Convert the 2d list into numpy array
m = np.array([
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]
])
Now apply the conditioning
m[:, 1] = m[:, 1] + 2
Print the output.
print("M: ", m)
Combined Code:
import numpy as np
m = np.array([
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]
])
m[:, 1] = m[:, 1] + 2
print("M: ", m)
So, you need to increase the second element of each row by 2. You could achieve this by a for loop.
for row in m:
row[1] += 2
You could convert the matrix into a numpy array. Just in case you're looking at exploiting the optimisations that this library offers
import numpy as np
m = np.array([
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]
])
m[:, 1] += 1

Creating a pattern in an array

I have an array:
import numpy as np
arr = np.zeros(15)
And a pattern [1,2,3] that needs to be learned.
Meaning, I'd like the array to have this pattern.
The difficulty is learning a function that outputs this pattern, or as close as possible, given any pattern or array.
Currently I have the function hard coded:
def rule(array, item_idx):
try:
left_nbr = array[item_idx-1]
right_nbr = array[item_idx+1]
if left_nbr == 0 and right_nbr == 0:
array[item_idx] = 1
if arr[item_idx] == 0 and left_nbr == 1:
array[item_idx] = 2
if arr[item_idx] == 0 and left_nbr == 2:
array[item_idx] = 3
if arr[item_idx] == 0 and left_nbr == 3:
array[item_idx] = 1
except IndexError:
pass
return array
for i in range (0,len(arr)):
arr = rule(arr, i)
print(arr)
>>>
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 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.]
[1. 2. 3. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 0. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 0. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 0. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 0. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 3. 0. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 0. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 0.]
[1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 3. 1. 2. 0.]
Is there a way to have a machine learning model that learns the rules (i.e. replace the function rule) to output the pattern? That is, instead of me hard coding the rules.
Update 1:
I tried creating a model using PyTorch but it doesn't seem to be able to learn the pattern (the loss doesn't decrease at all):
import torch
import torch.nn as nn
pattern = torch.tensor([1,2,3,1,2,3,1,2,3,1])
def custom_loss(output, target):
loss = torch.tensor(target - output).sum()
loss.requires_grad = True
return loss
model = torch.nn.Sequential(
torch.nn.Linear(3,1)
)
learning_rate = 1e-3
optimizer = torch.optim.RMSprop(model.parameters(), lr=learning_rate)
for t in range(2000):
x = torch.zeros(10)
for i in range (0,len(pattern)):
try:
left_nbr = x[i-1]
center = x[i]
right_nbr = x[i+1]
output = model(torch.tensor([left_nbr, center, right_nbr]))
x[i] = int(output)
except IndexError:
pass
loss = custom_loss(x, pattern)
if t % 100 == 0:
print(t, loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
Problem
I observed that the prediction has never changed.
output = model(torch.tensor([left_nbr, center, right_nbr]))
x[i] = int(output)
...
loss = custom_loss(x, pattern)
I observed that output < 1, and thus, int(output) == 0.
So, it seems like that your target to compute loss against is always [0, ..., 0].
loss will never change because predictions are always the same.
Additionally, I am not sure what you want to do, however, it would be better to use your model's output as input for a loss function.
Quick Fix
Deep learning is good for classification, rather than regression, based on its ability to deeply extract features.
Check this how model predicts numbers written in images. It does not predict a real number of the range [0, 9], instead, it predicts fixed number of real numbers of the range [0, 1], thus, something like [0.1, ..., 0.9]. The position itself of the highest number is the number, thus class.
So, try the following code. This is how we usually use PyTorch.
data = [
([1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0.]),
([1., 2., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1.]),
([1., 2., 3., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [1., 0., 0.]),
([1., 2., 3., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0.]),
([1., 2., 3., 1., 2., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1.]),
([1., 2., 3., 1., 2., 3., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [1., 0., 0.]),
([1., 2., 3., 1., 2., 3., 1., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 1., 0.]),
([1., 2., 3., 1., 2., 3., 1., 2., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 0., 0., 0., 0., 0., 0.], [1., 0., 0.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 0., 0., 0., 0., 0.], [0., 1., 0.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 0., 0., 0., 0.], [0., 0., 1.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 3., 0., 0., 0.], [1., 0., 0.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 0., 0.], [0., 1., 0.]),
([1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 3., 1., 2., 0.], [0., 0., 1.]),
]
if __name__ == '__main__':
model = torch.nn.Sequential(
torch.nn.Linear(15, 30),
nn.Sigmoid(),
torch.nn.Linear(30, 10),
nn.Sigmoid(),
torch.nn.Linear(10, 3),
nn.Sigmoid()
)
learning_rate = 1e-3
optimizer = torch.optim.RMSprop(model.parameters(), lr=learning_rate)
mse = nn.MSELoss()
for t in range(10000):
X, y = random.choice(data)
output = model(torch.tensor(X, requires_grad=False))
loss = mse(output, torch.tensor(y, requires_grad=False))
if t % 100 == 0:
print(t, loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
Better Fix
Since your input is a sequence, you would better use Recurrent Neural Network (RNN).

Accessing matrix in Python by an array of indices [duplicate]

This question already has answers here:
Numpy extract submatrix
(6 answers)
How to create a sub-matrix in numpy
(2 answers)
Closed 2 years ago.
I'm relatively new to Python and would appreciate your help!
Suppose I have two square matrices - one large M and one smaller K - and an integer array of indices ind, not necessarily sorted. The length of ind matches the dimensions of K. In Octave/MATLAB, I can easily do this:
M(ind, ind) = K
This will distribute all the components of K to those positions of M that correspond to indices ind. This is often used in Finite Element computations.
Is there a way to do the same thing just as elegantly in Python? You may assume my M and K are NumPy arrays that were constructed via the operations:
M = np.zeros((12, 12))
K = np.zeros((6, 6))
I did some work on these matrices and filled them with data. My ind array is a NumPy array as well.
However, when I do something like
M[ind, ind] = K
I get shape mismatch as an error. Plugging ind.tolist() instead of ind into M won't change anything.
Thanks for any advice!
You are looking for this:
M[np.ix_(ind,ind)] = K
example:
M = np.zeros((12, 12))
K = np.ones((6, 6))
ind = np.arange(6)
output:
[[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]]
If you are using numpy arrays, It can be donde directly using this syntax:
import numpy as np
M = np.zeros((12, 12))
K = np.ones((6, 6))
M[:6, :6] = K
# This is equivalent to:
# M[0:6, 0:6] = K
M will then look like this:
array([[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
Here you have more information about slice indexing in python
https://www.pythoncentral.io/how-to-slice-listsarrays-and-tuples-in-python/

tf.keras.utils.to_categorical mixing classes

I am using tf.keras.utils.to_categorical() for data preparation.
I have this very simple list and I want to get the categorical values out of it.
So I do this:
tf.keras.utils.to_categorical([1,2,3], num_classes=6)
and I get:
array([[0., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.],
[0., 0., 0., 1., 0., 0.]], dtype=float32)
Now for further usage, I reduce the values I sent to the function by 1, to get a amount of 6 classes, without 0 as placeholder:
tf.keras.utils.to_categorical([x -1 for x in [1,2,3]], num_classes=6)
which results in this:
array([[1., 0., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.]], dtype=float32)
Now comes the weird part. I want to set certain features to 0 and thats why I found this behaviour:
tf.keras.utils.to_categorical([x -1 for x in [-4,2,3]], num_classes=6)
results in:
array([[0., 1., 0., 0., 0., 0.],
[0., 1., 0., 0., 0., 0.],
[0., 0., 1., 0., 0., 0.]], dtype=float32)
So to_categorical() is mixing -4 and 2 into the same class, which I find pretty weird. I would have expected an exception as the list was not map-able to 6 classes. But I did not expect this to happen. Is this a bug or a feature, why is this happening?
Thanks!
That's completely normal. It just works consistently with Python's negative indexing. See:
import tensorflow as tf
tf.keras.utils.to_categorical([0, 1, 2, -1, -2, -3])
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.],
[0., 0., 1.],
[0., 1., 0.],
[1., 0., 0.]], dtype=float32)
To put it differently:
import tensorflow as tf
a = tf.keras.utils.to_categorical([0, 1, 2], num_classes=3)
b = tf.keras.utils.to_categorical([-3, -2, -1], num_classes=3)
print(a)
print(b)
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
[[1. 0. 0.]
[0. 1. 0.]
[0. 0. 1.]]
If you want to know why this happened, I think to_categorical in keras doesn't work with negative numbers. but if you want to solve it I suggest to make all numbers greater than 0.
this code do that:
arr=numpy.array([-5,-4,-2,-1,0,1,2,3,4]) #anything
arr+=(0-arr.min())
Keras to_categorical doesn't work for negative numbers. It's clearly written that the numbers must start from 0.
https://keras.io/api/utils/python_utils/#to_categorical-function
If you still need to make it work, make a dictionary to map the negative numbers.

Update a matrix through advanced indexing/vectorizing

I have a matrix of what is effectively counters. I would like to increment those counters based on a list of column indices - with each positional index also corresponding to a row increment.
This is straightforward with a for loop, and a little less straightforward with list comprehension. In either case, iteration is involved. But I was wondering if there is any way to vectorise this problem?
The minimal problem is:
counters = np.zeros((4,4))
counters
array([[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.],
[0., 0., 0., 0.]])
update_columns = [1,0,2,2]
for row, col in zip(range(len(update_columns)), update_columns):
counters[row, col] += 1
counters
array([[0., 1., 0., 0.],
[1., 0., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 1., 0.]])
What you are looking for is called advanced numpy indexing. You can pass the row index using np.arange and column index using update_columns:
update_columns = np.array(update_columns)
counters[np.arange(update_columns.size), update_columns] += 1
output:
[[0. 1. 0. 0.]
[1. 0. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 1. 0.]]

Categories