1

I am trying to change numpy-array values based on their column and row location and currently am achieving it this way:

for r in range(ResultArr2.shape[0]):
    for c in range(ResultArr2.shape[1]):
        ResultArr2[r,c] = ResultArr2[r,c]-r*1000-c*500

Is there a non-loop way of achieving the same result? I know that Python often works faster if one implements non-loop structure, but I could not find out how to do this.

2 Answers 2

3

Here are a few variants using either mgrid or ogrid or manually creating the same ranges that ogrid generates.

Observations:

  • for an array of size 1000, the fastest method is more than three times faster than mgrid
  • using ogrid or manual it is a bit better to add the two ranges separately, thereby avoiding a full size temporary
  • conveniences such as mgrid or ogrid tend to come at a cost in numpy, and indeed the manual method is twice as fast as ogrid

Code:

import numpy as np

from timeit import timeit

A = np.arange(1000).reshape(20, 50)

def f():
    B = A.copy()
    m, n = B.shape
    I, J = np.mgrid[:m*1000:1000, :n*500:500]
    B += I+J
    return B

def g():
    B = A.copy()
    m, n = B.shape
    I, J = np.ogrid[:m*1000:1000, :n*500:500]
    B += I+J
    return B

def h():
    B = A.copy()
    m, n = B.shape
    I, J = np.ogrid[:m*1000:1000, :n*500:500]
    B += I
    B += J
    return B

def i():
    B = A.copy()
    m, n = B.shape
    BT = B.T
    BT += np.arange(0, 1000*m, 1000)
    B += np.arange(0, 500*n, 500)
    return B

def j():
    B = A.copy()
    m, n = B.shape
    B += np.arange(0, 1000*m, 1000)[:, None]
    B += np.arange(0, 500*n, 500)
    return B


assert np.all(f()==h())
assert np.all(g()==h())
assert np.all(i()==h())
assert np.all(j()==h())

print(timeit(f, number=10000))
print(timeit(g, number=10000))
print(timeit(h, number=10000))
print(timeit(i, number=10000))
print(timeit(j, number=10000))

Sample run:

0.289166528998976    # mgrid                                                                                               
0.25259370900130307  # ogrid 1 step                                                                                               
0.24528862700026366  # ogrid 2 steps                                                                                               
0.09056068700010655  # manual transpose                                                                                             
0.08238107499892067  # manual add dim
Sign up to request clarification or add additional context in comments.

Comments

3

You can use np.mgrid:

arr = np.random.uniform(size=(5,5))

n_rows, n_cols = arr.shape
r, c = np.ogrid[0:n_rows, 0:n_cols]
arr -= 1000 * r + 500 * c

2 Comments

That is great - exactly what I was looking for, thank you.
Better use ogrid. The exact equivalent is arr -= 1000 * r + 500 * c.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.