এখানে একটি ও (সর্বোচ্চ (এক্স) + লেন (এক্স)) পদ্ধতিটি ব্যবহার করে scipy.sparse
:
import numpy as np
from scipy import sparse
x = np.array("1 2 2 0 0 1 3 5".split(),int)
x
# array([1, 2, 2, 0, 0, 1, 3, 5])
M,N = x.max()+1,x.size
sparse.csc_matrix((x,x,np.arange(N+1)),(M,N)).tolil().rows.tolist()
# [[3, 4], [0, 5], [1, 2], [6], [], [7]]
এটি পজিশনে (x [0], 0), (x [1], 1), এন্ট্রি সহ একটি স্পার্স ম্যাট্রিক্স তৈরি করে কাজ করে ... CSC
(সংকীর্ণ স্পার্স কলাম) ফর্ম্যাটটি ব্যবহার করে এটি বরং সহজ। ম্যাট্রিক্সটি তখন LIL
(লিঙ্কযুক্ত তালিকা) ফর্ম্যাটে রূপান্তরিত হয় । এই ফর্ম্যাটটি প্রতিটি সারির জন্য কলামের সূচকগুলিকে এর rows
গুণাবলী হিসাবে একটি তালিকা হিসাবে সংরক্ষণ করে , তাই আমাদের যা করা দরকার তা হ'ল তা এটিকে তালিকায় রূপান্তর করা।
মনে রাখবেন যে ছোট অ্যারে argsort
ভিত্তিক সমাধানগুলি সম্ভবত দ্রুততর তবে কিছু খুব বেশি আকারে নয় এটি অতিক্রম করবে।
সম্পাদনা করুন:
argsort
ভিত্তিক numpy
একমাত্র সমাধান:
np.split(x.argsort(kind="stable"),np.bincount(x)[:-1].cumsum())
# [array([3, 4]), array([0, 5]), array([1, 2]), array([6]), array([], dtype=int64), array([7])]
যদি গ্রুপগুলির মধ্যে সূচকগুলির ক্রম বিবেচনা না করে তবে আপনি চেষ্টাও করতে পারেন argpartition
(এটি এই ছোট উদাহরণে কোনও পার্থক্য না ঘটায় তবে এটি সাধারণভাবে নিশ্চিত নয়):
bb = np.bincount(x)[:-1].cumsum()
np.split(x.argpartition(bb),bb)
# [array([3, 4]), array([0, 5]), array([1, 2]), array([6]), array([], dtype=int64), array([7])]
সম্পাদনা করুন:
@ দিবাকর ব্যবহারের বিরুদ্ধে সুপারিশ করেছেন np.split
। পরিবর্তে, একটি লুপ সম্ভবত দ্রুত:
A = x.argsort(kind="stable")
B = np.bincount(x+1).cumsum()
[A[B[i-1]:B[i]] for i in range(1,len(B))]
অথবা আপনি ব্র্যান্ড নিউ (পাইথন 3.8 +) ওয়ালরাস অপারেটরটি ব্যবহার করতে পারেন:
A = x.argsort(kind="stable")
B = np.bincount(x)
L = 0
[A[L:(L:=L+b)] for b in B.tolist()]
সম্পাদনা করুন (সম্পাদিত):
(খাঁটি নোংরা নয়): নাম্বার বিকল্প হিসাবে (@ প্রেরকের পোস্ট দেখুন) আমরা পাইথ্রানও ব্যবহার করতে পারি।
সংকলন pythran -O3 <filename.py>
import numpy as np
#pythran export sort_to_bins(int[:],int)
def sort_to_bins(idx, mx):
if mx==-1:
mx = idx.max() + 1
cnts = np.zeros(mx + 2, int)
for i in range(idx.size):
cnts[idx[i] + 2] += 1
for i in range(3, cnts.size):
cnts[i] += cnts[i-1]
res = np.empty_like(idx)
for i in range(idx.size):
res[cnts[idx[i]+1]] = i
cnts[idx[i]+1] += 1
return [res[cnts[i]:cnts[i+1]] for i in range(mx)]
এখানে numba
হুইস্কারের পারফরম্যান্স অনুসারে জয়:
repeat(lambda:enum_bins_numba_buffer(x),number=10)
# [0.6235917090671137, 0.6071486569708213, 0.6096088469494134]
repeat(lambda:sort_to_bins(x,-1),number=10)
# [0.6235359431011602, 0.6264424560358748, 0.6217901279451326]
পুরানো জিনিস:
import numpy as np
#pythran export bincollect(int[:])
def bincollect(a):
o = [[] for _ in range(a.max()+1)]
for i,j in enumerate(a):
o[j].append(i)
return o
সময় বনাম নাম্বা (পুরানো)
timeit(lambda:bincollect(x),number=10)
# 3.5732191529823467
timeit(lambda:enumerate_bins(x),number=10)
# 6.7462647299980745
np.argsort([1, 2, 2, 0, 0, 1, 3, 5])
দেয়array([3, 4, 0, 5, 1, 2, 6, 7], dtype=int64)
। তাহলে আপনি কেবল পরবর্তী উপাদানগুলির তুলনা করতে পারেন।