/ / Групирайте numpy в множество подмасиви, използвайки масив от стойности - numpy

Групировката набъбна в множество под-масиви, използвайки масив от стойности - номера

Имам масив от точки по линия:

a = np.array([18, 56, 32, 75, 55, 55])

Имам друг масив, който съответства на индексите, които искам да използвам за достъп до информацията в (те винаги ще имат еднакви дължини). Нито един масив a нито масив b са сортирани.

b = np.array([0, 2, 3, 2, 2, 2])

Искам да се групирам a в множество подмасиви, така че да е възможно следното:

c[0] -> array([18])
c[2] -> array([56, 75, 55, 55])
c[3] -> array([32])

Въпреки че горният пример е прост, аз ще бъдасправяне с милиони точки, затова се предпочитат ефикасни методи. Също така е важно по-късно, че всеки под-масив от точки може да се получи по този начин по-късно в програмата чрез автоматизирани методи.

Отговори:

4 за отговор № 1

Ето един подход -

def groupby(a, b):
# Get argsort indices, to be used to sort a and b in the next steps
sidx = b.argsort(kind="mergesort")
a_sorted = a[sidx]
b_sorted = b[sidx]

# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,b_sorted[1:] != b_sorted[:-1],True])

# Split input array with those start, stop ones
out = [a_sorted[i:j] for i,j in zip(cut_idx[:-1],cut_idx[1:])]
return out

По-прост, но по-малко ефективен подход би бил да се използва np.split да замените последните няколко реда и да получите изхода, така -

out = np.split(a_sorted, np.flatnonzero(b_sorted[1:] != b_sorted[:-1])+1 )

Примерно изпълнение -

In [38]: a
Out[38]: array([18, 56, 32, 75, 55, 55])

In [39]: b
Out[39]: array([0, 2, 3, 2, 2, 2])

In [40]: groupby(a, b)
Out[40]: [array([18]), array([56, 75, 55, 55]), array([32])]

За да получите под-масиви, обхващащи целия диапазон от идентификатори в b -

def groupby_perID(a, b):
# Get argsort indices, to be used to sort a and b in the next steps
sidx = b.argsort(kind="mergesort")
a_sorted = a[sidx]
b_sorted = b[sidx]

# Get the group limit indices (start, stop of groups)
cut_idx = np.flatnonzero(np.r_[True,b_sorted[1:] != b_sorted[:-1],True])

# Create cut indices for all unique IDs in b
n = b_sorted[-1]+2
cut_idxe = np.full(n, cut_idx[-1], dtype=int)

insert_idx = b_sorted[cut_idx[:-1]]
cut_idxe[insert_idx] = cut_idx[:-1]
cut_idxe = np.minimum.accumulate(cut_idxe[::-1])[::-1]

# Split input array with those start, stop ones
out = [a_sorted[i:j] for i,j in zip(cut_idxe[:-1],cut_idxe[1:])]
return out

Примерно изпълнение -

In [241]: a
Out[241]: array([18, 56, 32, 75, 55, 55])

In [242]: b
Out[242]: array([0, 2, 3, 2, 2, 2])

In [243]: groupby_perID(a, b)
Out[243]: [array([18]), array([], dtype=int64),
array([56, 75, 55, 55]), array([32])]