1
votes

Lignes moyennes avec premier élément en double dans un tableau numpy 2D

J'ai un tableau numpy comme celui-ci:

[[1, 3, 4, 5],
 [2, 2, 3, 4],
 [3, 2, 3, 4]]

Ce que je veux faire, c'est faire la moyenne des lignes de chaque première entrée en double. Dans cet exemple, calcul de la moyenne de la deuxième à la dernière colonne des première et troisième lignes. La sortie correcte doit être:

[[1, 2, 3, 4],
 [2, 2, 3, 4],
 [1, 4, 5, 6],
 [3, 2, 3, 4]]

Cette réponse Les entrées moyennes avec le premier élément en double dans le tableau numpy 2D sont très liées à ce que je veux faire.


0 commentaires

3 Réponses :


2
votes

Pouvez-vous utiliser des pandas?

import pandas as pd

df = pd.DataFrame(
    [[1, 2, 3, 4],
     [2, 2, 3, 4],
     [1, 4, 5, 6],
     [3, 2, 3, 4]], 
    columns=list('abcd')
    )

df.groupby('a').mean().reset_index().values
# returns:
array([[1, 3, 4, 5],
       [2, 2, 3, 4],
       [3, 2, 3, 4]], dtype=int64)


1 commentaires

Pandas résout le problème mais malheureusement je dois utiliser numpy uniquement.



3
votes

Voici une façon:

np.array([a[i].mean(axis=0).tolist() for i in l])

array([[1., 3., 4., 5.],
       [2., 2., 3., 4.],
       [3., 2., 3., 4.]])

Explication

En ce qui concerne la première compréhension de la liste, np.arwhere renverra un tableau avec les indices des lignes avec un premier élément commun, pour chaque élément unique

l = [np.argwhere(i==a[:,0]).ravel() for i in np.unique(a[:,0])]
[array([0, 2]), array([1]), array([3])]

Il vous suffit maintenant de découper un en fonction de chaque tableau dans l et moyenne avec:

l = [np.argwhere(i==a[:,0]).ravel() for i in np.unique(a[:,0])]
np.array([a[i].mean(axis=0).tolist() for i in l])

array([[1., 3., 4., 5.],
       [2., 2., 3., 4.],
       [3., 2., 3., 4.]])


1 commentaires

Bonne solution, peut-être un peu laconique sur l'explication;)



1
votes

Approche n ° 1

En voici une vectorisée avec NumPy -

In [51]: a
Out[51]: 
array([[1, 2, 3, 4],
       [2, 2, 3, 4],
       [1, 4, 5, 6],
       [3, 2, 3, 4]])

In [52]: groupby_mean(a)
Out[52]: 
array([[1., 3., 4., 5.],
       [2., 2., 3., 4.],
       [3., 2., 3., 4.]])

Approche n ° 2 p>

Un autre vectorisé exploitant la multiplication matricielle -

def groupby_mean_matmul(a):
    unq = np.unique(a[:,0])
    m = a[:,0,None] == unq
    return np.c_[unq, m.T.dot(a[:,1:])/m.sum(0)[:,None].astype(float)]

Exemple d'exécution -

def groupby_mean(a):
    # Sort array by groupby column
    b = a[a[:,0].argsort()]

    # Get interval indices for the sorted groupby col
    idx = np.flatnonzero(np.r_[True,b[:-1,0]!=b[1:,0],True])

    # Get counts of each group and sum rows based on the groupings & hence averages
    counts = np.diff(idx)
    avg = np.add.reduceat(b[:,1:],idx[:-1],axis=0)/counts.astype(float)[:,None]

    # Finally concatenate for the output in desired format
    return np.c_[b[idx[:-1],0],avg]


1 commentaires

L'approche n ° 1 est incroyablement rapide! Merci! Je me demande pourquoi NumPy n'investirait pas dans le développement de fonctions groupby.