বিদ্যমান মানের চেয়ে মূল্যবোধের প্রথম সংখ্যা greater


143

আমার কাছে নিম্পিতে একটি 1 ডি অ্যারে রয়েছে এবং আমি সূচকের অবস্থানটি খুঁজতে চাই যেখানে একটি মান ন্যালি অ্যারেতে মূল্য ছাড়িয়ে যায়।

যেমন

aa = range(-10,10)

aaযেখানে অবস্থানটি সন্ধান করুন , মানটি 5অতিক্রম করে।


2
কোনও সমাধান হতে পারে কিনা তা একটি স্পষ্ট হওয়া উচিত (যেহেতু আরগম্যাক্স উত্তরটি সে ক্ষেত্রে কার্যকর হবে না (এমব্রুস মন্তব্য হিসাবে সর্বাধিক (0,0,0,0) = 0))
seanv507

উত্তর:


198

এটি কিছুটা দ্রুত (এবং আরও সুন্দর দেখাচ্ছে)

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

103
কেবলমাত্র সাবধানতার একটি শব্দ: যদি এর ইনপুট অ্যারেতে কোনও সত্যের মান না থাকে, তবে এনপি.আরগম্যাক্স সুখে 0 ফিরে আসবে (যা এই ক্ষেত্রে আপনি যা চান তা নয়)।
এমবারাস

8
ফলাফলগুলি সঠিক, তবে আমি ব্যাখ্যাটি কিছুটা সন্দেহজনক বলে মনে করি। argmaxপ্রথমে থামবে বলে মনে হচ্ছে না True। (এটি Trueবিভিন্ন পজিশনে একক দিয়ে বুলিয়ান অ্যারে তৈরির মাধ্যমে পরীক্ষা করা যেতে পারে )) গতি সম্ভবত এই বিষয় দ্বারা ব্যাখ্যা করা হয়েছে যে argmaxআউটপুট তালিকা তৈরি করার প্রয়োজন নেই।
ডা। ভিভি

1
আমি মনে করি আপনি ঠিক আছেন, @ ডিআরভি। আমার ব্যাখ্যাটি বোঝানো হয়েছিল যে আসল উদ্দেশ্যটি সর্বাধিক সন্ধান না করার পরেও কেন এটি সঠিক ফলাফল দেয়, কেন এটি তত দ্রুত হয় না কেন আমি অভ্যন্তরীণ বিবরণগুলি বোঝার জন্য দাবি করতে পারি না argmax
জিজ্ঞাসা

1
@ জর্জি, আমি ভয় করি আমি কেন ঠিক জানি না। আমি যে বিশেষ উদাহরণটি দেখিয়েছি এটি কেবলমাত্র এটিই দ্রুত বলতে পারি, তাই আমি (আই) এটি কেন না তা ((ডাঃ ডাঃ এর মন্তব্য দেখুন) বা (ii) আরও কেস পরীক্ষা না করে (যেমন, aaবাছাই করা হয়েছে কিনা , @ মাইকেল এর উত্তর হিসাবে)।
জিজ্ঞাসাবাদ

3
@ ডিআরভি, আমি মাত্র argmax১০ মিলিয়ন-এলিমেন্ট বুলিয়ান অ্যারেগুলিতে Trueনম্পপি ১.১১.২ ব্যবহার করে এবং বিভিন্ন পদক্ষেপের অবস্থানটি ব্যবহার করে বিভিন্ন অবস্থানে একটি একক দিয়ে দৌড়েছি True। সুতরাং 1.11.2 এর argmaxবুলিয়ান অ্যারেগুলিতে "শর্ট সার্কিট" বলে মনে হচ্ছে।
উলিরিচ স্টার্ন

95

আপনার অ্যারের অনুসারে বাছাই করা সামগ্রী দেওয়া হয়েছে, এর চেয়ে আরও দ্রুত পদ্ধতি রয়েছে: সন্ধান করা

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

19
অ্যারে বাছাই হয়েছে এটি ধরে নিলে এটি সেরা উত্তর (যা আসলে প্রশ্নটিতে নির্দিষ্ট নয়)। আপনি এর +1সাথে বিশ্রী এড়াতে পারবেনnp.searchsorted(..., side='right')
askewchan

3
আমি মনে করি sideসাজানো অ্যারেতে যদি পুনরাবৃত্তি মান থাকে তবে আর্গুমেন্টটি কেবল একটি পার্থক্য করে। এটি প্রত্যাবর্তিত সূচকের অর্থ পরিবর্তন করে না, যা সর্বদা সূচক যা আপনি কোয়েরি মানটি সন্নিবেশ করিয়ে দিতে পারেন, নিম্নলিখিত সমস্ত এন্ট্রিগুলিকে ডানে সরিয়ে দিতে এবং সাজানো অ্যারে বজায় রাখতে পারে।
গাস

উভয় ক্ষেত্রে পুনরাবৃত্তি করা মান নির্বিশেষে বাছাই করা এবং sertedোকানো অ্যারে উভয় ক্ষেত্রেside একই মানের হলে @ গাসের একটি প্রভাব থাকে। বাছাই করা অ্যারেতে পুনরাবৃত্তি করা মানগুলি কেবল প্রভাবকে অতিরঞ্জিত করে (উভয় পক্ষের মধ্যে পার্থক্যটি সাজানো অ্যারেতে যে পরিমাণ সন্নিবেশ করা হচ্ছে তার সংখ্যাটি কতবার)। নেই , ফিরে সূচক অর্থ পরিবর্তন যদিও সেই সূচকের এ সাজানো অ্যারের মধ্যে মান ঢোকাতে ফলে অ্যারের পরিবর্তন করে না। একটি সূক্ষ্ম কিন্তু গুরুত্বপূর্ণ পার্থক্য; আসলে এই উত্তরটি যদি না থাকে তবে ভুল সূচক দেয় । side N/2aa
জিজ্ঞাসাবাদ

উপরের মন্তব্যে ইঙ্গিত হিসাবে, যদি N/2না দেওয়া হয় তবে এই উত্তরটি বন্ধ করে দেওয়া হবে aa। সঠিক ফর্মটি হবে np.searchsorted(aa, N/2, side='right')(ছাড়া +1)। উভয় ফর্ম অন্যথায় একই সূচক দেয়। Nবিজোড় হওয়ার পরীক্ষার কেসটি বিবেচনা করুন (এবং N/2.0পাইথন 2 ব্যবহার করলে ভাসা জোর করে চাপিয়ে দেওয়া)।
জিজ্ঞাসাবাদ

21

আমি এটিতে আগ্রহীও ছিলাম এবং প্রস্তাবিত সমস্ত উত্তরগুলিকে পারফ্ল্লোটের সাথে তুলনা করেছি । (অস্বীকৃতি: আমি পার্ফ্লট্লোর লেখক))

