Max value per diagonal in 2d array
Use ndarray.diagonal
v = [max(c.diagonal(-i)) for i in range(b.shape[0])]print(v) # [0, 13, 3, 6, -4]
Not sure exactly how efficient this is considering the advanced indexing involved, but this is one way to do that:
import numpy as npa = np.array([8, 18, 5, 15, 12])b = a[:, None] - a# Fill lower triangle with largest negativeb[np.tril_indices(len(a))] = np.iinfo(b.dtype).min # np.finfo for float# Put diagonals as rowss = b.strides[1]diags = np.ndarray((len(a) - 1, len(a) - 1), b.dtype, b, offset=s, strides=(s, (len(a) + 1) * s))# Get maximum from each row and add initial zeroc = np.r_[0, diags.max(1)]print(c)# [ 0 13 3 6 -4]
EDIT:
Another alternative, which may not be what you were looking for though, is just using Numba, for example like this:
import numpy as npimport numba as nbdef max_window_diffs_jdehesa(a): a = np.asarray(a) dtinf = np.iinfo(b.dtype) if np.issubdtype(b.dtype, np.integer) else np.finfo(b.dtype) out = np.full_like(a, dtinf.min) _pwise_diffs(a, out) return out@nb.njit(parallel=True)def _pwise_diffs(a, out): out[0] = 0 for w in nb.prange(1, len(a)): for i in range(len(a) - w): out[w] = max(a[i] - a[i + w], out[w])a = np.array([8, 18, 5, 15, 12])print(max_window_diffs(a))# [ 0 13 3 6 -4]
Comparing these methods to the original:
import numpy as npimport numba as nbdef max_window_diffs_orig(a): a = np.asarray(a) b = a - a[:, None] out = np.zeros(len(a), b.dtype) out[-1] = b[-1, 0] for i in range(1, len(a) - 1): out[i] = np.diag(b, -i).max() return outdef max_window_diffs_jdehesa_np(a): a = np.asarray(a) b = a[:, None] - a dtinf = np.iinfo(b.dtype) if np.issubdtype(b.dtype, np.integer) else np.finfo(b.dtype) b[np.tril_indices(len(a))] = dtinf.min s = b.strides[1] diags = np.ndarray((len(a) - 1, len(a) - 1), b.dtype, b, offset=s, strides=(s, (len(a) + 1) * s)) return np.concatenate([[0], diags.max(1)])def max_window_diffs_jdehesa_nb(a): a = np.asarray(a) dtinf = np.iinfo(b.dtype) if np.issubdtype(b.dtype, np.integer) else np.finfo(b.dtype) out = np.full_like(a, dtinf.min) _pwise_diffs(a, out) return out@nb.njit(parallel=True)def _pwise_diffs(a, out): out[0] = 0 for w in nb.prange(1, len(a)): for i in range(len(a) - w): out[w] = max(a[i] - a[i + w], out[w])np.random.seed(0)a = np.random.randint(0, 100, size=100)r = max_window_diffs_orig(a)print((max_window_diffs_jdehesa_np(a) == r).all())# Trueprint((max_window_diffs_jdehesa_nb(a) == r).all())# True%timeit max_window_diffs_orig(a)# 348 µs ± 986 ns per loop (mean ± std. dev. of 7 runs, 1000 loops each)%timeit max_window_diffs_jdehesa_np(a)# 91.7 µs ± 1.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)%timeit max_window_diffs_jdehesa_nb(a)# 19.7 µs ± 88.1 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)np.random.seed(0)a = np.random.randint(0, 100, size=10000)%timeit max_window_diffs_orig(a)# 651 ms ± 26 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)%timeit max_window_diffs_jdehesa_np(a)# 1.61 s ± 6.19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)%timeit max_window_diffs_jdehesa_nb(a)# 22 ms ± 967 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
The first one may be a bit better for smaller arrays, but doesn't work well for bigger ones. Numba on the other hand is pretty good in all cases.
You can use numpy.diagonal
:
a = np.array([8, 18, 5,15,12])b = a - a[:, None]c = np.tril(b)for i in range(b.shape[0]): print(max(c.diagonal(-i)))
Output:
01336-4