Creating a pattern in an array - python

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).

Related

Python: Fill out edges of binary array

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.]]

Identity matrix of 3 Dimensional matrix

Identity = array([[[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]],
[[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]],
[[1., 0., 0., 0.],
[0., 1., 0., 0.],
[0., 0., 1., 0.],
[0., 0., 0., 1.]]])
There is a task which wants me to create identity matrix in 3D.
I have made assumptions that the above is the identity matrix in 3D with the shape (3,4,4).
I have seen other variations of identity of 3D matrix which I didn't understand. Check this What's the best way to create a "3D identity matrix" in Numpy? for reference.
If I am right in my above assumption of identity matrix. Please assist me to construct the same with numpy.
You can use np.identity() to generate an identity matrix and then use np.broadcast_to() to add the third dimension:
import numpy as np
n = 4
print(np.broadcast_to(np.identity(n), (3, n, n)))
You can also use np.tile:
n = 4
k = 3
out = np.tile(np.identity(n), (k,1)).reshape(k,n,n)
Output:
[[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]
[[1. 0. 0. 0.]
[0. 1. 0. 0.]
[0. 0. 1. 0.]
[0. 0. 0. 1.]]]

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/

How do I make append work as intended with arrays?

I'm having problem with this code. I think I'm doing something wrong.
import numpy as np
array = np.zeros(10)
arrays = []
for i in range(len(array)):
array[i] = 1
arrays.append(array)
print(arrays[0])
I was expecting to get:[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
But I'm getting:[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
That is the last array I appended to arrays, and not the first one. Why is that happening and more important what can I do to get the desired output?
I think you are expecting:
arrays.append(array)
to add a COPY of your main array to the arrays list. But that's not what you're doing. You're pushing another reference to the same array each time you do:
arrays.append(array)
so at the end of your loop, you have the list arrays with 10 references to the same original array you created. By then, you've set every value of that ONE ARRAY to 1. So you get that the first value in arrays contains an array with every value set to 1 because every array in arrays is that same array.
If you actually copy a new array each time into arrays, I bet you'll get what you expected. To do that, change that line to:
arrays.append(array.copy())
Here's a complete version of your program with this fix. I changed it also to print all 10 of the arrays in arrays:
def main():
import numpy as np
array = np.zeros(10)
arrays = []
for i in range(len(array)):
array[i] = 1
arrays.append(array.copy())
for array in arrays:
print(array)
Result:
[1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 1. 0. 0. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 0. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 0. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 0. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 0. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 1. 0. 0. 0.]
[1. 1. 1. 1. 1. 1. 1. 1. 0. 0.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 0.]
[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]
just add this change:
arrays.append(np.array(array))
The actual way to do this in numpy is with np.tri():
np.tri(10)
Out[]:
array([[ 1., 0., 0., ..., 0., 0., 0.],
[ 1., 1., 0., ..., 0., 0., 0.],
[ 1., 1., 1., ..., 0., 0., 0.],
...,
[ 1., 1., 1., ..., 1., 0., 0.],
[ 1., 1., 1., ..., 1., 1., 0.],
[ 1., 1., 1., ..., 1., 1., 1.]])
Maybe you are looking for this , just added if condition in your code
import numpy as np
array = np.zeros(10)
arrays = []
for i in range(len(array)):
if i==0:
array[i] = 1
arrays.append(array)
print(arrays[0])
out: [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
You can use array.copy() a method defined on numpy arrays as #Steve has suggested.
As it has been already used in one of the answer (#Steve's answer) to this problem so I choose another approach i.e. deepcopy() functionto obtain the result.
import numpy as np
from copy import deepcopy
array = np.zeros(10)
arrays = []
for i in range(len(array)):
array[i] = 1
arrays.append(deepcopy(array))
print(arrays)
# [array([1., 0., 0., 0., 0., 0., 0., 0., 0., 0.]), array([1., 1., 0., 0., 0., 0., 0., 0., 0., 0.]), array([1., 1., 1., 0., 0., 0., 0., 0., 0., 0.]), array([1., 1., 1., 1., 0., 0., 0., 0., 0., 0.]), array([1., 1., 1., 1., 1., 0., 0., 0., 0., 0.]), array([1., 1., 1., 1., 1., 1., 0., 0., 0., 0.]), array([1., 1., 1., 1., 1., 1., 1., 0., 0., 0.]), array([1., 1., 1., 1., 1., 1., 1., 1., 0., 0.]), array([1., 1., 1., 1., 1., 1., 1., 1., 1., 0.]), array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1.])]
print(arrays[0])
# [1. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
print(arrays[-1])
# [1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]

Python indirect indexing

This might be a super easy question if you know how to do it, but I just can't figure out the syntax:
I have an array of 5x10 zeros: y1 = np.zeros((5,10)) and an array 5x1 of index: index=np.array([2,3,2,5,6]). For each row of y1, I would like to set 1 at the column given by the index. The result would look like
array([[ 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 1., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0., 0., 1., 0., 0., 0.]])
Anyone can help please :-) ?
You can do multi-dimensional array indexing with array[index_1, index_2]. For your problem:
y1[range(y1.shape[0]), index] = 1
range(y1.shape[0]) generates the array [0,1,...,n-1], where n is the number of rows in y1. This array is your row index, and index is your column index.
Just use an enumerate()
import numpy as np
y1 = np.zeros((5,10))
index=np.array([2,3,2,5,6])
for i,item in enumerate(y1):
item[index[i]] = 1
print(y1)
# [[ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
# [ 0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]
# [ 0. 0. 1. 0. 0. 0. 0. 0. 0. 0.]
# [ 0. 0. 0. 0. 0. 1. 0. 0. 0. 0.]
# [ 0. 0. 0. 0. 0. 0. 1. 0. 0. 0.]]
Does this do what you want?

Categories