मैं एक अंक सरणी में एन अधिकतम मूल्यों के सूचकांक कैसे प्राप्त करूं?


482

NumPy एक सरणी के माध्यम से अधिकतम मान के सूचकांक को प्राप्त करने का एक तरीका प्रस्तावित करता है np.argmax

मैं एक समान बात करना चाहता हूं, लेकिन Nअधिकतम मूल्यों के सूचकांक को वापस करना।

उदाहरण के लिए, अगर मैं एक सरणी है, [1, 3, 2, 4, 5], function(array, n=3)सूचकांक वापसी होगी [4, 3, 1]जो तत्वों के अनुरूप [5, 4, 3]



4
आपका प्रश्न वास्तव में अच्छी तरह से परिभाषित नहीं है। उदाहरण के लिए, क्या सूचकांक (आप उम्मीद करेंगे) के लिए array([5, 1, 5, 5, 2, 3, 2, 4, 1, 5]), सफेद n= 3? सभी में से कौन सा विकल्प, जैसे [0, 2, 3], [0, 2, 9], ...सही हो सकता है? कृपया अपनी विशिष्ट आवश्यकताओं पर अधिक विस्तार करें। धन्यवाद
खाएं

@eat, मुझे वास्तव में परवाह नहीं है कि इस विशिष्ट मामले में किसे लौटाया जाना चाहिए। यहां तक ​​कि अगर पहले वाले का सामना करना तर्कसंगत लगता है, तो यह मेरे लिए एक आवश्यकता नहीं है।
एलेक्सिस मेएटेरियो

argsortयदि आप लौटे इंडोल के आदेश की परवाह नहीं करते हैं तो एक व्यवहार्य विकल्प हो सकता है। नीचे मेरा जवाब देखें।
नीला

जवाबों:


347

मैं जिस सरलता से आने में सक्षम हूं वह है:

In [1]: import numpy as np

In [2]: arr = np.array([1, 3, 2, 4, 5])

In [3]: arr.argsort()[-3:][::-1]
Out[3]: array([4, 3, 1])

इसमें सरणी का पूरा प्रकार शामिल है। मुझे आश्चर्य है कि अगर numpyएक आंशिक प्रकार करने के लिए एक अंतर्निहित तरीका प्रदान करता है; अब तक मैं एक खोजने में सक्षम नहीं था।

यदि यह समाधान बहुत धीमा हो जाता है (विशेष रूप से छोटे के लिए n), तो यह साइथन में कुछ को कोड करने के लिए देखने लायक हो सकता है


1
क्या पंक्ति 3 को समान रूप से लिखा जा सकता है arr.argsort()[-1:-4:-1]? मैंने इसे दुभाषिया में आज़माया है और यह उसी परिणाम के साथ आता है, लेकिन मैं सोच रहा हूं कि क्या यह किसी उदाहरण से नहीं टूटा है।
abroekhof

44
@abroekhof हाँ जो किसी भी सूची या सरणी के लिए समतुल्य होनी चाहिए। वैकल्पिक रूप से, इसका उपयोग करके उत्क्रमण के बिना किया जा सकता है np.argsort(-arr)[:3], जिसे मैं अधिक पठनीय और बिंदु तक पाता हूं।
आस्किवेन

6
[:: - 1] का क्या अर्थ है? @ एनपीई

@ 1a1a11a का अर्थ है एक सरणी को उल्टा करना (शाब्दिक रूप से, एक सरणी की एक प्रतिलिपि को
अप्रतिबंधित

15
arr.argsort()[::-1][:n]बेहतर है क्योंकि यह n=0पूर्ण सरणी के बजाय खाली लौटता है
abora

599

नए NumPy संस्करणों (1.8 और ऊपर) में इसके लिए एक फ़ंक्शन है argpartition। चार सबसे बड़े तत्वों के सूचकांकों को प्राप्त करने के लिए, करें

>>> a = np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
>>> a
array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])
>>> ind = np.argpartition(a, -4)[-4:]
>>> ind
array([1, 5, 8, 0])
>>> a[ind]
array([4, 9, 6, 9])

