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.
3 Réponses :
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)
Pandas résout le problème mais malheureusement je dois utiliser numpy uniquement.
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.]])
Bonne solution, peut-être un peu laconique sur l'explication;)
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]
L'approche n ° 1 est incroyablement rapide! Merci! Je me demande pourquoi NumPy n'investirait pas dans le développement de fonctions groupby.