web-dev-qa-db-fra.com

Existe-t-il un groupe numpy par fonction?

Existe-t-il une fonction dans numpy pour regrouper ce tableau en bas de la première colonne?

Je n'ai pas pu trouver de bonne réponse sur Internet ..

>>> 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]])

Sortie recherchée:

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

Inspiré par la bibliothèque d'Eelco Hoogendoorn, mais sans sa bibliothèque, et en utilisant le fait que la première colonne de votre tableau est en augmentation constante.

>>> 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])]

Je n'ai pas "timeit" mais c'est probablement le moyen le plus rapide de répondre à la question:

  • Pas de boucle native en python
  • Les listes de résultats sont des tableaux numpy, au cas où vous auriez besoin d'effectuer d'autres opérations numpy dessus, aucune nouvelle conversion ne sera nécessaire.
  • Complexité comme O (n)

PS: J'ai écrit une ligne similaire car j'avais besoin de "grouper par" les résultats de np.nonzero:

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

Le paquet numpy_indexed package (disclaimer: je suis son auteur) vise à combler cette lacune numpy. Toutes les opérations numpy-indexées sont entièrement vectorisées et aucun algorithme O (n ^ 2) n’a été endommagé lors de la création de cette bibliothèque.

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

Notez qu'il est généralement plus efficace de calculer directement les propriétés pertinentes sur de tels groupes (c'est-à-dire, group_by (keys) .mean (values)), plutôt que de les scinder en un premier tableau.

7
Eelco Hoogendoorn

Numpy n'est pas très pratique ici car la sortie désirée n'est pas un tableau d'entiers (c'est un tableau d'objets list).

Je suggère soit la façon pure de 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]})

... ou à la façon des pandas:

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
5
Piotr
n = unique(a[:,0])
array( [ list(a[a[:,0]==i,1]) for i in n] )

les sorties:

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

En simplifiant answer de Vincent J , on peut utiliser return_index = True au lieu de return_counts = True et supprimer la cumsum:

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

Sortie

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