Estoy tratando de resaltar exactamente lo que cambió entre dos marcos de datos.
Supongamos que tengo dos marcos de datos de 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
Mi objetivo es generar una tabla HTML que:
- Identifica las filas que han cambiado (podría ser int, float, boolean, string)
Emite filas con los mismos valores, VIEJO y NUEVO (idealmente en una tabla HTML) para que el consumidor pueda ver claramente qué cambió entre dos marcos de datos:
"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"
Supongo que podría hacer una comparación fila por fila y columna por columna, pero ¿hay alguna manera más fácil?
df.compare
.Respuestas:
La primera parte es similar a Constantine, puede obtener el valor booleano de qué filas están vacías *:
Luego podemos ver qué entradas han cambiado:
Aquí la primera entrada es el índice y la segunda las columnas que se han modificado.
* Nota: es importante que
df1
ydf2
comparta el mismo índice aquí. Para superar esta ambigüedad, puede asegurarse de que solo mira las etiquetas compartidas usandodf1.index & df2.index
, pero creo que lo dejaré como un ejercicio.fuente
df1
lo que sea primerodf2
, independientemente del valor del índice. JFYI en caso de que no sea la única persona para la que esto no era obvio. ; D Gracias!nan
en df1 y df1, esta función informará que ha cambiado denan
anan
. Esto es porquenp.nan != np.nan
regresaTrue
.Destacando la diferencia entre dos DataFrames
Es posible usar la propiedad de estilo DataFrame para resaltar el color de fondo de las celdas donde hay una diferencia.
Usando los datos de ejemplo de la pregunta original
El primer paso es concatenar los marcos de datos horizontalmente con la
concat
función y distinguir cada marco con elkeys
parámetro:Probablemente sea más fácil intercambiar los niveles de columna y poner los mismos nombres de columna uno al lado del otro:
Ahora, es mucho más fácil detectar las diferencias en los cuadros. Pero, podemos ir más allá y usar la
style
propiedad para resaltar las celdas que son diferentes. Definimos una función personalizada para hacer esto que puede ver en esta parte de la documentación .Esto resaltará las celdas que tienen valores faltantes. Puede llenarlos o proporcionar una lógica adicional para que no se resalten.
fuente
df_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
Esta respuesta simplemente extiende @Andy Hayden's, haciéndolo resistente a los campos numéricos
nan
y envolviéndolo en una función.Entonces, con sus datos (ligeramente editados para tener un NaN en la columna de puntuación):
Salida:
fuente
huellas dactilares
fuente
id
como índice,df.groupby(level='id')
aparece un error, y no estoy seguro de por qué ...Me he enfrentado a este problema, pero encontré una respuesta antes de encontrar esta publicación:
Según la respuesta de unutbu, cargue sus datos ...
... define tu función diff ...
Entonces puede simplemente usar un Panel para concluir:
Por cierto, si está en IPython Notebook, es posible que desee utilizar una función de diferencias de color para dar colores dependiendo de si las celdas son diferentes, iguales o nulas izquierda / derecha:
fuente
my_panel = pd.Panel(dict(df1=df1,df2=df2))
dentro de la funciónreport_diff()
? Quiero decir, ¿es posible hacer esto:print report_diff(df1,df2)
y obtener el mismo resultado que su declaración de impresión?pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)
- esto es genial !!!Si sus dos marcos de datos tienen los mismos identificadores, descubrir qué ha cambiado es bastante fácil. Simplemente hacerlo
frame1 != frame2
le dará un Marco deTrue
datos booleano donde cada uno es información que ha cambiado. A partir de eso, puede obtener fácilmente el índice de cada fila modificada haciendochangedids = frame1.index[np.any(frame1 != frame2,axis=1)]
.fuente
Un enfoque diferente usando concat y drop_duplicates:
Salida:
fuente
Después de jugar con la respuesta de @ journois, pude hacer que funcionara usando MultiIndex en lugar de Panel debido a la depricación de Panel .
Primero, cree algunos datos ficticios:
Luego, defina su función diff , en este caso usaré la de su respuesta que
report_diff
permanece igual:Luego, voy a concatenar los datos en un marco de datos MultiIndex:
Y finalmente voy a aplicar el
report_diff
grupo de cada columna hacia abajo:Esto produce:
¡Y eso es todo!
fuente
Ampliando la respuesta de @cge, que es bastante bueno para una mayor legibilidad del resultado:
Ejemplo de demostración completa:
fuente
Aquí hay otra forma de usar select y merge:
Aquí está lo mismo de una captura de pantalla de Jupyter:
fuente
pandas> = 1.1:
DataFrame.compare
Con pandas 1.1, esencialmente podría replicar la salida de Ted Petrou con una sola llamada de función. Ejemplo tomado de los documentos:
Aquí, "self" se refiere al LHS dataFrame, mientras que "other" es el RHS DataFrame. Por defecto, los valores iguales se reemplazan con NaN para que pueda centrarse solo en las diferencias. Si también desea mostrar valores que sean iguales, use
También puede cambiar el eje de comparación usando
align_axis
:Esto compara los valores en fila, en lugar de en columna.
fuente
A continuación se implementa una función que encuentra la diferencia asimétrica entre dos marcos de datos: (Basado en la diferencia establecida para pandas ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03
Ejemplo:
fuente
importar pandas como pd importar numpy como 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 ['EQUIPO']. str.contains ("SRH")] df2 = csk = df [df ['EQUIPO']. 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
nuevo = pd.concat ([srh, csk], axis = 1)
new.head ()
** TIPO DE JUGADOR TIPO DE JUGADOR
0 David Warner Batsman ... MS Dhoni Capitán
1 Bhuvaneshwar Kumar Bowler ... Ravindra Jadeja All-Rounder
2 Manish Pandey Batsman ... Suresh Raina All-Rounder
3 Rashid Khan Arman Bowler ... Kedar Jadhav All-Rounder
4 Shikhar Dhawan Batsman ... Dwayne Bravo All-Rounder
fuente