NumPy ऐरे में निकटतम शून्य के लिए दूरी का पता लगाएं


12

मान लीजिए कि मेरे पास एक अंक है:

x = np.array([0, 1, 2, 0, 4, 5, 6, 7, 0, 0])

प्रत्येक सूचकांक पर, मैं निकटतम शून्य मान की दूरी का पता लगाना चाहता हूं। यदि स्थिति स्वयं शून्य है तो शून्य को दूरी के रूप में लौटाएं। बाद में, हम केवल निकटतम शून्य के लिए दूरी में रुचि रखते हैं जो वर्तमान स्थिति के दाईं ओर है। सुपर भोले दृष्टिकोण कुछ इस तरह होगा:

out = np.full(x.shape[0], x.shape[0]-1)
for i in range(x.shape[0]):
    j = 0
    while i + j < x.shape[0]:
        if x[i+j] == 0:
            break
        j += 1
    out[i] = j

और उत्पादन होगा:

array([0, 2, 1, 0, 4, 3, 2, 1, 0, 0])

मैं शून्य में आउटपुट के बीच उलटी गिनती / गिरावट पैटर्न देख रहा हूँ। इसलिए, मैं शून्य (यानी zero_indices = np.argwhere(x == 0).flatten()) के स्थानों का उपयोग करने में सक्षम हो सकता हूं

रैखिक समय में वांछित आउटपुट प्राप्त करने का सबसे तेज़ तरीका क्या है?


क्या होगा अगर वहाँ सही करने के लिए कोई 0 है?
दिवाकर

बड़ा सवाल है, तो यह अंतिम सूचकांक के लिए डिफ़ॉल्ट चाहिए (यानी, x.shape[0] - 1)
slaw

जवाबों:


8

# 1: Searchsorted एक वेक्टर तरीके से रैखिक-समय के लिए बचाव के लिए (सुब्बा लोगों के आने से पहले)!

mask_z = x==0
idx_z = np.flatnonzero(mask_z)
idx_nz = np.flatnonzero(~mask_z)

# Cover for the case when there's no 0 left to the right
# (for same results as with posted loop-based solution)
if x[-1]!=0:
    idx_z = np.r_[idx_z,len(x)]

out = np.zeros(len(x), dtype=int)
idx = np.searchsorted(idx_z, idx_nz)
out[~mask_z] = idx_z[idx] - idx_nz

दृष्टिकोण # 2: कुछ के साथ एक और cumsum-

mask_z = x==0
idx_z = np.flatnonzero(mask_z)

# Cover for the case when there's no 0 left to the right
if x[-1]!=0:
    idx_z = np.r_[idx_z,len(x)]

out = idx_z[np.r_[False,mask_z[:-1]].cumsum()] - np.arange(len(x))

वैकल्पिक रूप से, कार्यक्षमता cumsumद्वारा प्रतिस्थापित किया जा सकता है के अंतिम चरण repeat-

r = np.r_[idx_z[0]+1,np.diff(idx_z)]
out = np.repeat(idx_z,r)[:len(x)] - np.arange(len(x))

दृष्टिकोण # 3: ज्यादातर के साथ एक और सिर्फ cumsum-

mask_z = x==0
idx_z = np.flatnonzero(mask_z)

pp = np.full(len(x), -1)
pp[idx_z[:-1]] = np.diff(idx_z) - 1
if idx_z[0]==0:
    pp[0] = idx_z[1]
else:
    pp[0] = idx_z[0]
out = pp.cumsum()

# Handle boundary case and assigns 0s at original 0s places
out[idx_z[-1]:] = np.arange(len(x)-idx_z[-1],0,-1)
out[mask_z] = 0

4

आप दूसरी तरफ से काम कर सकते थे। कितने गैर शून्य अंक पारित किए हैं और इसे सरणी में तत्व को असाइन करें पर एक काउंटर रखें। यदि आप 0 देखते हैं, तो काउंटर को 0 पर रीसेट करें

संपादित करें: यदि दाईं ओर कोई शून्य नहीं है, तो आपको एक और चेक की आवश्यकता है

x = np.array([0, 1, 2, 0, 4, 5, 6, 7, 0, 0])
out = x 
count = 0 
hasZero = False 
for i in range(x.shape[0]-1,-1,-1):
    if out[i] != 0:
        if not hasZero: 
            out[i] = x.shape[0]-1
        else:
            count += 1
            out[i] = count
    else:
        hasZero = True
        count = 0
print(out)

2

पूर्ववर्ती शून्य की दूरी निर्धारित करने के लिए आप प्रत्येक स्थिति के सूचकांकों और संचयी अधिकतम शून्य स्थितियों के बीच के अंतर का उपयोग कर सकते हैं। इसे आगे और पीछे किया जा सकता है। पूर्ववर्ती (या अगले) शून्य के आगे और पीछे की दूरी के बीच न्यूनतम निकटतम होगा:

import numpy as np

indices  = np.arange(x.size)
zeroes   = x==0
forward  = indices - np.maximum.accumulate(indices*zeroes)  # forward distance
forward[np.cumsum(zeroes)==0] = x.size-1                    # handle absence of zero from edge
forward  = forward * (x!=0)                                 # set zero positions to zero                

zeroes   = zeroes[::-1]
backward = indices - np.maximum.accumulate(indices*zeroes) # backward distance
backward[np.cumsum(zeroes)==0] = x.size-1                  # handle absence of zero from edge
backward = backward[::-1] * (x!=0)                         # set zero positions to zero

