Есть ли функция numpy group по функции?

Есть ли какая-либо функция в numpy для группировки этого массива ниже в первом столбце?

Я не нашел хорошего ответа в Интернете.

>>> a
array([[  1, 275],
       [  1, 441],
       [  1, 494],
       [  1, 593],
       [  2, 679],
       [  2, 533],
       [  2, 686],
       [  3, 559],
       [  3, 219],
       [  3, 455],
       [  4, 605],
       [  4, 468],
       [  4, 692],
       [  4, 613]])

Требуемый вывод:

array([[[275, 441, 494, 593]],
       [[679, 533, 686]],
       [[559, 219, 455]],
       [[605, 468, 692, 613]]], dtype=object)

Ответ 1

Вдохновленный библиотекой Eelco Hoogendoorn, но без его библиотеки и используя тот факт, что первый столбец вашего массива всегда увеличивается.

>>> np.split(a[:, 1], np.cumsum(np.unique(a[:, 0], return_counts=True)[1])[:-1])
[array([275, 441, 494, 593]),
 array([679, 533, 686]),
 array([559, 219, 455]),
 array([605, 468, 692, 613])]

Я не "тайм-аут", но это, вероятно, более быстрый способ решить вопрос:

  • Отсутствует собственный цикл python
  • Списки результатов представляют собой массивы numpy, в случае, если вам нужно выполнить другие операции numpy, новое преобразование не потребуется.
  • Сложность, такая как O (n)

PS: Я написал аналогичную строку, потому что мне нужно было "группировать" результаты np.nonzero:

>>> indexes, values = np.nonzero(...)
>>> np.split(values, np.cumsum(np.unique(indexes, return_counts=True)[1]))

Ответ 2

Пакет numpy_indexed (выражение об отказе: я его автор) стремится заполнить этот пробел в numpy. Все операции в numy-indexed полностью векторизованы, и никакие алгоритмы O (n ^ 2) не пострадали при создании этой библиотеки.

import numpy_indexed as npi
npi.group_by(a[:, 0]).split(a[:, 1])

Обратите внимание, что обычно более эффективно напрямую вычислять релевантные свойства для таких групп (то есть group_by (keys).mean(values)), а не сначала разбивать на массивы list/jagged.

Ответ 3

Numpy здесь не очень удобен, потому что желаемый результат не является массивом целых чисел (это массив объектов списка).

Я предлагаю либо чистый способ Python...

from collections import defaultdict

%%timeit
d = defaultdict(list)
for key, val in a:
    d[key].append(val)
10.7 µs ± 156 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

# result:
defaultdict(list,
        {1: [275, 441, 494, 593],
         2: [679, 533, 686],
         3: [559, 219, 455],
         4: [605, 468, 692, 613]})

... или путь панд:

import pandas as pd

%%timeit
df = pd.DataFrame(a, columns=["key", "val"])
df.groupby("key").val.apply(pd.Series.tolist)
979 µs ± 3.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

# result:
key
1    [275, 441, 494, 593]
2         [679, 533, 686]
3         [559, 219, 455]
4    [605, 468, 692, 613]
Name: val, dtype: object

Ответ 4

n = np.unique(a[:,0])
np.array( [ list(a[a[:,0]==i,1]) for i in n] )

выходы:

array([[275, 441, 494, 593], [679, 533, 686], [559, 219, 455],
       [605, 468, 692, 613]], dtype=object)

Ответ 5

Чтобы упростить ответ Винсента Дж, можно использовать return_index = True вместо return_counts = True и избавиться от cumsum:

np.split(a[:,1], np.unique(idx,return_index = True)[1][1:])

Выход

[array([275, 441, 494, 593]),
 array([679, 533, 686]),
 array([559, 219, 455]),
 array([605, 468, 692, 613])]

Ответ 6

Я использовал np.unique(), а затем np.extract()

unique = np.unique(a[:, 0:1])
answer = []
for element in unique:
    present = a[:,0]==element
    answer.append(np.extract(present,a[:,-1]))
print (answer)

[array([275, 441, 494, 593]), array([679, 533, 686]), array([559, 219, 455]), array([605, 468, 692, 613])]

Ответ 7

учитывая X как массив элементов, которые вы хотите сгруппировать, а y (массив 1D) как соответствующие группы, следующая функция группирует с помощью numpy:

def groupby(X, y):
    y = np.asarray(y)
    X = np.asarray(X)
    y_uniques = np.unique(y)
    return [X[y==yi] for yi in y_uniques]

Итак, groupby(a[:,1], a[:,0]) возвращается [array([275, 441, 494, 593]), array([679, 533, 686]), array([559, 219, 455]), array([605, 468, 692, 613])]