Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better alternative to nested for loops through arrays in numpy?

Often I need to traverse an array and perform some operation on each entry, where the operation may depend on the indices and the value of the entry. Here is a simple example.

import numpy as np

N=10
M = np.zeros((N,N))

for i in range(N):
    for j in range(N):
        M[i,j] = 1/((i+2*j+1)**2)

Is there a shorter, cleaner, or more pythonic way to perform such tasks?

like image 615
Potato Avatar asked Jan 18 '17 02:01

Potato


People also ask

What is faster than nested for loops?

We can see that in the case of nested loops, list comprehensions are faster than the ordinary for loops, which are faster than while.

What is the best alternative to a for loop in python?

The map() function is a replacement to a for a loop. It applies a function for each element of an iterable.

What advantage does the NumPy array have over a nested list?

NumPy uses much less memory to store data The NumPy arrays takes significantly less amount of memory as compared to python lists. It also provides a mechanism of specifying the data types of the contents, which allows further optimisation of the code. If this difference seems intimidating then prepare to have more.


2 Answers

What you show is 'pythonic' in the sense that it uses a Python list and iteration approach. The only use of numpy is in assigning the values, M{i,j] =. Lists don't take that kind of index.

To make most use of numpy, make index grids or arrays, and calculate all values at once, without explicit loop. For example, in your case:

In [333]: N=10
In [334]: I,J = np.ogrid[0:10,0:10]
In [335]: I
Out[335]: 
array([[0],
       [1],
       [2],
       [3],
       [4],
       [5],
       [6],
       [7],
       [8],
       [9]])
In [336]: J
Out[336]: array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
In [337]: M = 1/((I + 2*J + 1)**2)
In [338]: M
Out[338]: 
array([[ 1.        ,  0.11111111,  0.04      ,  0.02040816,  0.01234568,
         0.00826446,  0.00591716,  0.00444444,  0.00346021,  0.00277008],
 ...
       [ 0.01      ,  0.00694444,  0.00510204,  0.00390625,  0.00308642,
         0.0025    ,  0.00206612,  0.00173611,  0.00147929,  0.00127551]])

ogrid is one of several ways of construction sets of arrays that can be 'broadcast' together. meshgrid is another common function.

In your case, the equation is one that works well with 2 arrays like this. It depends very much on broadcasting rules, which you should study.

If the function only takes scalar inputs, we will have to use some form of iteration. That has been a frequent SO question; search for [numpy] vectorize.

like image 110
hpaulj Avatar answered Sep 21 '22 18:09

hpaulj


np.fromfunction is intended for that :

def f(i,j) : return 1/((i+2*j+1)**2) 
M = np.fromfunction(f,(N,N))

it's slighty slower that the 'hand made' vectorised way , but easy to understand.

like image 22
B. M. Avatar answered Sep 24 '22 18:09

B. M.