How to make a checkerboard in Pytorch? - pytorch

I see that a simple checkerboard pattern can be created fairly concisely with numpy Does anyone know if a checkerboard where each square may contain multiple values could be created? E.g.:
1 1 0 0 1 1
1 1 0 0 1 1
0 0 1 1 0 0
0 0 1 1 0 0

Although there is no equivalent of np.indices in PyTorch, you can still find a workaround using a combination of torch.arange, torch.meshgrid, and torch.stack:
def indices(h,w):
return torch.stack(torch.meshgrid(torch.arange(h), torch.arange(w)))
This allows you to define a base tensor with a checkboard pattern following your linked post:
>>> base = indices(2,3).sum(axis=0) % 2
tensor([[0, 1, 0],
[1, 0, 1]])
Then you can repeat the row end columns with torch.repeat_interleave:
>>> base.repeat_interleave(2, dim=0).repeat_interleave(2, dim=1)
tensor([[0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 0],
[1, 1, 0, 0, 1, 1],
[1, 1, 0, 0, 1, 1]])
And you can take the opposite of a given checkboard x by computing 1-x.
So you could define a function like this:
def checkerboard(shape, k):
"""
shape: dimensions of output tensor
k: edge size of square
"""
h, w = shape
base = indices(h//k, w//k).sum(dim=0) % 2
x = base.repeat_interleave(k, 0).repeat_interleave(k, 1)
return 1-x
And try with:
>>> checkerboard((4,6), 2)
tensor([[1, 1, 0, 0, 1, 1],
[1, 1, 0, 0, 1, 1],
[0, 0, 1, 1, 0, 0],
[0, 0, 1, 1, 0, 0]])

Related

How to select rows from two different Numpy arrays conditionally?

I have two Numpy 2D arrays and I want to get a single 2D array by selecting rows from the original two arrays. The selection is done conditionally. Here is the simple Python way,
import numpy as np
a = np.array([4, 0, 1, 2, 4])
b = np.array([0, 4, 3, 2, 0])
y = np.array([[0, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 1, 0],
[0, 0, 1, 1],
[0, 0, 1, 0]])
x = np.array([[0, 0, 0, 0],
[1, 1, 1, 0],
[1, 1, 0, 0],
[1, 1, 1, 1],
[0, 0, 1, 0]])
z = np.empty(shape=x.shape, dtype=x.dtype)
for i in range(x.shape[0]):
z[i] = y[i] if a[i] >= b[i] else x[i]
print(z)
Looking at numpy.select, I tried, np.select([a >= b, a < b], [y, x], -1) but got ValueError: shape mismatch: objects cannot be broadcast to a single shape. Mismatch is between arg 0 with shape (5,) and arg 1 with shape (5, 4).
Could someone help me write this in a more efficient Numpy manner?
This should do the trick, but it would be helpful if you could show an example of your expected output:
>>> np.where((a >= b)[:, None], y, x)
array([[0, 0, 0, 0],
[1, 1, 1, 0],
[1, 1, 0, 0],
[0, 0, 1, 1],
[0, 0, 1, 0]])

Multiclass vs. multilabel fitting

In scikit-learn tutorials, I found the following paragraphs in the section 'Multiclass vs. multilabel fitting'.
I couldn't understand why the following codes generate the given results.
First
from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn.preprocessing import LabelBinarizer
X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
y = [0, 0, 1, 1, 2]
classif = OneVsRestClassifier(estimator=SVC(random_state=0))
classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])
y = LabelBinarizer().fit_transform(y)
classif.fit(X, y).predict(X)
array([[1, 0, 0],
[1, 0, 0],
[0, 1, 0],
[0, 0, 0],
[0, 0, 0]])
Next
from sklearn.preprocessing import MultiLabelBinarizer
y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
y = MultiLabelBinarizer().fit_transform(y)
classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 0]])
Label binarization in scikit-learn will transform your targets and represent them in a label indicator matrix. This label indicator matrix has the shape (n_samples, n_classes) and is composed as follows:
each row represents a sample
each column represents a class
each element is 1 if the sample is labeled with the class and 0 if not
In your first example, you have a target collection with 5 samples and 3 classes. That's why transforming y with LabelBinarizer results in a 5x3 matrix. In your case, [1, 0, 0] corresponds to class 0, [0, 1, 0] corresponds to class 1 and so forth. Notice that in each row there is only one element set to 1, since each sample can have one label only.
In your next example, you have a target collection with 5 samples and 5 classes. That's why transforming y with MultiLabelBinarizer results in a 5x5 matrix. In your case, [1, 1, 0, 0, 0] corresponds to the multilabel [0, 1], [0, 1, 0, 1, 0] corresponds to the multilabel [1, 3] and so forth. The key difference to the first example is that each row can have multiple elements set to 1, because each sample can have multiple labels/classes.
The predicted values you get follow the very same pattern. They are however not equivalent to the original values in y since your classification model has obviously predicted different values. You can check this with the inverse_transform() of the binarizers:
from sklearn.preprocessing import MultiLabelBinarizer
mlb = MultiLabelBinarizer()
y = np.array([[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]])
y_bin = mlb.fit_transform(y)
# direct transformation
[[1 1 0 0 0]
[1 0 1 0 0]
[0 1 0 1 0]
[1 0 1 1 0]
[0 0 1 0 1]]
# prediction of your classifier
y_pred = np.array([[1, 1, 0, 0, 0],
[1, 0, 1, 0, 0],
[0, 1, 0, 1, 0],
[1, 0, 1, 0, 0],
[1, 0, 1, 0, 0]])
# inverting the binarized values to the original classes
y_inv = mlb.inverse_transform(y_pred)
# output
[(0, 1), (0, 2), (1, 3), (0, 2), (0, 2)]

