2d सरणी में अधिकतम मूल्य प्रति विकर्ण


9

मेरे पास सरणी है और डायनेमिक विंडो के साथ अधिकतम रोलिंग अंतर की आवश्यकता है।

a = np.array([8, 18, 5,15,12])
print (a)
[ 8 18  5 15 12]

इसलिए पहले मैं अपने आप में अंतर पैदा करता हूं:

b = a - a[:, None]
print (b)
[[  0  10  -3   7   4]
 [-10   0 -13  -3  -6]
 [  3  13   0  10   7]
 [ -7   3 -10   0  -3]
 [ -4   6  -7   3   0]]

फिर ऊपरी त्रिकोण मैट्रिक्स को 0 पर बदलें:

c = np.tril(b)
print (c)
[[  0   0   0   0   0]
 [-10   0   0   0   0]
 [  3  13   0   0   0]
 [ -7   3 -10   0   0]
 [ -4   6  -7   3   0]]

अंतिम विकर्ण प्रति अधिकतम मान की आवश्यकता है, इसलिए इसका मतलब है:

max([0,0,0,0,0]) = 0  
max([-10,13,-10,3]) = 13
max([3,3,-7]) = 3
max([-7,6]) = 6
max([-4]) = -4

इसलिए अपेक्षित आउटपुट है:

[0, 13, 3, 6, -4]

कुछ अच्छा सदिश समाधान क्या है? या अपेक्षित आउटपुट के लिए कुछ और तरीका संभव है?

जवाबों:


3

निश्चित रूप से यह शामिल नहीं है कि उन्नत अनुक्रमण पर विचार करना कितना कुशल है, लेकिन यह ऐसा करने का एक तरीका है:

import numpy as np

a = np.array([8, 18, 5, 15, 12])
b = a[:, None] - a
# Fill lower triangle with largest negative
b[np.tril_indices(len(a))] = np.iinfo(b.dtype).min  # np.finfo for float
# Put diagonals as rows
s = 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 zero
c = np.r_[0, diags.max(1)]
print(c)
# [ 0 13  3  6 -4]

संपादित करें:

एक अन्य विकल्प, जो हो सकता है कि आप के लिए क्या देख रहे थे, उदाहरण के लिए, बस निम्बा का उपयोग नहीं कर रहा है:

import numpy as np
import numba as nb

def 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]

इन तरीकों की तुलना मूल से करें:

import numpy as np
import numba as nb

def 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 out

def 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())
# True
print((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)

पहले वाला छोटे सरणियों के लिए थोड़ा बेहतर हो सकता है, लेकिन बड़े लोगों के लिए अच्छा काम नहीं करता है। दूसरी ओर नंबा सभी मामलों में बहुत अच्छा है।


क्या आप उत्तर देने के लिए कुछ समय जोड़ सकते हैं, उदाहरण के लिए 10, 100, 1000 मान a?
jezrael

1
@ जेजराएल ने संभव नंबा समाधान और कुछ समय के उपाय जोड़े। मेरा न्यूमपी सॉल्यूशन वास्तव में अच्छा नहीं है, नुम्बा अच्छा है, हालांकि मुझे यकीन नहीं है कि यह आपके लिए उपयोगी है।
jdehesa



1

यहां एक सदिश समाधान दिया गया है strides-

from skimage.util import view_as_windows

n = len(a)
z = np.zeros(n-1,dtype=a.dtype)
p = np.concatenate((a,z))

s = view_as_windows(p,n)
mask = np.tri(n,k=-1,dtype=bool)[:,::-1]
v = s[0]-s
out = np.where(mask,v.min()-1,v).max(1)

स्मृति-दक्षता के लिए एक-पाश के साथ -

n = len(a)
out = [max(a[:-i+n]-a[i:]) for i in range(n)]

उपयोग np.maxके स्थान पर maxसरणी स्मृति के बेहतर इस्तेमाल के लिए।


1
@Jzrael मुझे लगता है कि datasize पर निर्भर करता है। बड़े आकार के लिए, मुझे लगता है कि स्लाइसिंग + अधिकतम के साथ ढलान एक हो सकता है क्योंकि मेम दक्षता के कारण जीत सकता है।
दिवाकर

1

आप इस तथ्य का दुरुपयोग कर सकते हैं कि आकार के गैर-वर्ग सरणियों को फिर से आकार (N+1, N)देने (N, N+1)से विकर्णों को कॉलम के रूप में दिखाई देगा

from scipy.linalg import toeplitz
a = toeplitz([1,2,3,4], [1,4,3])
# array([[1, 4, 3],
#        [2, 1, 4],
#        [3, 2, 1],
#        [4, 3, 2]])
a.reshape(3, 4)
# array([[1, 4, 3, 2],
#        [1, 4, 3, 2],
#        [1, 4, 3, 2]])

तब आप इसका उपयोग कर सकते हैं (ध्यान दें कि मैंने साइन स्वैप किया है और निचले त्रिकोण को शून्य पर सेट किया है)

smallv = -10000  # replace this with np.nan if you have floats

a = np.array([8, 18, 5,15,12])
b = a[:, None] - a

b[np.tril_indices(len(b), -1)] = smallv
d = np.vstack((b, np.full(len(b), smallv)))

d.reshape(len(d) - 1, -1).max(0)[:-1]
# array([ 0, 13,  3,  6, -4])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.