অ্যারেতে দু'বার অ্যারে বাছাই না করে পাইথন / নুমপি ব্যবহার করে একটি অ্যারে আইটেমগুলি রেঙ্ক করুন


107

আমার সংখ্যার একটি অ্যারে রয়েছে এবং আমি অন্য অ্যারে তৈরি করতে চাই যা প্রথম অ্যারেতে প্রতিটি আইটেমের র‌্যাঙ্ক উপস্থাপন করে। আমি পাইথন এবং নুমপি ব্যবহার করছি।

উদাহরণ স্বরূপ:

array = [4,2,7,1]
ranks = [2,1,3,0]

আমি যে সেরা পদ্ধতিটি নিয়ে এসেছি তা এখানে:

array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.arange(len(array))[temp.argsort()]

আরও ভাল / দ্রুত কোন পদ্ধতি আছে যা অ্যারের দু'বার বাছাই করা এড়ায়?


6
আপনার শেষ লাইন সমতুল্য ranks = temp.argsort()
সোভেন মারনাচ

উত্তর:


71

শেষ ধাপে বাম দিকে স্লাইসিং ব্যবহার করুন:

array = numpy.array([4,2,7,1])
temp = array.argsort()
ranks = numpy.empty_like(temp)
ranks[temp] = numpy.arange(len(array))

এটি শেষ ধাপে আদেশটি উল্টিয়ে দ্বিগুণ বাছাই করা এড়িয়ে যায়।


4
নিখুঁত আপনাকে ধন্যবাদ! আমি জানতাম যে এর সমাধান রয়েছে এবং এটি একবার দেখলেই তা স্পষ্ট মনে হবে। আমি টাইমিট দিয়ে কিছু পরীক্ষা করেছি এবং এই পদ্ধতিটি ছোট অ্যারেগুলির জন্য কিছুটা ধীর। আমার মেশিনে তারা সমান হয় যখন অ্যারেতে 2,000 উপাদান থাকে। 20,000 উপাদানগুলিতে, আপনার পদ্ধতিটি প্রায় 25% দ্রুত।
জোশায়াররা

এই সারিতে কীভাবে করা যায় সে সম্পর্কে কোনও সুপারিশ?
জেসার

1 টিরও বেশি ডিমের জন্য নীচে উত্তর দেখুন।
গণিত

105

প্রথমে অ্যারের ক্রমটি পেতে, তারপরে র‌্যাঙ্কিং পেতে আর্গসোর্টটি দু'বার ব্যবহার করুন:

array = numpy.array([4,2,7,1])
order = array.argsort()
ranks = order.argsort()

2 ডি (বা উচ্চতর মাত্রিক) অ্যারেগুলির সাথে কাজ করার সময়, সঠিক অক্ষের উপর অর্ডার দেওয়ার জন্য আর্গসোর্টে একটি অক্ষ যুক্তিটি পাস করার বিষয়ে নিশ্চিত হন।


4
নোট করুন যে যদি আপনার ইনপুট অ্যারেতে সংখ্যাগুলি পুনরাবৃত্তি করা হয় (উদাহরণস্বরূপ [4,2,7,1,1]) আউটপুট তাদের অ্যারে অবস্থানের ভিত্তিতে এই সংখ্যাগুলি র‌্যাংক করবে ( [3,2,4,0,1])
rcoup

4
দু'বার বাছাই করা অক্ষম। @ সোভেন মারনাচের উত্তরটি দেখায় যে কীভাবে একক কল দিয়ে র‌্যাঙ্কিংটি সম্পন্ন করা যায় argsort
ওয়ারেন ওয়েকেকসার

