web-dev-qa-db-fra.com

Python - Supprimer les doublons dans une trame de données basée sur deux combinaisons de colonnes?

J'ai un dataframe avec 3 colonnes en Python:

Name1 Name2 Value
Juan  Ale   1
Ale   Juan  1

et souhaite éliminer les doublons en fonction des combinaisons de colonnes Nom1 et Nom2.

Dans mon exemple, les deux lignes sont égales (mais elles sont dans un ordre différent), et je voudrais supprimer la deuxième ligne et simplement conserver la première, donc le résultat final devrait être:

Name1 Name2 Value
Juan  Ale   1

Toute idée sera vraiment appréciée!

16
Juan

Vous pouvez convertir en frozenset et utiliser pd.DataFrame.duplicated .

res = df[~df[['Name1', 'Name2']].apply(frozenset, axis=1).duplicated()]

print(res)

  Name1 Name2  Value
0  Juan   Ale      1

frozenset est nécessaire au lieu de set car duplicated utilise le hachage pour vérifier les doublons.

S'adapte mieux aux colonnes qu'aux lignes. Pour un grand nombre de lignes, utilisez l'algorithme basé sur le tri de @ Wen.

18
jpp

En utilisant np.sort avec duplicated

df[pd.DataFrame(np.sort(df[['Name1','Name2']].values,1)).duplicated()]
Out[614]: 
  Name1 Name2  Value
1   Ale  Juan      1

Performance

df=pd.concat([df]*100000)

%timeit df[pd.DataFrame(np.sort(df[['Name1','Name2']].values,1)).duplicated()]
10 loops, best of 3: 69.3 ms per loop
%timeit df[~df[['Name1', 'Name2']].apply(frozenset, axis=1).duplicated()]
1 loop, best of 3: 3.72 s per loop
21
WeNYoBen

Je sais que je suis un peu en retard pour cette question mais je donne quand même ma contribution:)

Vous pouvez aussi utiliser get_dummies et add pour une bonne façon de créer des lignes lavables

df[~(pd.get_dummies(df.a).add(pd.get_dummies(df.b), fill_value=0)).duplicated()]

Les temps ne sont pas aussi bons que la réponse de @ Wen, mais ils sont toujours bien plus rapides que apply + frozen_set

df=pd.concat([df]*1000000)
%timeit df[~(pd.get_dummies(df.a).add(pd.get_dummies(df.b), fill_value=0)).duplicated()]
1.8 s ± 85 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df[pd.DataFrame(np.sort(df[['a','b']].values,1)).duplicated()]
1.26 s ± 19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit df[~df[['a', 'b']].apply(frozenset, axis=1).duplicated()]
1min 9s ± 684 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
5
rafaelc