23

is there any way in numpy to get a reference to the array diagonal? I want my array diagonal to be divided by a certain factor Thanks

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
Luca Fiaschi
  • 3,145
  • 7
  • 31
  • 44

4 Answers4

29

If X is your array and c is the factor,

X[np.diag_indices_from(X)] /= c

See diag_indices_from in the Numpy manual.

Fred Foo
  • 355,277
  • 75
  • 744
  • 836
21

A quick way to access the diagonal of a square (n,n) numpy array is with arr.flat[::n+1]:

n = 1000
c = 20
a = np.random.rand(n,n)

a[np.diag_indices_from(a)] /= c # 119 microseconds
a.flat[::n+1] /= c # 25.3 microseconds
kwgoodman
  • 2,088
  • 16
  • 7
17

The np.fill_diagonal function is quite fast:

np.fill_diagonal(a, a.diagonal() / c)

where a is your array and c is your factor. On my machine, this method was as fast as @kwgoodman's a.flat[::n+1] /= c method, and in my opinion a bit clearer (but not as slick).

hunse
  • 3,175
  • 20
  • 25
9

Comparing the above 3 methods:

import numpy as np
import timeit

n = 1000
c = 20
a = np.random.rand(n,n)
a1 = a.copy()
a2 = a.copy()
a3 = a.copy()

t1 = np.zeros(1000)
t2 = np.zeros(1000)
t3 = np.zeros(1000)

for i in range(1000):
    start = timeit.default_timer()
    a1[np.diag_indices_from(a1)] /= c 
    stop = timeit.default_timer()
    t1[i] = start-stop

    start = timeit.default_timer()
    a2.flat[::n+1] /= c
    stop = timeit.default_timer()
    t2[i] = start-stop

    start = timeit.default_timer()
    np.fill_diagonal(a3,a3.diagonal() / c)
    stop = timeit.default_timer()
    t3[i] = start-stop

print([t1.mean(), t1.std()])
print([t2.mean(), t2.std()])
print([t3.mean(), t3.std()])

[-4.5693619907979154e-05, 9.3142851395411316e-06]
[-2.338075107036275e-05, 6.7119609571872443e-06]
[-2.3731951987429056e-05, 8.0455946813059586e-06]

So you can see that the np.flat method is the fastest but marginally. When I ran this for a few more times there were times when the fill_diagonal method was slightly faster. But readability wise its probably worth using the fill_diagonal method.

sachinruk
  • 9,571
  • 12
  • 55
  • 86