6
@ ওয়ারেন উইকেকেসার: আমি মাত্র দু'জনের মধ্যে পার্থক্যটি পরীক্ষা করেছি এবং আপনি বড় অ্যারেগুলির জন্য সঠিক, তবে ছোট কিছু (এন <100) এর জন্য ডাবল আরোগোর্ট দ্রুত (এন = 100 এর জন্য প্রায় 20% দ্রুত এবং প্রায় 5 গুণ দ্রুত) এন = 10 এর জন্য)। সুতরাং যদি আপনাকে মানগুলির ছোট ছোট সেটগুলি জুড়ে প্রচুর র‌্যাঙ্কিং করতে হয় তবে এই পদ্ধতিটি আরও ভাল।
nnot101

4
@ ওয়ারেনওকেকসার: আসলে, আমি ভুল, এই পদ্ধতিটি হ্যান্ড-ডাউন আরও ভাল। উভয় পদ্ধতি স্কিপি.স্ট্যাটস পদ্ধতির চেয়েও দ্রুত। ফলাফল: gist.github.com/naught101/14042d91a2d0f18a6ae4
নট 101

4
@ ননট ১০১১: আপনার স্ক্রিপ্টে একটি বাগ রয়েছে। লাইন array = np.random.rand(10)হওয়া উচিত array = np.random.rand(n)
ওয়ারেন ওয়েকেকসার

93

এই প্রশ্নটি কয়েক বছর পুরনো, এবং গৃহীত উত্তরটি দুর্দান্ত তবে আমার মনে হয় নিম্নলিখিতটি এখনও উল্লেখ করার মতো worth আপনি যদি নির্ভরতা আপত্তি না করেন তবে আপনি scipyব্যবহার করতে পারেন scipy.stats.rankdata:

In [22]: from scipy.stats import rankdata

In [23]: a = [4, 2, 7, 1]

In [24]: rankdata(a)
Out[24]: array([ 3.,  2.,  4.,  1.])

In [25]: (rankdata(a) - 1).astype(int)
Out[25]: array([2, 1, 3, 0])

এর একটি দুর্দান্ত বৈশিষ্ট্য rankdataহ'ল methodযুক্তিটি সম্পর্কগুলি পরিচালনা করার জন্য বিভিন্ন বিকল্প সরবরাহ করে। উদাহরণস্বরূপ, সেখানে 20 টির তিনটি ঘটনা এবং 40 টির মধ্যে দুটি ঘটনা রয়েছে b:

In [26]: b = [40, 20, 70, 10, 20, 50, 30, 40, 20]

ডিফল্ট বাঁধা মানগুলিতে গড় র‌্যাঙ্ক নির্ধারণ করে:

In [27]: rankdata(b)
Out[27]: array([ 6.5,  3. ,  9. ,  1. ,  3. ,  8. ,  5. ,  6.5,  3. ])

method='ordinal' একটানা পদে নিয়োগ দেয়:

In [28]: rankdata(b, method='ordinal')
Out[28]: array([6, 2, 9, 1, 3, 8, 5, 7, 4])

method='min' সমস্ত বাঁধা মানগুলিতে বাঁধা মানগুলির সর্বনিম্ন র‌্যাঙ্ক বরাদ্দ করে:

In [29]: rankdata(b, method='min')
Out[29]: array([6, 2, 9, 1, 2, 8, 5, 6, 2])

আরও বিকল্পের জন্য ডকাস্ট্রিং দেখুন।


4
হ্যাঁ, প্রান্তের মামলাগুলি গুরুত্বপূর্ণ যেখানেই এটি এটি সেরা উত্তর।
nnot101

আমি এটি আকর্ষণীয় rankdataমনে করি যা অভ্যন্তরীণভাবে প্রাথমিক র‌্যাঙ্কিং উত্পন্ন করার জন্য গৃহীত উত্তর হিসাবে একই প্রক্রিয়াটি ব্যবহার করে বলে মনে হয়।
অ্যালেক্সভি

5

আমি আপনার অ্যারে সারি-সারি-সারি (অক্ষ = 1) প্রক্রিয়া করে মনে করি, একাধিক মাত্রার অ্যারেগুলির জন্য উভয় সমাধান প্রসারিত করার চেষ্টা করেছি।