Hermitian Adjacency Matrix of Digraph

I am trying to find a pythonic way to calculate the Hermitian adjacency matrix in Python and I'm really struggling. The definition of a Hermitian Adjacency matrix is shown in this image:
It works as follows. Lets say we have two nodes named i and j. If there is an directed edge going from both i to j and j to i, then the corresponding matrix value at location [ i, j ] should be set to 1. If there is only a directed edge from i to j, then the matrix element at location [i, j] should be set to +i. And if there is only a directed edge from j to i then the matrix element at location [i, j] should be set to -i. All other matrix values are set to 0.
I cannot figure out a smart way to make this Hermitian Adjacency Matrix that doesn't involve iterating through my nodes one by one. Any advice?
I don't think there's a built-in for this, so I've cobbled together my own vectorised solution:
import numpy as np
import networkx as nx
# Create standard adjacency matrix
A = nx.linalg.graphmatrix.adjacency_matrix(G).toarray()
# Add to its transpose and convert from sparse array
B = A + A.T
# Get row index matrix
I = np.indices(B.shape)[0] + 1
# Apply vectorised formula to get Hermitian adjacency matrix
H = np.multiply(B/2 * (2*I)**(B%2), 2*A-1).astype(int)
Explanation
Let's start with a directed graph:
We start by creating the normal adjacency matrix using nx.linalg.graphmatrix.adjacency_matrix(), giving us the following matrix:
>>> A = nx.linalg.graphmatrix.adjacency_matrix(G).toarray()
[[1, 1, 0, 1, 0, 1, 0, 0],
[1, 0, 0, 1, 0, 0, 1, 0],
[1, 1, 1, 1, 0, 1, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 1, 0, 0, 0, 0],
[1, 1, 0, 0, 1, 0, 1, 1],
[0, 1, 0, 0, 1, 0, 0, 1],
[0, 0, 0, 0, 1, 0, 0, 0]]
We can then add this matrix to its transpose, giving us 2 in every location where there is a directed edge going from i to j and vice-versa, a 1 in every location where only one of these edges exists, and a 0 in every location where no edge exists:
>>> B = A + A.T
>>> B
[[2, 2, 1, 1, 1, 2, 0, 0],
[2, 0, 1, 2, 0, 1, 2, 0],
[1, 1, 2, 1, 0, 1, 0, 0],
[1, 2, 1, 0, 1, 0, 0, 0],
[1, 0, 0, 1, 0, 1, 1, 1],
[2, 1, 1, 0, 1, 0, 1, 1],
[0, 2, 0, 0, 1, 1, 0, 1],
[0, 0, 0, 0, 1, 1, 1, 0]]
Now, we want to apply a function to the matrix so that 0 maps to 0, 2 maps to 1, and 1 maps to the row number i. We can use np.indices() to get the row number, and the following equation: x/2 * (2*i)**(x%2), where i is the row number and x is the element. Finally, we need to multiply elements in positions where no edge ij exists by -1. This can be vectorised as follows:
>>> I = np.indices(B.shape)[0] + 1
>>> H = np.multiply(B/2 * (2*I)**(B%2), 2*A-1).astype(int)
>>> H
[[ 1, 1, -1, 1, -1, 1, 0, 0],
[ 1, 0, -2, 1, 0, -2, 1, 0],
[ 3, 3, 1, 3, 0, 3, 0, 0],
[-4, 1, -4, 0, -4, 0, 0, 0],
[ 5, 0, 0, 5, 0, -5, -5, -5],
[ 1, 6, -6, 0, 6, 0, 6, 6],
[ 0, 1, 0, 0, 7, -7, 0, 7],
[ 0, 0, 0, 0, 8, -8, -8, 0]]
As required.
We can check that this is correct by using a naïve iterate-through-nodes approach:
>>> check = np.zeros([8,8])
>>> for i in G.nodes:
for j in G.nodes:
if (i, j) in G.edges:
if (j, i) in G.edges:
check[i-1, j-1] = 1
else:
check[i-1, j-1] = i
else:
if (j, i) in G.edges:
check[i-1, j-1] = -i
else:
check[i-1, j-1] = 0
>>> (check == H).all()
True

