Estou tentando destacar exatamente o que mudou entre dois quadros de dados.
Suponha que eu tenha dois quadros de dados do 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
Meu objetivo é gerar uma tabela HTML que:
- Identifica as linhas que foram alteradas (podem ser int, float, boolean, string)
Gera linhas com os mesmos valores OLD e NEW (idealmente em uma tabela HTML) para que o consumidor possa ver claramente o que mudou entre dois quadros de dados:
"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"
Suponho que eu poderia fazer uma comparação linha por linha e coluna por coluna, mas existe uma maneira mais fácil?
df.compare
.Respostas:
A primeira parte é semelhante a Constantine, você pode obter o booleano de quais linhas estão vazias *:
Então podemos ver quais entradas foram alteradas:
Aqui a primeira entrada é o índice e a segunda as colunas que foram alteradas.
* Nota: é importante
df1
edf2
compartilhe o mesmo índice aqui. Para superar essa ambiguidade, você pode garantir que apenas analise os rótulos compartilhados usandodf1.index & df2.index
, mas acho que deixarei isso como um exercício.fonte
df1
a ser o primeiro adf2
entrar, independentemente do valor do índice. JFYI, caso eu não seja a única pessoa para a qual isso não era óbvio. ; D Obrigado!nan
em df1 e df1, esta função relatará que ela foi alterada denan
paranan
. Isso ocorre porquenp.nan != np.nan
retornaTrue
.Destacando a diferença entre dois DataFrames
É possível usar a propriedade de estilo DataFrame para destacar a cor de fundo das células onde há uma diferença.
Usando os dados de exemplo da pergunta original
A primeira etapa é concatenar os DataFrames horizontalmente com a
concat
função e distinguir cada quadro com okeys
parâmetro:Provavelmente é mais fácil trocar os níveis das colunas e colocar os mesmos nomes de colunas um ao lado do outro:
Agora, é muito mais fácil identificar as diferenças nos quadros. Porém, podemos ir além e usar a
style
propriedade para destacar as células que são diferentes. Definimos uma função personalizada para fazer isso, que você pode ver nesta parte da documentação .Isso destacará as células que possuem valores ausentes. Você pode preenchê-los ou fornecer lógica extra para que eles não fiquem realçados.
fonte
df_final[(df != df2).any(1)].style.apply(highlight_diff, axis=None)
Essa resposta simplesmente estende o @Andy Hayden, tornando-o resiliente para quando os campos numéricos são
nan
e agrupando-o em uma função.Portanto, com seus dados (levemente editados para ter um NaN na coluna de pontuação):
Resultado:
fonte
impressões
fonte
id
como o índice, em seguida,df.groupby(level='id')
gera um erro, e eu não sei porquê ...Eu enfrentei esse problema, mas encontrei uma resposta antes de encontrar este post:
Com base na resposta da unutbu, carregue seus dados ...
... defina sua função diff ...
Então você pode simplesmente usar um painel para concluir:
A propósito, se você estiver no IPython Notebook, poderá usar uma função diff colorida para fornecer cores, dependendo se as células forem diferentes, iguais ou nulas esquerda / direita:
fonte
my_panel = pd.Panel(dict(df1=df1,df2=df2))
dentro da funçãoreport_diff()
? Quero dizer, é possível fazer isso:print report_diff(df1,df2)
e obter a mesma saída que sua declaração de impressão?pd.Panel(dict(df1=df1,df2=df2)).apply(report_diff, axis=0)
- isso é incrível!!!Se seus dois quadros de dados tiverem os mesmos IDs, descobrir o que mudou é realmente muito fácil. Apenas fazer
frame1 != frame2
lhe dará um DataFrame booleano, onde cadaTrue
um deles é alterado. Com isso, é possível obter facilmente o índice de cada linha alteradachangedids = frame1.index[np.any(frame1 != frame2,axis=1)]
.fonte
Uma abordagem diferente usando concat e drop_duplicates:
Resultado:
fonte
Depois de brincar com a resposta do @ journois, consegui fazê-lo funcionar usando o MultiIndex em vez do Panel devido à privação do Panel .
Primeiro, crie alguns dados fictícios:
Em seguida, defina sua função diff , neste caso, usarei a da resposta dele
report_diff
a mesma:Então, vou concatenar os dados em um quadro de dados MultiIndex:
E, finalmente, vou aplicar o
report_diff
grupo abaixo de cada coluna:Isso gera:
E isso é tudo!
fonte
Estendendo a resposta do @cge, que é bem legal para obter mais legibilidade do resultado:
Exemplo completo de demonstração:
fonte
Aqui está outra maneira de selecionar e mesclar:
Aqui está o mesmo de uma captura de tela do Jupyter:
fonte
pandas> = 1.1:
DataFrame.compare
Com o pandas 1.1, você pode essencialmente replicar a saída de Ted Petrou com uma única chamada de função. Exemplo retirado dos documentos:
Aqui, "self" refere-se ao dataFrame do LHS, enquanto "outro" é o DataFrame do RHS. Por padrão, valores iguais são substituídos por NaNs para que você possa se concentrar apenas nas diferenças. Se você deseja mostrar valores iguais também, use
Você também pode alterar o eixo de comparação usando
align_axis
:Isso compara valores em linhas, em vez de em colunas.
fonte
Uma função que encontra diferença assimétrica entre dois quadros de dados é implementada abaixo: (Com base na diferença definida para pandas ) GIST: https://gist.github.com/oneryalcin/68cf25f536a25e65f0b3c84f9c118e03
Exemplo:
fonte
importar pandas como pd importar numpy como np
df = pd.read_excel ('D: \ HARISH \ DATA SCIENCE \ 1 MEU treinamento \ AMOSTRA DE DADOS E 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
new = pd.concat ([srh, csk], eixo = 1)
new.head ()
** TIPO DE JOGADOR TIPO DE JOGADOR
0 David Warner Batsman ... MS Dhoni Capitão
1 Bhuvaneshwar Kumar Bowler ... Ravindra Jadeja Polivalente
2 Manish Pandey Batsman ... Suresh Raina Polivalente
3 Rashid Khan Arman Bowler ... Kedar Jadhav Polivalente
4 Shikhar Dhawan Batsman ... Dwayne Bravo Polivalente
fonte