create a list of list of N-dimensional numpy arrays - python

I want to create a list of list of 2x2 numpy arrays
array([[0, 0],
[1, 1]])
for example I want to fill a list with 8 of these arrays.
x = []
for j in range(9):
for i in np.random.randint(2, size=(2, 2)):
x.append([i])
this gives me a 1x1 array
z = iter(x)
next(z)
[array([0, 1])]
what am I missing here ?

You missed that are iterating over a 2x2 array 9 times. Each iteration yields a row of the array which is what you see when you look at the first element - the first row of the first matrix. Not only that, you append this row within a list, so you actually have 18 lists with a single element. What you want to do is append the matrix directly, with no inner loop and definitely no additional [] around, or better yet:
x = [np.random.randint(2, size=(2, 2)) for _ in range(9)]

Related

Convert a list of two numbers to indices for an array

Short version: Given a list with two elements [i, j], how do I get the i, j -element of a 2d array instead of the i, j rows: arr[[i,j]] to arr[i,j].
I've seen similar cases where *list has been used, but I don't entirely understand how that operator works.
Deeper context:
I have a function that returns a nested list, where each sub-list is a pair of indices to be used in an array:
grid = np.full((3,3), 1)
def path():
...
return [[i_1, j_1], [i_2, j_2], ...]
for i in path():
grid[path()[i]] = 0
But since path()[i] is a list, grid[path()[i]] == 0 sets two rows equal to zero, and not a single element. How do I prevent that?
While not stricly necessary, a faster solution would be preferable as this operation is to be done many times.
The thing that is confusing you is the difference in mathematic notation and indexing 2D (or n-dimensional) lists in Python/programming languages.
If you have a 2D matrix in mathematics, called X, and let's say you'd want to access the element in the first row and first column, you'd write X(1, 1).
If you have a 2D array, it's elements are lists. So, if you want to access the 1st row of an array called X you'd do:
X[0] # 0 because indexation starts at 0
Keep in mind that the previous statement returns a new list. You can index this list as well. Since we need the first column, we do:
X[0][0] # element in 1st row and 1st column of matrix X
Thus the answer is you need to successively index the matrix, i.e. apply chain indexing.
As for your original question, here is my answer. Let's say a is the 2-element list which contains the indices i and j which you want to access in the 2D array. I'll denote the 2D array as b. Then you apply chain indexing, the first index is the first element of a and the second index is the second element of a:
a = [0, 0] # list with 2 elements containing the indices
b = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] # 2D array in which you want to access b[0][0]
i, j = a[0], a[1]
print(b[i][j])
Obviously you don't need to use variables i, j, I just did so for clarity:
print(b[a[0]][a[1]])
Both statements print out the element in the 1st row and 1st column of b:
1

for-loop in function does not append arrays while same loop outside function does append arrays

I am new to python. I am trying to understand the behavior of a function.
I have two arrays:
a_indices, a 5x2 array for which each row contains row and column indices of specific cells of a matrix (not relevant for this question)
a_template a 9x2 array containing values that should be subtracted from each row of 1) in order to get the indices of the neighboring cells
To subtract a_template from each row of a_indices I cooked up the following code:
import numpy as np
# define arrays
a_indices = np.array([[0, 1],[1, 2],[2, 2],[0, 2],[1, 2]])
a_template = np.array([[-1,-1],[-1,0],[-1,1],[ 0,-1],[0, 0],[ 0, 1],[ 1, -1],[ 1, 0],[ 1, 1]])
# add a_template to each row of a_indices
a1 = []
for x in a_indices:
a1.append(np.add(x,a_template))
print(a1)
Starting with an empty list it appends arrays with added values for each row of a_indices. This gives a list of 5 numpy arrays of 2x9, containing the values I need. Good!
However I will produce a lot of these a_indices arrays and they will likely have different numbers of rows. Therefore I wanted to wrap the above for loop into a function that should return my desired objects. So I tried this:
def find_neighbors(idc):
b = []
for x in idc:
b.append(np.add(x,a_template))
return b
a2 = find_neighbors(a_indices)
print(a2)
The function just contains the for loop from the above example. I expected that this function returns the same object as a1. However it returns a list of only one array (the same as the first array from a1).
My question is why does my function not return a list for each row of a_indices and of course how can I fix this?
Change to this
def find_neighbors(idc):
b = []
for x in idc:
b.append(np.add(x,a_template))
return b
a2 = find_neighbors(a_indices)
print(a2)
your return is inside the loop. It will only give you the first array

