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)
কুচি কুচি করে কাঁটা বাঁধাকপি

উত্তর:


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

তবে এটি কম দক্ষ কারণ আপনি সমস্ত শূন্য অবস্থানের মানটির ডান দিকে খুঁজে পাচ্ছেন এবং তারপরে কেবল প্রথমটি খুঁজে বের করছেন। প্রায় স্পষ্টতই এটি করার আরও ভাল উপায় num


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])
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.