আমার কাছে নিম্পিতে একটি 1 ডি অ্যারে রয়েছে এবং আমি সূচকের অবস্থানটি খুঁজতে চাই যেখানে একটি মান ন্যালি অ্যারেতে মূল্য ছাড়িয়ে যায়।
যেমন
aa = range(-10,10)
aa
যেখানে অবস্থানটি সন্ধান করুন , মানটি 5
অতিক্রম করে।
আমার কাছে নিম্পিতে একটি 1 ডি অ্যারে রয়েছে এবং আমি সূচকের অবস্থানটি খুঁজতে চাই যেখানে একটি মান ন্যালি অ্যারেতে মূল্য ছাড়িয়ে যায়।
যেমন
aa = range(-10,10)
aa
যেখানে অবস্থানটি সন্ধান করুন , মানটি 5
অতিক্রম করে।
উত্তর:
এটি কিছুটা দ্রুত (এবং আরও সুন্দর দেখাচ্ছে)
np.argmax(aa>5)
যেহেতু argmax
প্রথমটি থামবে True
("সর্বাধিক মানগুলির একাধিক সংখ্যার ক্ষেত্রে, প্রথম ঘটনার সাথে সম্পর্কিত সূচকগুলি ফিরে আসবে" ") এবং অন্য কোনও তালিকা সংরক্ষণ করে না।
In [2]: N = 10000
In [3]: aa = np.arange(-N,N)
In [4]: timeit np.argmax(aa>N/2)
100000 loops, best of 3: 52.3 us per loop
In [5]: timeit np.where(aa>N/2)[0][0]
10000 loops, best of 3: 141 us per loop
In [6]: timeit np.nonzero(aa>N/2)[0][0]
10000 loops, best of 3: 142 us per loop
argmax
প্রথমে থামবে বলে মনে হচ্ছে না True
। (এটি True
বিভিন্ন পজিশনে একক দিয়ে বুলিয়ান অ্যারে তৈরির মাধ্যমে পরীক্ষা করা যেতে পারে )) গতি সম্ভবত এই বিষয় দ্বারা ব্যাখ্যা করা হয়েছে যে argmax
আউটপুট তালিকা তৈরি করার প্রয়োজন নেই।
argmax
।
aa
বাছাই করা হয়েছে কিনা , @ মাইকেল এর উত্তর হিসাবে)।
argmax
১০ মিলিয়ন-এলিমেন্ট বুলিয়ান অ্যারেগুলিতে True
নম্পপি ১.১১.২ ব্যবহার করে এবং বিভিন্ন পদক্ষেপের অবস্থানটি ব্যবহার করে বিভিন্ন অবস্থানে একটি একক দিয়ে দৌড়েছি True
। সুতরাং 1.11.2 এর argmax
বুলিয়ান অ্যারেগুলিতে "শর্ট সার্কিট" বলে মনে হচ্ছে।
আপনার অ্যারের অনুসারে বাছাই করা সামগ্রী দেওয়া হয়েছে, এর চেয়ে আরও দ্রুত পদ্ধতি রয়েছে: সন্ধান করা ।
import time
N = 10000
aa = np.arange(-N,N)
%timeit np.searchsorted(aa, N/2)+1
%timeit np.argmax(aa>N/2)
%timeit np.where(aa>N/2)[0][0]
%timeit np.nonzero(aa>N/2)[0][0]
# Output
100000 loops, best of 3: 5.97 µs per loop
10000 loops, best of 3: 46.3 µs per loop
10000 loops, best of 3: 154 µs per loop
10000 loops, best of 3: 154 µs per loop
+1
সাথে বিশ্রী এড়াতে পারবেনnp.searchsorted(..., side='right')
side
সাজানো অ্যারেতে যদি পুনরাবৃত্তি মান থাকে তবে আর্গুমেন্টটি কেবল একটি পার্থক্য করে। এটি প্রত্যাবর্তিত সূচকের অর্থ পরিবর্তন করে না, যা সর্বদা সূচক যা আপনি কোয়েরি মানটি সন্নিবেশ করিয়ে দিতে পারেন, নিম্নলিখিত সমস্ত এন্ট্রিগুলিকে ডানে সরিয়ে দিতে এবং সাজানো অ্যারে বজায় রাখতে পারে।
side
একই মানের হলে @ গাসের একটি প্রভাব থাকে। বাছাই করা অ্যারেতে পুনরাবৃত্তি করা মানগুলি কেবল প্রভাবকে অতিরঞ্জিত করে (উভয় পক্ষের মধ্যে পার্থক্যটি সাজানো অ্যারেতে যে পরিমাণ সন্নিবেশ করা হচ্ছে তার সংখ্যাটি কতবার)। নেই , ফিরে সূচক অর্থ পরিবর্তন যদিও সেই সূচকের এ সাজানো অ্যারের মধ্যে মান ঢোকাতে ফলে অ্যারের পরিবর্তন করে না। একটি সূক্ষ্ম কিন্তু গুরুত্বপূর্ণ পার্থক্য; আসলে এই উত্তরটি যদি না থাকে তবে ভুল সূচক দেয় । side
N/2
aa
N/2
না দেওয়া হয় তবে এই উত্তরটি বন্ধ করে দেওয়া হবে aa
। সঠিক ফর্মটি হবে np.searchsorted(aa, N/2, side='right')
(ছাড়া +1
)। উভয় ফর্ম অন্যথায় একই সূচক দেয়। N
বিজোড় হওয়ার পরীক্ষার কেসটি বিবেচনা করুন (এবং N/2.0
পাইথন 2 ব্যবহার করলে ভাসা জোর করে চাপিয়ে দেওয়া)।
আমি এটিতে আগ্রহীও ছিলাম এবং প্রস্তাবিত সমস্ত উত্তরগুলিকে পারফ্ল্লোটের সাথে তুলনা করেছি । (অস্বীকৃতি: আমি পার্ফ্লট্লোর লেখক))
যদি আপনি জানেন যে আপনি যে অ্যারেটি সন্ধান করছেন সেটি ইতিমধ্যে বাছাই হয়ে গেছে , তবে
numpy.searchsorted(a, alpha)
তোমার জন্য. এটি একটি ধ্রুবক-সময় অপারেশন, অর্থাৎ গতি অ্যারের আকারের উপর নির্ভর করে না । আপনি এর চেয়ে দ্রুত পেতে পারবেন না।
আপনি যদি আপনার অ্যারে সম্পর্কে কিছু না জানেন তবে আপনি ভুল করছেন না
numpy.argmax(a > alpha)
ইতিমধ্যে সাজানো:
পাঁচমিশালী:
প্লটটি পুনরুত্পাদন করার কোড:
import numpy
import perfplot
alpha = 0.5
def argmax(data):
return numpy.argmax(data > alpha)
def where(data):
return numpy.where(data > alpha)[0][0]
def nonzero(data):
return numpy.nonzero(data > alpha)[0][0]
def searchsorted(data):
return numpy.searchsorted(data, alpha)
out = perfplot.show(
# setup=numpy.random.rand,
setup=lambda n: numpy.sort(numpy.random.rand(n)),
kernels=[
argmax, where,
nonzero,
searchsorted
],
n_range=[2**k for k in range(2, 20)],
logx=True,
logy=True,
xlabel='len(array)'
)
np.searchsorted
ধ্রুবক সময় নয়। এটা আসলে O(log(n))
। তবে আপনার পরীক্ষার কেসটি আসলে searchsorted
(যা O(1)
) এর সেরা কেসটিকে বেঞ্চমার্ক করে ।
searchsorted
(বা যে কোনও অ্যালগোরিদম) O(log(n))
বাছাই করা অভিন্ন বিতরণ করা ডেটার জন্য বাইনারি অনুসন্ধান করতে পারে । সম্পাদনা করুন: searchsorted
হয় একটি বাইনারি অনুসন্ধান।
একটি ক্ষেত্রে range
বা অন্য কোন সুসংগত বৃদ্ধি অ্যারের আপনি কেবল সূচক প্রোগ্রামেটিক্যালি কোন প্রয়োজন আসলে পুনরুক্তি করতে এ সব অ্যারের উপর নিরূপণ করতে পারেন:
def first_index_calculate_range_like(val, arr):
if len(arr) == 0:
raise ValueError('no value greater than {}'.format(val))
elif len(arr) == 1:
if arr[0] > val:
return 0
else:
raise ValueError('no value greater than {}'.format(val))
first_value = arr[0]
step = arr[1] - first_value
# For linearly decreasing arrays or constant arrays we only need to check
# the first element, because if that does not satisfy the condition
# no other element will.
if step <= 0:
if first_value > val:
return 0
else:
raise ValueError('no value greater than {}'.format(val))
calculated_position = (val - first_value) / step
if calculated_position < 0:
return 0
elif calculated_position > len(arr) - 1:
raise ValueError('no value greater than {}'.format(val))
return int(calculated_position) + 1
কেউ সম্ভবত কিছুটা উন্নতি করতে পারে। আমি নিশ্চিত করেছি যে এটি কয়েকটি নমুনা অ্যারে এবং মানগুলির জন্য সঠিকভাবে কাজ করে তবে এর অর্থ এই নয় যে সেখানে ভুল হতে পারে না, বিশেষত বিবেচনা করে যে এটি ভাসমান ব্যবহার করে ...
>>> import numpy as np
>>> first_index_calculate_range_like(5, np.arange(-10, 10))
16
>>> np.arange(-10, 10)[16] # double check
6
>>> first_index_calculate_range_like(4.8, np.arange(-10, 10))
15
প্রদত্ত যে এটি কোনও পুনরাবৃত্তি ছাড়াই অবস্থানটি গণনা করতে পারে এটি ধ্রুবক সময় ( O(1)
) এবং সম্ভবত উল্লিখিত সমস্ত পন্থাগুলি বীট করতে পারে। তবে এটির জন্য ধ্রুব পদক্ষেপ প্রয়োজন, অন্যথায় এটি ভুল ফলাফল আনবে।
আরও সাধারণ পদ্ধতির একটি নাম্বা ফাংশন ব্যবহার করা হবে:
@nb.njit
def first_index_numba(val, arr):
for idx in range(len(arr)):
if arr[idx] > val:
return idx
return -1
এটি যে কোনও অ্যারের জন্য কাজ করবে তবে এটি অ্যারের উপরে পুনরাবৃত্তি করতে হবে, সুতরাং গড় ক্ষেত্রে এটি হবে O(n)
:
>>> first_index_numba(4.8, np.arange(-10, 10))
15
>>> first_index_numba(5, np.arange(-10, 10))
16
যদিও নিকো শ্ল্যামার ইতিমধ্যে কিছু মানদণ্ড সরবরাহ করেছেন আমি ভেবেছিলাম আমার নতুন সমাধানগুলি অন্তর্ভুক্ত করা এবং বিভিন্ন "মান" পরীক্ষার জন্য এটি কার্যকর হতে পারে।
পরীক্ষা সেটআপ:
import numpy as np
import math
import numba as nb
def first_index_using_argmax(val, arr):
return np.argmax(arr > val)
def first_index_using_where(val, arr):
return np.where(arr > val)[0][0]
def first_index_using_nonzero(val, arr):
return np.nonzero(arr > val)[0][0]
def first_index_using_searchsorted(val, arr):
return np.searchsorted(arr, val) + 1
def first_index_using_min(val, arr):
return np.min(np.where(arr > val))
def first_index_calculate_range_like(val, arr):
if len(arr) == 0:
raise ValueError('empty array')
elif len(arr) == 1:
if arr[0] > val:
return 0
else:
raise ValueError('no value greater than {}'.format(val))
first_value = arr[0]
step = arr[1] - first_value
if step <= 0:
if first_value > val:
return 0
else:
raise ValueError('no value greater than {}'.format(val))
calculated_position = (val - first_value) / step
if calculated_position < 0:
return 0
elif calculated_position > len(arr) - 1:
raise ValueError('no value greater than {}'.format(val))
return int(calculated_position) + 1
@nb.njit
def first_index_numba(val, arr):
for idx in range(len(arr)):
if arr[idx] > val:
return idx
return -1
funcs = [
first_index_using_argmax,
first_index_using_min,
first_index_using_nonzero,
first_index_calculate_range_like,
first_index_numba,
first_index_using_searchsorted,
first_index_using_where
]
from simple_benchmark import benchmark, MultiArgument
এবং প্লটগুলি ব্যবহার করে তৈরি করা হয়েছিল:
%matplotlib notebook
b.plot()
b = benchmark(
funcs,
{2**i: MultiArgument([0, np.arange(2**i)]) for i in range(2, 20)},
argument_name="array size")
নাম্বা ফাংশন ক্যালকুলেট-ফাংশন এবং অনুসন্ধানের ক্রিয়াকলাপের পরে সর্বোত্তম কাজ করে। অন্যান্য সমাধানগুলি আরও খারাপ সম্পাদন করে।
b = benchmark(
funcs,
{2**i: MultiArgument([2**i-2, np.arange(2**i)]) for i in range(2, 20)},
argument_name="array size")
ছোট অ্যারেগুলির জন্য নাম্বা ফাংশনটি আশ্চর্যজনকভাবে দ্রুত সঞ্চালন করে, তবে বড় অ্যারেগুলির জন্য এটি গণনা-ফাংশন এবং অনুসন্ধানের ক্রিয়াকলাপ দ্বারা ছাপিয়ে যায়।
b = benchmark(
funcs,
{2**i: MultiArgument([np.sqrt(2**i), np.arange(2**i)]) for i in range(2, 20)},
argument_name="array size")
এটি আরও আকর্ষণীয়। আবার নাম্বা এবং ক্যালকুলেট ফাংশন দুর্দান্ত সঞ্চালন করে, তবে এটি প্রকৃতপক্ষে অনুসন্ধানের সবচেয়ে খারাপ ক্ষেত্রে ট্রিগার করছে যা সত্যই এই ক্ষেত্রে ভাল কাজ করে না।
আর একটি আকর্ষণীয় বিষয় হ'ল এই ফাংশনটি কীভাবে আচরণ করে যদি কোনও মূল্য না থাকে যার সূচি ফিরিয়ে দেওয়া উচিত:
arr = np.ones(100)
value = 2
for func in funcs:
print(func.__name__)
try:
print('-->', func(value, arr))
except Exception as e:
print('-->', e)
এই ফলাফলের সাথে:
first_index_using_argmax
--> 0
first_index_using_min
--> zero-size array to reduction operation minimum which has no identity
first_index_using_nonzero
--> index 0 is out of bounds for axis 0 with size 0
first_index_calculate_range_like
--> no value greater than 2
first_index_numba
--> -1
first_index_using_searchsorted
--> 101
first_index_using_where
--> index 0 is out of bounds for axis 0 with size 0
অনুসন্ধান করা, আরগম্যাক্স এবং নাম্বা কেবল একটি ভুল মান দেয় value তবে searchsorted
এবং numba
এমন একটি সূচক ফেরত করুন যা অ্যারের জন্য বৈধ সূচক নয়।
ফাংশন where
, min
, nonzero
এবং calculate
একটি ব্যতিক্রম নিক্ষেপ করা। তবে কেবল ব্যতিক্রমগুলি calculate
আসলে কার্যকর কিছু বলে।
এর অর্থ হ'ল একজনকে এই কলগুলিকে একটি উপযুক্ত মোড়কের ফাংশনে আবদ্ধ করতে হবে যা ব্যতিক্রম বা অবৈধ রিটার্ন মানগুলি ধরবে এবং যথাযথভাবে হ্যান্ডেল করবে, কমপক্ষে যদি আপনি নিশ্চিত না হন তবে মানটি অ্যারেতে থাকতে পারে কিনা।
দ্রষ্টব্য: গণনা এবং searchsorted
বিকল্পগুলি কেবলমাত্র বিশেষ শর্তে কাজ করে। "গণনা" ফাংশনটির জন্য একটি ধ্রুব পদক্ষেপ প্রয়োজন এবং অনুসন্ধানের জন্য অ্যারে বাছাই করা দরকার। সুতরাং এটি সঠিক পরিস্থিতিতে কার্যকর হতে পারে তবে এই সমস্যার সাধারণ সমাধান নয় n't কেস আপনার সাথে ডিল করছি সাজানো পাইথন তালিকা আপনি কটাক্ষপাত করা করতে চাইবেন দ্বিখণ্ডিত করা পরিবর্তে Numpys searchsorted ব্যবহারের মডিউল।