How to get rid of nested for loop - python

mazeHow do i replace the nested for loop without affecting the functionality of the code:
def addCoordinate(self, x, y, blockType):
if self.x1 < x :
self.x1 = x
if self.y1 < y:
self.y1 = y
if self.x1 >= len(self.mazeboard) or self.y1 >= len(self.mazeboard):
modified_board = [[1 for a in range(self.x1 + 1)] for b in range(self.y1 + 1)]
for a in range(len(self.mazeboard)):
for b in range(len(self.mazeboard[a])):
modified_board[a][b] = self.mazeboard[a][b]
self.mazeboard = modified_board
self.mazeboard[x][y] = blockType

Yes, the nested loops & the range(len(self.mazeboard)) are highly unpythonic here, most of all when you just want to extend a matrix like
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
to
0 0 0 0 0 1 1 1
0 0 0 0 0 1 1 1
0 0 0 0 0 1 1 1
0 0 0 0 0 1 1 1
0 0 0 0 0 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
you could work in-place, completing the existing rows with ones, and adding rows of ones until you reach the proper dimension
Self-contained example:
mazeboard = [[0]*5 for _ in range(5)]
x1 = 7
x2 = 7
old_len = len(mazeboard[0])
# extend the existing rows
for m in mazeboard:
m += [1]*(x1+1-old_len)
# add rows
mazeboard += [[1]*(x1+1) for i in range(len(mazeboard),x2+1)]
print(mazeboard)
result:
[[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 1, 1, 1],
[0, 0, 0, 0, 0, 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]]
so no nested loop, no useless copy, using list multiplication to generate the proper lengths for the lists to add.

