2
votes

Supprimer les doublons, mais conserver les lignes avec la valeur la plus élevée, y compris les liens

Je souhaite supprimer les valeurs en double pour col1 , en enregistrant uniquement les lignes avec la valeur la plus élevée dans col2 . Exemple df:

dfoutput = pd.DataFrame({'col1': ['a', 'a', 'b', 'c'],
                       'col2': [5, 5, 15, 20]})

Je sais que df1.drop_duplicates se débarrassera des valeurs en double, mais comment puis-je m'assurer que c'est la valeur la plus élevée qui est enregistrée (ou plusieurs valeurs s'il y a des valeurs liées pour la plus élevée)?

Sortie souhaitée:

df1 = pd.DataFrame({'col1': ['a', 'a', 'b', 'b', 'c'],
                   'col2': [5, 5, 10, 15, 20]})


0 commentaires

3 Réponses :


2
votes

Commencez par trier votre DataFrame par ordre décroissant. Ensuite, calculez deux masques, l'un pour déterminer quelles lignes sont le maximum dans leur groupe, et l'autre pour déterminer quelles lignes sont dupliquées.

Nous pouvons ensuite combiner ces masques pour déterminer quelles lignes sont dupliquées et pas le maximum dans leurs groupes respectifs, et effectuez une dernière étape de filtrage.

v = df1.sort_values('col2', ascending=False)
m1 = v['col2'] == v.groupby('col1', sort=False)['col2'].transform('max')
m2 = v.duplicated('col1')

v[~(m2 & ~m1)].sort_index()   # v[~m2 | m1] - DeMorgan's Law

  col1  col2
0    a     5
1    a     5
3    b    15
4    c    20


2 commentaires

J'aime mieux le premier, il donne le rendement souhaité par l'OP. :)


@ anky_91 Merci! Je ne savais pas qu'il y avait une différence dans le résultat! A également attribué +1 au vôtre.



4
votes

Vous pouvez utiliser la fonction rank of Pandas:

Attribuez le rang à chaque ligne du groupe. Si les valeurs sont identiques, les lignes auront le même rang. Quelque chose comme ci-dessous:

In [130]: df1[df1.groupby('col1')['col2'].rank() < 2]
Out[130]: 
  col1  col2
0    a     5
1    a     5
2    b    10
4    c    20

Ensuite, utilisez query pour filtrer uniquement les classements inférieurs à 2.0:

In [129]: df1.query('rnk < 2.0').drop('rnk',1)
Out[129]: 
  col1  col2
0    a     5
1    a     5
2    b    10
4    c    20

Peut combiner les deux commandes pour obtenir une solution sur 1 ligne:

In [126]: df1['rnk'] = df1.groupby('col1')['col2'].rank()
In [127]: df1
Out[127]: 
  col1  col2  rnk
0    a     5  1.5
1    a     5  1.5
2    b    10  1.0
3    b    15  2.0
4    c    20  1.0


3 commentaires

Solution intéressante!


En fait, il n'y a pas besoin de colonne supplémentaire, il suffit de faire df1 [df1.groupby ('col1') ['col2']. Rank () <2] fonctionnera.


Oui, je sais qu'il n'y a pas besoin de la colonne supplémentaire. Il suffit de le mettre là pour comprendre OP.



2
votes

une autre manière que j'ai trouvée:

obtenir des doublons et les ajouter avec des valeurs dédupliquées après le tri dans l'ordre décroissant , puis se débarrasser de l'index dupliqué.

dfoutput = df1[df1.duplicated(keep=False)].append(df1.sort_values(['col1','col2'],ascending=False).drop_duplicates(['col1']))
dfoutput[~dfoutput.index.duplicated()].sort_index()

    col1    col2
0   a       5
1   a       5
3   b       15
4   c       20


0 commentaires