3
votes

Regrouper la liste des tuples par deuxième élément, prendre la moyenne du premier élément

J'ai une liste de tuples (x, y) comme:

l = [(2.5,1), (4,6), (2,7), (7,10)]

Maintenant je veux créer une nouvelle liste:

l = [(2,1), (4,6), (3,1), (2,7), (7,10)]

avec la nouvelle liste ayant la moyenne de la première valeur (x) des tuples s'il y a plus d'un tuple avec la même deuxième valeur (y) dans le tuple.

Ici, puisque pour (x, y) = (2,1) et (3,1) le deuxième élément du tuple y = 1 est commun donc la moyenne de x = 2 et 3 est dans la nouvelle liste. y = 1 ne se produit nulle part ailleurs, donc les autres tuples restent inchangés.


1 commentaires

Pourquoi avez-vous tagué des pandas mais donné une liste de tuples (au lieu de dataframe) en entrée? pandas Dataframe fonctionne beaucoup mieux. Les listes Python natives ont des capacités très limitées pour le traitement des tuples.


4 Réponses :


2
votes

Puisque vous avez balisé pandas:

array([[ 2.5,  1. ],
       [ 4. ,  6. ],
       [ 2. ,  7. ],
       [ 7. , 10. ]])

Alors df est un bloc de données avec deux colonnes:

(df.groupby(1).mean()     # compute mean on each group
   .reset_index()[[0,1]]  # restore the column order
   .values                # return the underlying numpy array
 )

Vous voulez maintenant calculer la moyenne des nombres dans la colonne 0 avec la même valeur dans la colonne 1:

    0   1
0   2   1
1   4   6
2   3   1
3   2   7
4   7   10

Résultat:

l = [(2,1), (4,6), (3,1), (2,7), (7,10)]
df = pd.DataFrame(l)


10 commentaires

pourriez-vous expliquer un peu ce qui se passe dans le code? ... Je suis nouveau sur les pandas


Bien sûr, voir la mise à jour. Si vous avez toujours du mal à suivre, je recommande de séparer la commande de chaîne et la sortie d'impression de chacun.


que fait le [[0,1]]? Je sais que c'est inverser l'ordre des colonnes, mais comment fait-il cela?


sans elle, les données apparaîtront sous la forme colonne 1, colonne 0 .


oui je sais que .. je demande comment cela se passe? comment s'inverse-t-il?


C'est similaire au découpage en numpy . En fait, je crois que c'est le découpage de numpy car DataFrame est une sous-classe du tableau numpy.


@smci honnêtement, je n'avais pas la moindre idée de dégrouper .


@smci pouvez-vous fournir des références?


@QuangHoang: désolé, je suis un idiot, .reset_index () est correct. (J'ai confondu les pandas avec R). Mais je me demandais si le [0,1] était évitable.


@smci oui, sans elle [[0,1]], le dataframe est ordonné comme [1,0] puisque 1 était l'index.



0
votes

Commencez par former une table de hachage / dict de tous les seconds éléments comme clé et leur valeur correspondante comme liste de valeurs. Ensuite, avec un listcomp, vous pouvez obtenir la sortie souhaitée en itérant sur les éléments du dict.

from collections import defaultdict
out = defaultdict(list)
for i in l:
    out[i[1]] += [i[0]]
out = [(sum(v)/len(v), k) for k, v in out.items()]
print(out)
#prints [(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]


0 commentaires

0
votes

Une autre façon d'utiliser groupby :

[(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]

Vous obtenez:

from itertools import groupby

# Sort list by the second element
sorted_list = sorted(l,key=lambda x:x[1])

# Group by second element
grouped_list = groupby(sorted_list, key=lambda x:x[1])

result = []
for _,group in grouped_list:
    x,y = list(zip(*group))
    # Take the mean of the first elements
    result.append((sum(x) / len(x),y[0]))


2 commentaires

pour _, group in groupby (...) est presque toujours évitable et toujours mauvais idiome. Pire également les performances sur les grandes données.


Jamais entendu parler de ça. Avez-vous un article / une référence à ce sujet?



0
votes

Voici une méthode utilisant numpy.bincount . Il repose sur le fait que les étiquettes sont des entiers non négatifs. (Si ce n'est pas le cas, on peut commencer par np.unique (i, return_inverse = True) ).

w,i = zip(*l)
n,d = np.bincount(i,w), np.bincount(i)
v, = np.where(d)
[*zip(n[v]/d[v],v)]
# [(2.5, 1), (4.0, 6), (2.0, 7), (7.0, 10)]


0 commentaires