Iterating through rows in numpy array with one row

For a 2D numpy array A, the loop for a in A will loop through all the rows in A. This functionality is what I want for my code, but I'm having difficulty with the edge case where A only has one row (i.e., is essentially a 1-dimensional array). In this case, the for loop treats A as a 1D array and iterates through its elements. What I want to instead happen in this case is a natural extension of the 2D case, where the loop retrieves the (single) row in A. Is there a way to format the array A such that the for loop functions like this?
Depending on if you declare the array yourself you can do this:
A = np.array([[1, 2, 3]])
Else you can check the dim of your array before iterating over it
B = np.array([1, 2, 3])
if B.ndim == 1:
B = B[None, :]
Or you can use the function np.at_least2d
C = np.array([1, 2, 3])
C = np.atleast_2d(C)
If your array trully is a 2D array, even with one row, there is no edge case:
import numpy
a = numpy.array([[1, 2, 3]])
for line in a:
print(line)
>>> [1 2 3]
You seem to be confusing numpy.array([[1, 2, 3]]) which is a 2D array of one line and numpy.array([1, 2, 3]) which would be a 1D array.
I think you can use np.expand_dims to achieve your goal
X = np.expand_dims(X, axis=0)

Using permuted list to populate two-dimensional array with special order

I want to create a 2D array containing tuples or lists which requires a particular order.
Using itertools.product I am capable of creating the required permutations:
import itertools
import numpy as np
elements = 2
n = 3
temp = []
for tuples in itertools.product(np.arange(elements,-1,-1), repeat=n):
if sum(tuples) == elements:
temp.append(tuples)
print temp
This will print:
Out[1277]:
array([[2,0,0],
[1,1,0],
[1,0,1],
[0,2,0],
[0,1,1],
[0,0,2]])
The array should then be created to yield:
array = [[(2,0,0),(1,1,0),(0,2,0)],
[(1,0,1),(0,1,1),(0,0,0)],
[(0,0,2),(0,0,0),(0,0,0)]]
and is subsequently used to compute a dot product:
array2 = [1,5,10]
np.dot(array, array2)
Out[1278]:
array([2,6,10,11,15,0,20,0,0])
However, itertools does not yield the order I am looking for.
Therefore, I am using argsort and basically 1D arrays in the end:
array = itertools.product(np.arange(elements,-1,-1), repeat=n)
sortedArray = array[array[:,1].argsort()]
print sortedArray
Out[1279]:
array([[2,0,0],
[1,0,1],
[0,0,2],
[1,1,0],
[0,1,1],
[0,2,0]])
result = np.dot(sortedList, array2)
This works fine in combination with np.pad to restore the original size (3x3 = 9):
np.pad(result, (0, array.size - result.size), "constant")
Out[1280]:
array([2,6,10,11,15,20,0,0,0])
However, the order is not retained.
The reason for doing this, is a second reference array that uses the same structure as the array above, which can be raveled:
reference = [[foo,bar,baz],
[bar,bar,0],
[foo, 0, 0]]
np.ravel(reference)
Out[1281]:
array([foo,bar,baz,bar,bar,0,foo,0,0])
I am looking for a solution that does not need the work-around.

Selecting some dimensions from a multi-dimensional array

I have a 4-D array, and I need to process all 1-D vectors from this array along a given dimension. This works well:
def myfun(arr4d,selected_dim): # selected_dim can only be 2 or 3
print arr4d.shape # (2, 5, 10, 10)
for i in xrange(arr4d.shape[0]):
for j in xrange(arr4d.shape[1]):
for k in xrange(arr4d.shape[selected_dim]):
if selected_dim==2:
arr=arr4d[i,j,k,:]
elif selected_dim==3:
arr=arr4d[i,j,:,k]
do_something(arr) # arr is 1-D and has 10 items
...but I believe there is some way to avoid the nested "if" part, and maybe also be more efficient? Like creating other views of this array before the loops and then iterating through these views?
One common way to handle this is to use np.rollaxis:
def myfun(arr4d, selected_dim): # selected_dim can only be 2 or 3
arr4d = np.rollaxis(arr4d, selected_dim)
print arr4d.shape # (10, 2, 5, 10)
for i in xrange(arr4d.shape[1]):
for j in xrange(arr4d.shape[2]):
for k in xrange(arr4d.shape[0]):
arr=arr4d[k, i, j, :]
do_something(arr) # arr is 1-D and has 10 items
Note that np.rollaxis should return a view so it doesn't actually copy the array.

Categories