-1

I want to change a value of given array in numpy to a multiplication of other elements of the array. Therefore I want to extract the multi_index and manipulate it so that I can identify the position and use it. (e.g. nditer through all elements and always do 'current position in array = next position +position above in array'

I tried to call a function with the multi_index of the current position and want said function to take it and e.g. increase it by one position. (<0 , 1> ---> <0 , 2> while <0 , n> n>=length otherwise <0 , 1> ---> <1 , 0>)

import numpy as np;

def fill(multi_index):
    "This will get the new value of the current iteration value judgeing from its index"
    return a[(multi_index + <0,1>) + (multi_index + <0,-1>) + (multi_index + <1,0>) + (multi_index + <-1,0>)]

#a = np.random.uniform(0, 100, size=(100, 100))
a = np.arange(6).reshape(2,3)

it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])
while not it.finished:
    it[0] = fill(it.multi_index)
    print(it[0])
    it.iternext()

"""for x in np.nditer(a, flags=['multi_index'], op_flags=['readwrite']):

    print(x)"""

I don't understand how to extract the actual "coordinates" from the multi_index. I am kinda new to python so please try to explain it thoroughly if possible. Thanks.

Edit: Before I only coded on C++ and a bit Java, so I used to mainly using arrays (in c++ it would be somthing like this:

int main() { 
  int a[100][100];
  for (int i=1, i<=a.length-1, i++) { 
    for (int j=1, i<=a.width-1, j++) { 
      a[i][j] = 1/4 (a[i][j+1]+a[i][j-1]+a[i+1][j]+a[i-1][j]);
    } 
  } 
return 0;
}
  • Stay away from `nditer`, especially if you are beginner. It does not improve iteration speed. Show with plain indexed for loops what you are trying to do. – hpaulj May 23 '19 at 21:12
  • Providing a sample input and preferred output would help as well – G. Anderson May 23 '19 at 21:15
  • Normally the input would be a 100x100 array with random values and in various steps of iterations each element in the array would be set to 1/4 of the neighboring elements. After 1000 iterations or so, the finished array will be printed out. In order to change the values of an element to a product of its neighboring elements I need to extracts its "coordinates"and (in the seperate funtions fill) get the new value through simple multiplications. At the moment there is nothing in the fill-function yet. – Sebastian May 23 '19 at 21:40
  • In for loops: ```python for x in for x in np.nditer(a, flags=['multi_index'], op_flags=['readwrite']: a[x] = 1/4 ( a[mutil_index + <0,1>] + a[mutil_index + <0, -1>] + a[mutil_index + <1,1>] + a[mutil_index + <-1,-1>] ) ``` – Sebastian May 23 '19 at 21:44

1 Answers1

0
In [152]: a = np.arange(6).reshape(2,3)                                                                  
In [153]: a                                                                                              
Out[153]: 
array([[0, 1, 2],
       [3, 4, 5]])

Let's run your nditer and look at its values:

In [157]: it = np.nditer(a, flags=['multi_index'], op_flags=['readwrite'])                               
In [158]: while not it.finished: 
     ...:     print(it.multi_index, a[it.multi_index], it[0], type(it[0])) 
     ...:     it.iternext() 
     ...:                                                                                                
(0, 0) 0 0 <class 'numpy.ndarray'>
(0, 1) 1 1 <class 'numpy.ndarray'>
(0, 2) 2 2 <class 'numpy.ndarray'>
(1, 0) 3 3 <class 'numpy.ndarray'>
(1, 1) 4 4 <class 'numpy.ndarray'>
(1, 2) 5 5 <class 'numpy.ndarray'>

At each iteration multiindex is a tuple of the i,j indices. a[it.multiindex] then selects that item from the array. But it[0] is also that item, but wrapped as a 0d array. If you aren't comfortable with the idea of a 0d array (shape ()) then nditer is not the tool for you (at this time).

If you just want the sequential indexing tuples, ndindex works just as well:

In [162]: list(np.ndindex(a.shape))                                                                      
Out[162]: [(0, 0), (0, 1), (0, 2), (1, 0), (1, 1), (1, 2)]

(in fact, np.lib.index_tricks.py shows that ndindex uses the nditer multiindex. nditer isn't commonly used in numpy Python level code.)

Or to get indices plus value:

In [177]: list(np.ndenumerate(a))                                                                        
Out[177]: [((0, 0), 0), ((0, 1), 1), ((0, 2), 2), ((1, 0), 3), ((1, 1), 4), ((1, 2), 5)]

Just values in flat order:

In [178]: a.ravel()                                                                                      
Out[178]: array([0, 1, 2, 3, 4, 5])

BUT, in numpy we prefer not to iterate at all. Instead we try to write code that works with the whole array, using the fast compiled numpy methods. Iteration on arrays is slow, slower than iteration on lists.

===

Looks like your iteration, in a somewhat stylized sense, is:

for i in range(n):
    for j in range(m):
         a[i,j] = ( a[i,j+1] + a[i,j-1] + a[i+1,j] + a[i-1,j] )/4 

There some details to worry about. What about the edges, where j+/-1 is out of bounds? And is this calculation sequential, so that a[i,j] depends on the changes just made to a[i,j-1]; or is it buffered?

In general sequential, iterative calculations on an array like this are a bad fit for numpy.

On the other hand, buffered calculations can be nicely done with whole-array slices

x[1:-1, 1:-1] = (x[:,:-1]+x[:,1:]+x[:-1,:]+x[1:,:])/4

There are also, in scipy some convolution functions that perform calculations on moving windows.

hpaulj
  • 221,503
  • 14
  • 230
  • 353
  • Normally the input would be a 100x100 array with random values and in various steps of iterations each element in the array would be set to 1/4 of the neighboring elements. After 1000 iterations or so, the finished array will be printed out. In order to change the values of an element to a product of its neighboring elements I need to extracts its "coordinates"and (in the seperate funtions fill) get the new value through simple multiplications. At the moment there is nothing in the fill-function yet. I don't particularly care about them being 0d-arrays ( I suppose simple scalars? ) – Sebastian May 23 '19 at 21:46
  • Perhaps there is a fast compiled numpy method for these kinds of iterations, but this was the best way I could find in the moment. Before I only coded on C++ and a bit Java, so I used to mainly using arrays (in c++ it would be like this: int main() { for (int i=1, i<=a.length-1, i++) { for (int j=1, i<=a.width-1, j++) { a[i][j] = 1/4 (a[i][j+1]+a[i][j-1]+a[i+1][j]+a[i-1][j]); } } return 0; } – Sebastian May 23 '19 at 21:53
  • I think you will be badly disappointed with the speed of this kind of iteration in `numpy`. – hpaulj May 23 '19 at 22:34
  • That actually looks really nice, can you explain how the last code bit works precicely? I also decided that I might have better calculation times in c++ and have a new question concerning this topic. – Sebastian May 25 '19 at 22:50
  • Make a simple 1d array (e.g. `np.arange(12)`) and try this pair wise difference calculation, `arr[1:]-arr[:-1]`. That should give you a feel for what is going on. – hpaulj May 25 '19 at 22:59