যদি আপনি জানেন যে আপনি যে অ্যারেটি সন্ধান করছেন সেটি ইতিমধ্যে বাছাই হয়ে গেছে , তবে

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

4
np.searchsortedধ্রুবক সময় নয়। এটা আসলে O(log(n))। তবে আপনার পরীক্ষার কেসটি আসলে searchsorted(যা O(1)) এর সেরা কেসটিকে বেঞ্চমার্ক করে ।
এমসিফার্ট

@ সাইফের্ট ও (লগ (এন)) দেখতে আপনার কী ধরণের ইনপুট অ্যারে / আলফা দরকার?
নিকো শ্ল্যামার

1
সূচি স্কয়ার্ট (দৈর্ঘ্য) এ আইটেমটি পাওয়া খুব খারাপ পারফরম্যান্সের দিকে নিয়ে যায়। আমি এখানে একটি উত্তরও লিখেছিলাম সেই মানদণ্ড সহ।
এমসিফার্ট

আমি সন্দেহ করি searchsorted(বা যে কোনও অ্যালগোরিদম) O(log(n))বাছাই করা অভিন্ন বিতরণ করা ডেটার জন্য বাইনারি অনুসন্ধান করতে পারে । সম্পাদনা করুন: searchsorted হয় একটি বাইনারি অনুসন্ধান।
মতিন উলহাক

16
In [34]: a=np.arange(-10,10)

In [35]: a
Out[35]:
array([-10,  -9,  -8,  -7,  -6,  -5,  -4,  -3,  -2,  -1,   0,   1,   2,
         3,   4,   5,   6,   7,   8,   9])

In [36]: np.where(a>5)
Out[36]: (array([16, 17, 18, 19]),)

In [37]: np.where(a>5)[0][0]
Out[37]: 16

8

উপাদানগুলির মধ্যে ধ্রুব পদক্ষেপ রয়েছে এমন অ্যারে

একটি ক্ষেত্রে 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 ব্যবহারের মডিউল।


3

আমি প্রস্তাব দিতে চাই

np.min(np.append(np.where(aa>5)[0],np.inf))

এটি শর্তটি পূরণ করা হয় যেখানে ক্ষুদ্রতম সূচকটি ফিরিয়ে দেবে, যখন শর্তটি কখনও পূরণ না করা হয় এবং অনন্ততা ফিরে whereআসে (এবং একটি খালি অ্যারে প্রদান করে)।


1

আমি সাথে যেতে হবে

i = np.min(np.where(V >= x))

যেখানে Vভেক্টর (1 ডি অ্যারে), xএর মান এবং iফলাফল সূচক।

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