আমি সারিগুলিতে একটি লুপ দিয়ে প্রথম কোডটি প্রসারিত করেছি; সম্ভবত এটি উন্নত করা যেতে পারে

temp = A.argsort(axis=1)
rank = np.empty_like(temp)
rangeA = np.arange(temp.shape[1])
for iRow in xrange(temp.shape[0]): 
    rank[iRow, temp[iRow,:]] = rangeA

এবং দ্বিতীয়টি, কে.রুয়েজার্সের পরামর্শ অনুসারে পরিণত হয়:

temp = A.argsort(axis=1)
rank = temp.argsort(axis=1)

আমি এলোমেলোভাবে আকারের (1000,100) 400 টি অ্যারে তৈরি করেছি; প্রথম কোডটি প্রায় 7.5 নিয়েছিল, দ্বিতীয়টি 3.8।


5

গড় র‌্যাঙ্কের একটি ভেক্টরাইজড সংস্করণের জন্য নীচে দেখুন। আমি এনপিউনিককে ভালবাসি, এটি কী কোডের দক্ষতার সাথে ভেক্টরাইজড হতে পারে এবং কীভাবে করা যায় না তার সুযোগটি প্রসারিত করে। লুপগুলির জন্য অজগরটিকে এড়ানো ছাড়াও, এই পদ্ধতিটি 'ক' এর উপরে অন্তর্নিহিত ডাবল লুপও এড়িয়ে চলে।

import numpy as np

a = np.array( [4,1,6,8,4,1,6])

a = np.array([4,2,7,2,1])
rank = a.argsort().argsort()

unique, inverse = np.unique(a, return_inverse = True)

unique_rank_sum = np.zeros_like(unique)
np.add.at(unique_rank_sum, inverse, rank)
unique_count = np.zeros_like(unique)
np.add.at(unique_count, inverse, 1)

unique_rank_mean = unique_rank_sum.astype(np.float) / unique_count

rank_mean = unique_rank_mean[inverse]

print rank_mean

উপায় দ্বারা; অন্যান্য গড় র‌্যাঙ্ক কোডের মতো একই আউটপুট তৈরি করতে আমি এই কোডটি তৈরি করেছি, তবে আমি পুনরাবৃত্তি সংখ্যার একটি গ্রুপের ন্যূনতম র‌্যাঙ্কটি ঠিক তেমনভাবে কাজ করে তা কল্পনা করতে পারি। এই যেমন >>> অনন্য, সূচি, বিপরীত = np.unique (ক, এটা ঠিক যে, সত্য) >>> rank_min = র্যাঙ্ক [সূচক] [বিপরীত] এমনকি আরো সহজে প্রাপ্ত করা যাবে
Eelco Hoogendoorn

আপনার সমাধানের সাথে আমি নীচের ত্রুটিটি পাচ্ছি (অদ্ভুত 1.7.1): অ্যাট্রিবিউটআরার: 'numpy.ufunc' অবজেক্টটির 'তে' কোনও বৈশিষ্ট্য নেই
ভয়

এর জন্য নম্পির আরও সাম্প্রতিক সংস্করণ প্রয়োজন; আপনার বেশ প্রাচীন
Eelco Hoogendoorn

4

সমাধানের কমনীয়তা এবং সংক্ষিপ্ততা ছাড়াও পারফরম্যান্সের প্রশ্ন রয়েছে। এখানে একটি সামান্য মানদণ্ড দেওয়া হল:

import numpy as np
from scipy.stats import rankdata
l = list(reversed(range(1000)))

%%timeit -n10000 -r5
x = (rankdata(l) - 1).astype(int)
>>> 128 µs ± 2.72 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