distZero = np.minimum(forward,backward) # closest distance (minimum)

परिणाम:

distZero
# [0, 1, 1, 0, 1, 2, 2, 1, 0, 0]

forward
# [0, 1, 2, 0, 1, 2, 3, 4, 0, 0]

backward
# [0, 2, 1, 0, 4, 3, 2, 1, 0, 0]

विशेष मामला जहां बाहरी किनारों पर कोई शून्य मौजूद नहीं है:

x = np.array([3, 1, 2, 0, 4, 5, 6, 0,8,8])

forward:  [9 9 9 0 1 2 3 0 1 2]
backward: [3 2 1 0 3 2 1 0 9 9]
distZero: [3 2 1 0 1 2 1 0 1 2]

कोई शून्य के साथ भी काम करता है

[संपादित करें]  गैर-खस्ता समाधान ...

यदि आप एक ओ (एन) समाधान की तलाश कर रहे हैं, जिसे सुन्न करने की आवश्यकता नहीं है, तो आप इटर्लस से संचित फ़ंक्शन का उपयोग करके इस रणनीति को लागू कर सकते हैं:

x = [0, 1, 2, 0, 4, 5, 6, 7, 0, 0]

from itertools import accumulate

maxDist  = len(x) - 1
zeroes   = [maxDist*(v!=0) for v in x]
forward  = [*accumulate(zeroes,lambda d,v:min(maxDist,(d+1)*(v!=0)))]
backward = accumulate(zeroes[::-1],lambda d,v:min(maxDist,(d+1)*(v!=0)))
backward = [*backward][::-1]
distZero = [min(f,b) for f,b in zip(forward,backward)]                      

print("x",x)
print("f",forward)
print("b",backward)
print("d",distZero)

उत्पादन:

x [0, 1, 2, 0, 4, 5, 6, 7, 0, 0]
f [0, 1, 2, 0, 1, 2, 3, 4, 0, 0]
b [0, 2, 1, 0, 4, 3, 2, 1, 0, 0]
d [0, 1, 1, 0, 1, 2, 2, 1, 0, 0]

यदि आप किसी भी पुस्तकालय का उपयोग नहीं करना चाहते हैं, तो आप एक लूप में मैन्युअल रूप से दूरी जमा कर सकते हैं:

x = [0, 1, 2, 0, 4, 5, 6, 7, 0, 0]
forward,backward = [],[]
fDist = bDist = maxDist = len(x)-1
for f,b in zip(x,reversed(x)):
    fDist = min(maxDist,(fDist+1)*(f!=0))
    forward.append(fDist)
    bDist = min(maxDist,(bDist+1)*(b!=0))
    backward.append(bDist)
backward = backward[::-1]
distZero = [min(f,b) for f,b in zip(forward,backward)]

print("x",x)
print("f",forward)
print("b",backward)
print("d",distZero)

उत्पादन:

x [0, 1, 2, 0, 4, 5, 6, 7, 0, 0]
f [0, 1, 2, 0, 1, 2, 3, 4, 0, 0]
b [0, 2, 1, 0, 4, 3, 2, 1, 0, 0]
d [0, 1, 1, 0, 1, 2, 2, 1, 0, 0]

0

मेरा पहला अंतर्ज्ञान स्लाइसिंग का उपयोग करना होगा। यदि एक्स एक सुन्न सरणी के बजाय एक सामान्य सूची हो सकती है, तो आप उपयोग कर सकते हैं

 out = [x[i:].index(0) for i,_ in enumerate(x)]

यदि सुन्नता आवश्यक है, तो आप उपयोग कर सकते हैं

 out = [np.where(x[i:]==0)[0][0] for i,_ in enumerate(x)]

लेकिन यह कम कुशल है क्योंकि आप मूल्य के दाईं ओर सभी शून्य स्थानों को ढूंढ रहे हैं और फिर बस पहले बाहर खींच रहे हैं। लगभग निश्चित रूप से सुन्न में ऐसा करने का एक बेहतर तरीका है।


0

संपादित करें: मुझे खेद है, मुझे गलत समझा गया। यह आपको निकटतम शून्य की दूरी देगा - यह बाएं या दाएं पर हो सकता है। लेकिन आप d_rightमध्यवर्ती परिणाम के रूप में उपयोग कर सकते हैं । यह हालांकि दाईं ओर कोई शून्य नहीं होने के किनारे के मामले को कवर नहीं करता है।

import numpy as np

x = np.array([0, 1, 2, 0, 4, 5, 6, 7, 0, 0])

# Get the distance to the closest zero from the left:
zeros = x == 0
zero_locations = np.argwhere(x == 0).flatten()
zero_distances = np.diff(np.insert(zero_locations, 0, 0))

temp = x.copy()
temp[~zeros] = 1
temp[zeros] = -(zero_distances-1)
d_left = np.cumsum(temp) - 1

# Get the distance to the closest zero from the right:
zeros = x[::-1] == 0
zero_locations = np.argwhere(x[::-1] == 0).flatten()
zero_distances = np.diff(np.insert(zero_locations, 0, 0))

temp = x.copy()
temp[~zeros] = 1
temp[zeros] = -(zero_distances-1)
d_right = np.cumsum(temp) - 1
d_right = d_right[::-1]

# Get the smallest distance from both sides:
smallest_distances = np.min(np.stack([d_left, d_right]), axis=0)
# np.array([0, 1, 1, 0, 1, 2, 2, 1, 0, 0])
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.