If you work with a matrix in Python, you may want to consider using Numpy
You example becomes trivial with numpy. First, import numpy:
>>> import numpy as np
Create the 5x5 matrix:
>>> a=np.ones(shape=(5,5))
>>> a
array([[ 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.]])
Expand that matrix with 5 more columns and 5 more rows:
>>> a=np.pad(a,((0,5),(0,5)),mode='constant', constant_values=0)
>>> a
array([[ 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
[ 1., 1., 1., 1., 1., 0., 0., 0., 0., 0.],
[ 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.]])
Instead of nested Python loops, you will have C code executing matrix function many times faster and more efficiently.

Related

how to fix "index 3 is out of bounds for axis 1 with size 3" in one-hot encoding? [duplicate]

This question already has answers here:
Convert array of indices to one-hot encoded array in NumPy
(22 answers)
Closed 3 years ago.
I was working on one-hot encoding using python. but there is some problem when i run one-hot-encoding
def one_hot_encode(labels):
n_labels = len(labels)
n_unique_labels = len(np.unique(labels))
one_hot_encode = np.zeros((n_labels,n_unique_labels))
one_hot_encode[np.arange(n_labels), labels] = 1
return one_hot_encode
this is what i used to running one-hot endcode
and the data is like this...
[3 3 3 3 3 2 2 2 2 2 1 1 1 1 1]
It occurs this error
"index 3 is out of bounds for axis 1 with size 3"
And i try another path...
change the part of code
one_hot_encode = np.zeros((n_labels,n_unique_labels+1))
This is running but it its not the 3 classes...
The result is like this
array([[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 0., 1.],
[0., 0., 1., 0.],
[0., 0., 1., 0.],
[0., 0., 1., 0.],
[0., 0., 1., 0.],
[0., 0., 1., 0.],
[0., 1., 0., 0.],
[0., 1., 0., 0.],
[0., 1., 0., 0.],
[0., 1., 0., 0.],
[0., 1., 0., 0.]])
how do I fix this problem?
The error is raising from [3 3 3 3 3 2 2 2 2 2 1 1 1 1 1]. You have 3 in your mapping np.array which means in some position you are trying to equal index 3 to 1 but the problem is that maximum index in your mapping array is 2.
def one_hot_encode(labels):
n_labels = len(labels) # this will give 15
n_unique_labels = len(np.unique(labels)) # this will give 3
one_hot_encode = np.zeros((n_labels,n_unique_labels)) # will create 15x3 matrix
one_hot_encode[np.arange(n_labels), labels] = 1 # error here you try to map index 3 to 1 which does not exist
return one_hot_encode
Just simply change your mapping array from [3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1] to [2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]

Convert integer to categorical vector of fixed size in Python

I have a set of N integers with the range of values to be from 1-6. I would like to produce the corresponding categorical vector of size 6 per each integer (therefore an array of size Nx6) which will be the categorical representation of my initial set. In the case that my integer will be 1 the result should be:
[1, 0, 0, 0, 0, 0]
While for 6:
[0, 0, 0, 0, 0, 1]
And etc..
You could use a simple list comprehension:
>>> x = 1
>>> [int(i+1 == x) for i in range(6)]
[1, 0, 0, 0, 0, 0]
>>> x = 6
>>> [int(i+1 == x) for i in range(6)]
[0, 0, 0, 0, 0, 1]
Likewise for an Nx6 list of lists:
>>> X = [4,1,5]
>>> [[int(i+1 == x) for i in range(6)] for x in X]
[[0, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0]]
If you are happy to use a 3rd party library, this can be achieved efficiently with NumPy:
import numpy as np
np.random.seed(0)
m, n = 6, 10
L = np.random.randint(1, m+1, n) # construct array of 10 numbers between 1 and 6
A = np.zeros((n, m)) # initialize array of zeros
A[np.arange(n), L-1] = 1 # use advanced indexing to assign values
The result is a NumPy array which you can then index via A[0], A[1], etc.
print(A)
array([[ 0., 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 0., 1.],
[ 1., 0., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 1., 0., 0., 0., 0.],
[ 0., 0., 0., 1., 0., 0.],
[ 0., 0., 0., 0., 0., 1.],
[ 0., 0., 1., 0., 0., 0.]])
You can use numpy.fill_diagonal to fill diagonals with value of your need:
import numpy as np
a = np.zeros((6, 6), int)
np.fill_diagonal(a, 1)
print(a)
Output:
[[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]]
Now, if your integer is 1, use a[0],... for 6, use a[5].
Eg:
input_integer = 1
print(a[input_integer-1])
# [1 0 0 0 0 0]

Map numpy categorical data to a numpy vector

I am having a numpy array that is looking like:
my_arr = array([[0., 0., 0., 0., 1., 0.],
[0., 1., 0., 0., 0., 0.],
[0., 0., 0., 1., 0., 0.],
[0., 0., 0., 0., 1., 0.],
[1., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0.],
[0., 1., 0., 0., 0., 0.],
[0., 0., 0., 0., 1., 0.],
...
...]
I want to return a vector that will contain for each vector of my_arr the index of entry with value one. How can I do so?
You use np.argmax() for that.
inds = np.argmax(my_arr, axis=1)
# array([4, 1, 3, 4, 0, 4, 1, 4])
np.where(my_arr)[1]
Look at docs: https://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html
You can use np.argwhere to return an array of coordinates:
arr = np.random.randint(0, 2, (5, 5))
print(arr)
[[0 0 1 1 1]
[0 1 0 1 1]
[1 1 0 0 1]
[1 1 1 0 0]
[1 1 1 1 0]]
res = np.argwhere(arr)
print(res)
array([[0, 2], [0, 3], ..., [4, 2], [4, 3]], dtype=int64)

Expanding a matrix [duplicate]

This question already has answers here:
Quick way to upsample numpy array by nearest neighbor tiling [duplicate]
(3 answers)
Closed 4 years ago.
Given a matrix, such as:
1 0 0
0 1 1
1 1 0
I would like to expand each element to a "sub-matrix" of size AxA, e.g., 3x3, the result will be:
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
1 1 1 0 0 0 0 0 0
0 0 0 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1
0 0 0 1 1 1 1 1 1
1 1 1 1 1 1 0 0 0
1 1 1 1 1 1 0 0 0
1 1 1 1 1 1 0 0 0
What is the fastest way of doing it in Python using numpy (or PyTorch)?
Since what you're describing is the Kronecker product:
Use np.kron
Computes the Kronecker product, a composite array made of blocks of the second array scaled by the first.
x = np.array([[1, 0, 0], [0, 1, 1], [1, 1, 0]])
np.kron(x, np.ones((3, 3)))
array([[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[1., 1., 1., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[0., 0., 0., 1., 1., 1., 1., 1., 1.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.],
[1., 1., 1., 1., 1., 1., 0., 0., 0.]])

Numpy: What is the correct way to upsample an array?

octave:1> a=[1 2 3]
a =
1 2 3
octave:2> k=[a;zeros(9,length(a))]
k =
1 2 3
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
Is the below method the correct way to achieve it in Python:
>>> a=[1, 2, 3]
>>> np.append(a,np.zeros((9,len(a))))
array([ 1., 2., 3., 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.])
The octave solution results in a 10x3 matrix while your solution results in a 1-dimensional array with 30 elements.
I am assuming you want a matrix with the dimensions 10x3 right?
>>>a=np.array((1, 2, 3))
>>>k=np.vstack((a,np.zeros((9,len(a)))))
array([[ 1., 2., 3.],
[ 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.]])

Categories