%%timeit -n10000 -r5
a = np.array(l)
r = a.argsort().argsort()
>>> 69.1 µs ± 464 ns per loop (mean ± std. dev. of 5 runs, 10000 loops each)

%%timeit -n10000 -r5
a = np.array(l)
temp = a.argsort()
r = np.empty_like(temp)
r[temp] = np.arange(len(a))
>>> 63.7 µs ± 1.27 µs per loop (mean ± std. dev. of 5 runs, 10000 loops each)

4
ভাল ধারণা, তবে ন্যায্য তুলনার জন্য আপনার ব্যবহার করা উচিত rankdata(l, method='ordinal') - 1
ওয়ারেন ওয়েকেকেসার


2

আমি উপরের পদ্ধতিগুলি চেষ্টা করেছিলাম, তবে ব্যর্থ হলাম কারণ আমার অনেক জুরি ছিল। হ্যাঁ, এমনকি ফ্লোটের সদৃশ আইটেমগুলিও গুরুত্বপূর্ণ হতে পারে।

তাই আমি টাই-চেকিং পদক্ষেপ যুক্ত করে একটি সংশোধিত 1D সমাধান লিখেছি:

def ranks (v):
    import numpy as np
    t = np.argsort(v)
    r = np.empty(len(v),int)
    r[t] = np.arange(len(v))
    for i in xrange(1, len(r)):
        if v[t[i]] <= v[t[i-1]]: r[t[i]] = r[t[i-1]]
    return r

# test it
print sorted(zip(ranks(v), v))

আমি বিশ্বাস করি এটি যথাসাধ্য দক্ষ


0

আমি কে.রুয়েজারদের দ্বারা পদ্ধতিটি পছন্দ করেছি, তবে rcoup যেমন লিখেছেন, পুনরাবৃত্তি সংখ্যা অ্যারের অবস্থান অনুসারে স্থান পেয়েছে। এটি আমার পক্ষে ভাল ছিল না, তাই আমি পদগুলিকে পোস্ট প্রসেস করার জন্য সংস্করণটি সংশোধন করেছি এবং যে কোনও পুনরাবৃত্তি সংখ্যাকে সম্মিলিত গড় র‌্যাঙ্কে একীভূত করেছি:

import numpy as np
a = np.array([4,2,7,2,1])
r = np.array(a.argsort().argsort(), dtype=float)
f = a==a
for i in xrange(len(a)):
   if not f[i]: continue
   s = a == a[i]
   ls = np.sum(s)
   if ls > 1:
      tr = np.sum(r[s])
      r[s] = float(tr)/ls
   f[s] = False

print r  # array([ 3. ,  1.5,  4. ,  1.5,  0. ])

আমি আশা করি এটি অন্যকেও সহায়তা করতে পারে, আমি এর জন্য অনাদার সমাধানগুলি চেষ্টা করার চেষ্টা করেছি, তবে কোনও খুঁজে পেলাম না ...


0

আরর্গোর্ট এবং স্লাইসগুলি প্রতিসম ক্রিয়াকলাপ।

দুইবার আরগসর্টের পরিবর্তে দু'বার টুকরো টুকরো করে দেখুন। যেহেতু স্লাইসটি অর্গসোর্টের চেয়ে দ্রুত

array = numpy.array([4,2,7,1])
order = array.argsort()
ranks = np.arange(array.shape[0])[order][order]

0

উত্তরের একটির আরও সাধারণ সংস্করণ:

In [140]: x = np.random.randn(10, 3)

In [141]: i = np.argsort(x, axis=0)

In [142]: ranks = np.empty_like(i)

In [143]: np.put_along_axis(ranks, i, np.repeat(np.arange(x.shape[0])[:,None], x.shape[1], axis=1), axis=0)

2 টির বেশি মাত্রায় সূচক হিসাবে numpy.argsort () কীভাবে ব্যবহার করবেন তা দেখুন ? আরও ডিমেজে সাধারণকরণ করা।

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