How to change only the diagonal elements of a 2D list?

So I am trying to create an NxN 2D array and then change its diagonal elemets to 1. Here is my code:
arr=[1,1,1,2,2,2]
table=[[0]*len(arr)]*len(arr)
for i in range(0,len(arr)):
table[i][i]=1
print(table)
However, whenever I run this code, I get this output:
[[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]]
I am looking to get this:
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
I have been staring at my code for hours and I cannot figure out what's wrong
The interesting thing about this is that you are really only editing one list in the for loop, but there are just five pointers to that list. (In this case, the list would be [0, 0, 0, 0, 0, 0].) You can see this by printing the id of each list in table by using id():
>>> for t in table:
print(id(t))
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
2236544254464
Your numbers are likely different than mine, but they are all the same number, nevertheless. You also can see that the edits to one list are applied to the others in table by putting a print(table) statement after each index assignment statement.
So in order to 'fix' this, I would recommend using list comprehension instead. For example:
table = [[0]*len(arr) for _ in range(len(arr))]
If you checkout the ids of each list:
>>> for t in table:
print(id(t))
2236544617664
2236544616064
2236544616320
2236544615872
2236544618368
2236544622720
Since they are different, you can now use the method for changing only the diagonals:
>>> for i in range(0,len(arr)):
table[i][i]=1
>>> table
[[1, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0],
[0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 1]]
Your 2D "array" contains 6 lists which are the same list. Changes to any of those lists will also be reflected in the other lists. Consider this:
>>> l = [0] * 6
>>> x = [l]
>>> l[0] = 1
>>> l
[1, 0, 0, 0, 0, 0]
>>> x
[[1, 0, 0, 0, 0, 0]]
>>> x = [l, l, l]
>>> x
[[1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0]]
>>> x[-1][-1] = 100
>>> x
[[1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100], [1, 0, 0, 0, 0, 100]]
This is because the list x contains the list l, so any changes to l are also seen through the reference to the same list in x.
The problem is when multiplying mutable objects because it creates multiple references to the same mutable object.
You should initialise your table like this:
table = [[0 for j in range(len(arr))] for i in range(len(arr))]
or
table = [[0] * len(arr) for i in range(len(arr))]
which, despite the use of multiplication, works because each list is different.
You can create your table and populate it simultaneously in nested loops:
arr=[1,1,1,2,2,2]
table = []
for i in range(len(arr)):
table.append([0]*len(arr))
for j in range(len(arr)):
if i == j:
table[i][j] = 1
print(table)
#[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]
Interesting.
Try to use numpy to avoid list trap:
import numpy as np
org_row = [0]*5
l = [org_row]*5
x = np.array(l, np.int32)
for i in range(len(x)):
x[i][i]=1
print(x)
output>:
output>
[[1 0 0 0 0]
[0 1 0 0 0]
[0 0 1 0 0]
[0 0 0 1 0]
[0 0 0 0 1]]

Finding a sequence of numbers in a multi dimensional list

How do I find if a sequence of numbers exists in a two-dimensional list? i.e.
matrix: [[1, 1, 1, 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, 1, 0, 0, 0]]
if [1,1,1] in matrix:
print("It's in there")
else: print("It's not there")
I guess I could turn every int into a string but is there a slicker way?
Using an iterator over each cell of the matrix, I've managed to get a basic idea of what you wanted to achieve in Python script.
matrix = [[1, 1, 1, 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, 1, 0, 0, 0]]
matchCount = 0
lastNumber = None
for cell in matrix:
for number in cell:
if number == 1 and lastNumber == 1 or lastNumber == None:
matchCount += 1
if matchCount >= 3:
print("MATCH in cell " + str(cell))
lastNumber = number
matchCount = 0
lastNumber = None
What happens is, it steps into the cell. It it's the first iteration then allow entry into our iterator. We don't know if it's a match list yet, so push it back in our little list.
Stepping over and over, if we get enough matches in a row, then wonderful! Print we found a match in our matrix's cell!

Resources