J'essaie de mettre en évidence exactement ce qui a changé entre deux dataframes.
Supposons que j'ai deux dataframes Python Pandas:
"StudentRoster Jan-1":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.11 False Graduated
113 Zoe 4.12 True
"StudentRoster Jan-2":
id Name score isEnrolled Comment
111 Jack 2.17 True He was late to class
112 Nick 1.21 False Graduated
113 Zoe 4.12 False On vacation
Mon objectif est de générer un tableau HTML qui:
- Identifie les lignes qui ont changé (peuvent être int, float, boolean, string)
Sort les lignes avec les mêmes valeurs, OLD et NEW (idéalement dans un tableau HTML) afin que le consommateur puisse voir clairement ce qui a changé entre deux dataframes:
"StudentRoster Difference Jan-1 - Jan-2": id Name score isEnrolled Comment 112 Nick was 1.11| now 1.21 False Graduated 113 Zoe 4.12 was True | now False was "" | now "On vacation"
Je suppose que je pourrais faire une comparaison ligne par ligne et colonne par colonne, mais y a-t-il un moyen plus simple?
df.compare
.Réponses:
La première partie est similaire à Constantine, vous pouvez obtenir le booléen dont les lignes sont vides *:
Ensuite, nous pouvons voir quelles entrées ont changé:
Ici, la première entrée est l'index et la seconde les colonnes qui ont été modifiées.
* Note: il est important que
df1
etdf2
partager le même indice ici. Pour surmonter cette ambiguïté, vous pouvez vous assurer de ne regarder que les étiquettes partagées en utilisantdf1.index & df2.index
, mais je pense que je vais laisser cela comme un exercice.la source
df1
à ce qui est le premierdf2
, quelle que soit la valeur de l'indice. JFYI au cas où je ne serais pas la seule personne pour laquelle ce n'était pas évident. ; D Merci!nan
dans df1 et df1, cette fonction le signalera comme étant passé denan
ànan
. C'est parce quenp.nan != np.nan
revientTrue
.Mettre en évidence la différence entre deux DataFrames
Il est possible d'utiliser la propriété de style DataFrame pour mettre en évidence la couleur d'arrière-plan des cellules où il y a une différence.
Utilisation des exemples de données de la question d'origine
La première étape consiste à concaténer les DataFrames horizontalement avec la
concat
fonction et à distinguer chaque image avec lekeys
paramètre:Il est probablement plus facile d'échanger les niveaux de colonne et de placer les mêmes noms de colonne les uns à côté des autres:
Maintenant, il est beaucoup plus facile de repérer les différences dans les cadres. Mais, on peut aller plus loin et utiliser la
style
propriété pour mettre en évidence les cellules qui sont différentes. Nous définissons une fonction personnalisée pour ce faire que vous pouvez voir dans cette partie de la documentation .Cela mettra en évidence les cellules qui ont toutes deux des valeurs manquantes. Vous pouvez les remplir ou fournir une logique supplémentaire afin qu'ils ne soient pas mis en évidence.
la source
df_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
Cette réponse étend simplement celle de @Andy Hayden, le rendant résilient aux champs numériques
nan
et l'enveloppant dans une fonction.Donc avec vos données (légèrement modifiées pour avoir un NaN dans la colonne score):
Production:
la source
impressions
la source
id
comme index,df.groupby(level='id')
celaJ'ai rencontré ce problème, mais j'ai trouvé une réponse avant de trouver ce message:
Sur la base de la réponse d'unutbu, chargez vos données ...
... définissez votre fonction diff ...
Ensuite, vous pouvez simplement utiliser un panneau pour conclure:
À propos, si vous êtes dans IPython Notebook, vous pouvez utiliser une fonction de différence colorée pour donner des couleurs selon que les cellules sont différentes, égales ou nulles gauche / droite:
la source
my_panel = pd.Panel(dict(df1=df1,df2=df2))
dans la fonctionreport_diff()
? Je veux dire, est-il possible de faire ceci:print report_diff(df1,df2)
et obtenir le même résultat que votre instruction d'impression?pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)
- C'est génial!!!Si vos deux dataframes ont les mêmes identifiants, il est en fait assez facile de découvrir ce qui a changé.
frame1 != frame2
Faire juste vous donnera un DataFrame booléen où chacunTrue
est des données qui ont changé. À partir de là, vous pouvez facilement obtenir l'index de chaque ligne modifiée en faisantchangedids = frame1.index[np.any(frame1 != frame2,axis=1)]
.la source
Une approche différente utilisant concat et drop_duplicates:
Production:
la source
Après avoir bidouillé la réponse de @ journois, j'ai pu la faire fonctionner en utilisant MultiIndex au lieu de Panel en raison de la dépréciation de Panel .
Tout d'abord, créez des données factices:
Ensuite, définissez votre fonction diff , dans ce cas j'utiliserai celle de sa réponse
report_diff
reste la même:Ensuite, je vais concaténer les données dans une trame de données MultiIndex:
Et enfin, je vais appliquer le
report_diff
bas de chaque groupe de colonnes:Cela produit:
Et c'est tout!
la source
Extension de la réponse de @cge, ce qui est plutôt cool pour plus de lisibilité du résultat:
Exemple de démonstration complète:
la source
Voici une autre façon d'utiliser la sélection et la fusion:
Voici la même chose à partir d'une capture d'écran de Jupyter:
la source
pandas> = 1,1:
DataFrame.compare
Avec pandas 1.1, vous pourriez essentiellement répliquer la sortie de Ted Petrou avec un seul appel de fonction. Exemple tiré de la documentation:
Ici, "self" fait référence au dataFrame LHS, tandis que "other" est le DataFrame RHS. Par défaut, les valeurs égales sont remplacées par NaN afin que vous puissiez vous concentrer uniquement sur les différences. Si vous souhaitez également afficher des valeurs égales, utilisez
Vous pouvez également modifier l'axe de comparaison en utilisant
align_axis
:Cela compare les valeurs par ligne et non par colonne.
la source
Une fonction qui trouve la différence asymétrique entre deux trames de données est implémentée ci-dessous: (Basé sur la différence définie pour les pandas ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03
Exemple:
la source
importer des pandas comme pd importer numpy comme np
df = pd.read_excel ('D: \ HARISH \ DATA SCIENCE \ 1 MY Training \ SAMPLE DATA & projs \ CRICKET DATA \ IPL PLAYER LIST \ IPL PLAYER LIST _ harish.xlsx')
df1 = srh = df [df ['TEAM']. str.contains ("SRH")] df2 = csk = df [df ['TEAM']. str.contains ("CSK")]
srh = srh.iloc [:, 0: 2] csk = csk.iloc [:, 0: 2]
csk = csk.reset_index (drop = True) csk
srh = srh.reset_index (drop = True) srh
nouveau = pd.concat ([srh, csk], axe = 1)
new.head ()
** TYPE DE JOUEUR TYPE DE JOUEUR
0 David Warner Batsman ... MS Dhoni Capitaine
1 Bhuvaneshwar Kumar Bowler ... Ravindra Jadeja polyvalent
2 Manish Pandey Batsman ... Suresh Raina polyvalent
3 Rashid Khan Arman Bowler ... Kedar Jadhav polyvalent
4 Shikhar Dhawan Batsman .... Dwayne Bravo All-Rounder
la source