इसके विपरीत argsort, यह फ़ंक्शन सबसे खराब स्थिति में रैखिक समय में चलता है, लेकिन लौटे हुए सूचकांकों को क्रमबद्ध नहीं किया जाता है, जैसा कि मूल्यांकन के परिणाम से देखा जा सकता है a[ind]। यदि आपको भी इसकी आवश्यकता है, तो उन्हें बाद में क्रमबद्ध करें:

>>> ind[np.argsort(a[ind])]
array([1, 8, 5, 0])

इस तरह से क्रमबद्ध क्रम में शीर्ष- k तत्वों को प्राप्त करने में O ( n + k log k ) समय लगता है।


27
@varela argpartition, रेखीय समय में चलता है, O (n), इंट्रोसेप्ट एल्गोरिथ्म का उपयोग करते हुए । बाद का क्रम केवल k तत्वों को संभालता है, ताकि O (k log k) में चलता रहे।
फ्रेड फू

2
अगर कोई सोच रहा है कि वास्तव में np.argpartitionऔर उसकी बहन एल्गोरिथ्म कैसे np.partitionकाम करती है, तो जुड़े हुए प्रश्न में अधिक विस्तृत विवरण है: stackoverflow.com/questions/10337533/…
रेमन मार्टिनेज

7
@FredFoo: आपने -4 का उपयोग क्यों किया? क्या आपने पिछड़े को शुरू करने के लिए ऐसा किया है? (क्योंकि k सकारात्मक या नकारात्मक होने के कारण मेरे लिए समान काम करता है! यह केवल सबसे छोटी संख्याओं को प्रिंट करता है!
Rika

2
@ LKT का उपयोग करें a=np.array([9, 4, 4, 3, 3, 9, 0, 4, 6, 0])क्योंकि सामान्य अजगर सूचियों को सूचियों द्वारा अनुक्रमण का समर्थन नहीं करते हैं, इसके विपरीतnp.array
Marawan Okasha

2
@Umangsinghal np.argpartitionएक वैकल्पिक axisतर्क लेता है। प्रत्येक पंक्ति के लिए शीर्ष एन मानों के सूचकांकों को खोजने के लिए:np.argpartition(a, -n, axis=1)[-n:]
राल्फ

48

अभी तक सरल:

idx = (-arr).argsort()[:n]

जहाँ n अधिकतम मानों की संख्या है।


7
यह एक 2d सरणी के लिए किया जा सकता है? यदि नहीं, तो क्या आप जानते हैं कि कैसे?
एंड्रयू हंड्ट

2
@AndrewHundt: बस (-आर) (.argsort (अक्ष = -1) का उपयोग करें: [:,: n]
MiniQuark

2
इसी तरह arr[arr.argsort()[-n:]]सरणी को नकारने के बजाय, केवल अंतिम n तत्वों का एक टुकड़ा लें
loganjones16

35

उपयोग:

>>> import heapq
>>> import numpy
>>> a = numpy.array([1, 3, 2, 4, 5])
>>> heapq.nlargest(3, range(len(a)), a.take)
[4, 3, 1]

नियमित पायथन सूची के लिए:

>>> a = [1, 3, 2, 4, 5]
>>> heapq.nlargest(3, range(len(a)), a.__getitem__)
[4, 3, 1]

यदि आप पायथन 2 का उपयोग करते हैं, तो xrangeइसके बजाय का उपयोग करें range

स्रोत: हीपेक - हीप कतार एल्गोरिदम


2
सब यहाँ पर एक पाश की कोई ज़रूरत नहीं है: heapq.nlargest(3, xrange(len(a)), a.take)। पायथन सूची के लिए हम .__getitem__इसके बजाय उपयोग कर सकते हैं .take
अश्विनी चौधरी

Aसामान्य रूप से एन-आयामी सरणियों के लिए heapq.nlargest(3, range(len(A.ravel())), A.ravel().take):। (मुझे आशा है कि यह केवल विचारों पर काम कर रहा है, यह भी देखें ( ravel vs flatten) ( stackoverflow.com/a/28930580/603003 ))।
ComFric

31

यदि आप एक बहुआयामी सरणी के साथ काम कर रहे हैं तो आपको सूचक को समतल करना और खोलना होगा:

def largest_indices(ary, n):
    """Returns the n largest indices from a numpy array."""
    flat = ary.flatten()
    indices = np.argpartition(flat, -n)[-n:]
    indices = indices[np.argsort(-flat[indices])]
    return np.unravel_index(indices, ary.shape)

उदाहरण के लिए:

>>> xs = np.sin(np.arange(9)).reshape((3, 3))
>>> xs
array([[ 0.        ,  0.84147098,  0.90929743],
       [ 0.14112001, -0.7568025 , -0.95892427],
       [-0.2794155 ,  0.6569866 ,  0.98935825]])
>>> largest_indices(xs, 3)
(array([2, 0, 0]), array([2, 2, 1]))
>>> xs[largest_indices(xs, 3)]
array([ 0.98935825,  0.90929743,  0.84147098])

9

यदि आप K-th सबसे बड़े तत्वों के क्रम के बारे में परवाह नहीं करते हैं जो आप उपयोग कर सकते हैं argpartition, जो कि एक पूर्ण प्रकार से बेहतर प्रदर्शन करना चाहिए argsort

K = 4 # We want the indices of the four largest values
a = np.array([0, 8, 0, 4, 5, 8, 8, 0, 4, 2])
np.argpartition(a,-K)[-K:]
array([4, 1, 5, 6])

क्रेडिट इस सवाल पर जाते हैं

मैं कुछ परीक्षण भाग गया और यह की तरह लग रहा argpartitionOutperforms argsortसरणी के आकार और कश्मीर वृद्धि के मूल्य के रूप में।


7

बहु-आयामी सरणियों के लिए आप axisअपेक्षित अक्ष के साथ विभाजन को लागू करने के लिए कीवर्ड का उपयोग कर सकते हैं ।

# For a 2D array
indices = np.argpartition(arr, -N, axis=1)[:, -N:]

और आइटम हथियाने के लिए:

x = arr.shape[0]
arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N)

लेकिन ध्यान दें कि यह एक हल किए गए परिणाम को वापस नहीं करेगा। उस स्थिति में आप np.argsort()इच्छित अक्ष के साथ उपयोग कर सकते हैं :

indices = np.argsort(arr, axis=1)[:, -N:]

# Result
x = arr.shape[0]
arr[np.repeat(np.arange(x), N), indices.ravel()].reshape(x, N)

यहाँ एक उदाहरण है:

In [42]: a = np.random.randint(0, 20, (10, 10))

In [44]: a
Out[44]:
array([[ 7, 11, 12,  0,  2,  3,  4, 10,  6, 10],
       [16, 16,  4,  3, 18,  5, 10,  4, 14,  9],
       [ 2,  9, 15, 12, 18,  3, 13, 11,  5, 10],
       [14,  0,  9, 11,  1,  4,  9, 19, 18, 12],
       [ 0, 10,  5, 15,  9, 18,  5,  2, 16, 19],
       [14, 19,  3, 11, 13, 11, 13, 11,  1, 14],
       [ 7, 15, 18,  6,  5, 13,  1,  7,  9, 19],
       [11, 17, 11, 16, 14,  3, 16,  1, 12, 19],
       [ 2,  4, 14,  8,  6,  9, 14,  9,  1,  5],
       [ 1, 10, 15,  0,  1,  9, 18,  2,  2, 12]])

In [45]: np.argpartition(a, np.argmin(a, axis=0))[:, 1:] # 1 is because the first item is the minimum one.
Out[45]:
array([[4, 5, 6, 8, 0, 7, 9, 1, 2],
       [2, 7, 5, 9, 6, 8, 1, 0, 4],
       [5, 8, 1, 9, 7, 3, 6, 2, 4],
       [4, 5, 2, 6, 3, 9, 0, 8, 7],
       [7, 2, 6, 4, 1, 3, 8, 5, 9],
       [2, 3, 5, 7, 6, 4, 0, 9, 1],
       [4, 3, 0, 7, 8, 5, 1, 2, 9],
       [5, 2, 0, 8, 4, 6, 3, 1, 9],
       [0, 1, 9, 4, 3, 7, 5, 2, 6],
       [0, 4, 7, 8, 5, 1, 9, 2, 6]])

In [46]: np.argpartition(a, np.argmin(a, axis=0))[:, -3:]
Out[46]:
array([[9, 1, 2],
       [1, 0, 4],
       [6, 2, 4],
       [0, 8, 7],
       [8, 5, 9],
       [0, 9, 1],
       [1, 2, 9],
       [3, 1, 9],
       [5, 2, 6],
       [9, 2, 6]])

In [89]: a[np.repeat(np.arange(x), 3), ind.ravel()].reshape(x, 3)
Out[89]:
array([[10, 11, 12],
       [16, 16, 18],
       [13, 15, 18],
       [14, 18, 19],
       [16, 18, 19],
       [14, 14, 19],
       [15, 18, 19],
       [16, 17, 19],
       [ 9, 14, 14],
       [12, 15, 18]])

मुझे लगता है कि आप यहाँ अनुक्रमण को सरल बना सकते हैं np.take_along_axis(इस प्रश्न का उत्तर देते समय (जिसका कोई अस्तित्व नहीं था)
एरिक

4

यह आपके मूल सरणी के आकार और आपके चयन के आकार के आधार पर पूर्ण प्रकार से अधिक तेज़ होगा:

>>> A = np.random.randint(0,10,10)
>>> A
array([5, 1, 5, 5, 2, 3, 2, 4, 1, 0])
>>> B = np.zeros(3, int)
>>> for i in xrange(3):
...     idx = np.argmax(A)
...     B[i]=idx; A[idx]=0 #something smaller than A.min()
...     
>>> B
array([0, 2, 3])

बेशक, इसमें आपके मूल सरणी के साथ छेड़छाड़ शामिल है। जिसे आप (यदि आवश्यक हो) कॉपी करके या मूल मानों को वापस बदलकर ठीक कर सकते हैं। ... जो भी आपके उपयोग के मामले के लिए सस्ता है।


FWIW, आपका समाधान सभी स्थितियों में असंदिग्ध समाधान प्रदान नहीं करेगा। ओपी को वर्णन करना चाहिए कि इन असंदिग्ध मामलों को कैसे संभालना है। धन्यवाद
खाएं

@eat ओपी का सवाल थोड़ा अस्पष्ट है। एक कार्यान्वयन, हालांकि, वास्तव में व्याख्या के लिए खुला नहीं है। :) ओपी को केवल np.argmax docs.scipy.org/doc/numpy/reference/generated/numpy.argmax.html की परिभाषा का उल्लेख करना चाहिए यह सुनिश्चित करने के लिए कि यह विशिष्ट समाधान आवश्यकताओं को पूरा करता है। यह संभव है कि ओपी द्वारा बताई गई किसी भी समाधान की बैठक स्वीकार्य हो ..
पॉल

ठीक है, एक के argmax(.)रूप में अच्छी तरह से लागू करने के लिए विचार किया जा सकता है। (IMHO यह किसी प्रकार के छोटे सर्कुलेटिंग लॉजिक का पालन करने की कोशिश करता है, लेकिन दुर्भाग्य से सार्वभौमिक रूप से स्वीकार्य व्यवहार प्रदान करने में विफल रहता है)। धन्यवाद
खाएं

3

विधि np.argpartitionकेवल k सबसे बड़े सूचक को लौटाती है, एक स्थानीय प्रकार का प्रदर्शन करती है, और np.argsortजब सरणी काफी बड़ी होती है तो (पूर्ण प्रकार का प्रदर्शन) की तुलना में तेज़ होती है। लेकिन लौटाए गए सूचकांक आरोही / अवरोही क्रम में नहीं हैं । आइए एक उदाहरण के साथ कहते हैं:

यहां छवि विवरण दर्ज करें

हम देख सकते हैं कि यदि आप एक सख्त आरोही क्रम शीर्ष कश्मीर सूचकांक चाहते हैं, तो आप जो चाहते हैं वह np.argpartitionवापस नहीं होगा।

Np.argpartition के बाद मैन्युअल रूप से एक प्रकार करने के अलावा, मेरा समाधान PyTorch, torch.topkतंत्रिका नेटवर्क निर्माण के लिए एक टूल का उपयोग करना है, CPU और GPU दोनों के साथ NumPy जैसी API प्रदान करता है। यह MKL के साथ NumPy जितना तेज़ है, और यदि आपको बड़े मैट्रिक्स / वेक्टर गणना की आवश्यकता है तो GPU बूस्ट प्रदान करता है।

सख्त चढ़ना / उतरना शीर्ष कश्मीर सूचकांक कोड होगा:

यहां छवि विवरण दर्ज करें

ध्यान दें कि torch.topkएक टार्च टेंसर को स्वीकार करता है, और प्रकार में शीर्ष k मान और शीर्ष k सूचकांक दोनों देता है torch.Tensor। Np के समान, torch.topk भी एक अक्ष तर्क को स्वीकार करता है ताकि आप बहुआयामी सरणियों / टेनर्स को संभाल सकें।


2

उपयोग:

from operator import itemgetter
from heapq import nlargest
result = nlargest(N, enumerate(your_list), itemgetter(1))

अब resultसूची में N tuples ( index, value) होगा जहां valueअधिकतम किया जाता है।


2

उपयोग:

def max_indices(arr, k):
    '''
    Returns the indices of the k first largest elements of arr
    (in descending order in values)
    '''
    assert k <= arr.size, 'k should be smaller or equal to the array size'
    arr_ = arr.astype(float)  # make a copy of arr
    max_idxs = []
    for _ in range(k):
        max_element = np.max(arr_)
        if np.isinf(max_element):
            break
        else:
            idx = np.where(arr_ == max_element)
        max_idxs.append(idx)
        arr_[idx] = -np.inf
    return max_idxs

यह 2D सरणियों के साथ भी काम करता है। उदाहरण के लिए,

In [0]: A = np.array([[ 0.51845014,  0.72528114],
                     [ 0.88421561,  0.18798661],
                     [ 0.89832036,  0.19448609],
                     [ 0.89832036,  0.19448609]])
In [1]: max_indices(A, 8)
Out[1]:
    [(array([2, 3], dtype=int64), array([0, 0], dtype=int64)),
     (array([1], dtype=int64), array([0], dtype=int64)),
     (array([0], dtype=int64), array([1], dtype=int64)),
     (array([0], dtype=int64), array([0], dtype=int64)),
     (array([2, 3], dtype=int64), array([1, 1], dtype=int64)),
     (array([1], dtype=int64), array([1], dtype=int64))]

In [2]: A[max_indices(A, 8)[0]][0]
Out[2]: array([ 0.89832036])

अच्छा काम करता है, लेकिन अगर आप अपने सरणी में डुप्लिकेट (अधिकतम) मान रखते हैं तो अधिक परिणाम देता है। मैं वास्तव में k परिणामों की अपेक्षा करता हूं, लेकिन डुप्लिकेट मानों के मामले में, आपको k परिणामों की तुलना में अधिक मिलता है।
गुइडो

मैंने कोड को थोड़ा संशोधित किया। लौटाए गए सूचकांकों की सूची की लंबाई कश्मीर के बराबर है। यदि आपके पास डुप्लिकेट हैं, तो उन्हें एक एकल टपल में वर्गीकृत किया गया है।
X :04 A-12

1

bottleneck एक आंशिक सॉर्ट फ़ंक्शन है, यदि एन सबसे बड़ा मान प्राप्त करने के लिए पूरे सरणी को छाँटने का खर्च बहुत अच्छा है।

मुझे इस मॉड्यूल के बारे में कुछ नहीं पता है; मैंने अभी गुगली की numpy partial sort


मुझे टोंटी में कोई आंशिक सॉर्ट फ़ंक्शन नहीं मिलता है, एक विभाजन फ़ंक्शन है, लेकिन यह सॉर्ट नहीं करता है
nbecker

1

निम्नलिखित अधिकतम तत्वों और इसके पदों को देखने का एक बहुत आसान तरीका है। यहाँ axisडोमेन है; axis= 0 का अर्थ है कॉलम वार अधिकतम संख्या और axis= 1 का मतलब है 2 डी केस के लिए पंक्ति वार अधिकतम संख्या। और उच्च आयामों के लिए यह आप पर निर्भर करता है।

M = np.random.random((3, 4))
print(M)
print(M.max(axis=1), M.argmax(axis=1))

मैंने इस लिंक का उपयोग किया jakevdp.github.io/PythonDataScienceHandbook/…
उदार

0

मुझे इसका उपयोग करना सबसे अधिक सहज लगा np.unique

विचार यह है, कि अनूठी विधि इनपुट मूल्यों के सूचकांकों को लौटाती है। फिर अधिकतम अद्वितीय मूल्य और संकेतों से, मूल मूल्यों की स्थिति को फिर से बनाया जा सकता है।

multi_max = [1,1,2,2,4,0,0,4]
uniques, idx = np.unique(multi_max, return_inverse=True)
print np.squeeze(np.argwhere(idx == np.argmax(uniques)))
>> [4 7]

0

मुझे लगता है कि सबसे अधिक समय दक्षता का तरीका मैन्युअल रूप से सरणी के माध्यम से पुनरावृत्त होता है और एक के-आकार का न्यूनतम-ढेर रखता है, जैसा कि अन्य लोगों ने उल्लेख किया है।

और मैं भी एक क्रूर बल दृष्टिकोण के साथ आता हूं:

top_k_index_list = [ ]
for i in range(k):
    top_k_index_list.append(np.argmax(my_array))
    my_array[top_k_index_list[-1]] = -float('inf')

अपने अनुक्रमणिका को प्राप्त करने के लिए argmax का उपयोग करने के बाद सबसे बड़े तत्व को एक बड़े नकारात्मक मान पर सेट करें। और फिर argmax की अगली कॉल दूसरा सबसे बड़ा तत्व वापस करेगी। और आप इन तत्वों के मूल मूल्य को लॉग इन कर सकते हैं और यदि आप चाहें तो उन्हें पुनर्प्राप्त कर सकते हैं।


0

यह कोड एक संख्यात्मक मैट्रिक्स सरणी के लिए काम करता है:

mat = np.array([[1, 3], [2, 5]]) # numpy matrix

n = 2  # n
n_largest_mat = np.sort(mat, axis=None)[-n:] # n_largest 
tf_n_largest = np.zeros((2,2), dtype=bool) # all false matrix
for x in n_largest_mat: 
  tf_n_largest = (tf_n_largest) | (mat == x) # true-false  

n_largest_elems = mat[tf_n_largest] # true-false indexing 

यह एक सच्चे-झूठे n_largest मैट्रिक्स अनुक्रमणिका का निर्माण करता है जो मैट्रिक्स सरणी से n_largest तत्वों को निकालने के लिए भी काम करता है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.