Muitas vezes, desejo manipular display
um dataframe durante uma sequência de operações encadeadas, para as quais eu usaria*:
df = (
df
#Modify the dataframe:
.assign(new_column=...)
#View result (without killing the chain)
.pipe(lambda df_: display(df_) or df_)
#...further chaining is possible
)
O bloco de código acima adiciona new_column
ao dataframe, exibe o novo dataframe e finalmente o retorna. O encadeamento funciona aqui porque display
retorna None
**.
Minha pergunta é sobre cenários onde eu quero substituir display
por plt.plot
ou alguma função que não retorna None
. Nesses casos, df_
não se propagaria mais pela cadeia.
Atualmente, minha tarefa é definir uma função externa transparent_pipe
que possa ser executada plt.plot
ou qualquer outro método, ao mesmo tempo em que garanto que o dataframe seja propagado:
def transparent_pipe(df, *funcs):
[func(df) for func in funcs]
return df
df = (
df
#Modify the dataframe:
.assign(new_column=...)
#Visualise a column from the modified df, without killing the chain
.pipe(lambda df_: transparent_pipe(df_, plt.ecdf(df_.new_column), display(df_), ...)
#...further chaining is possible
)
Pergunta
Existe uma maneira totalmente integrada de fazer isso, sem precisar definir transparent_pipe
?
De preferência usando apenas pandas
.
*Dica do Effective Pandas 2: Padrões opinativos para manipulação de dados , M. Harrison, 2024.
**A .pipe
operação retorna df_
desde que seja display(df_) or df_
avaliada None or df_
como df_
.
Com
pyjanitor
, você pode usaralso
:Alternativamente, com uma função wrapper para ocultar a saída de qualquer função e substituí-la pelo seu primeiro parâmetro (=o DataFrame):
Ou, seguindo a abordagem original com curto-circuito:
Ou forçando uma verdade com uma tupla:
Em vez disso, você pode compor um
list
dentro da.pipe()
operação e, em seguida, extrair o dataframe dessa lista:.pipe(lambda x: [x, funcA(x), funcB(x), ...][0])
Isso permite que você defina e execute operações arbitrárias em linha, ao mesmo tempo em que garante que o dataframe modificado será propagado.
Selecionei a resposta de @mozway em vez desta resposta, embora elas sejam bem parecidas.
A quarta sugestão do @mozway é:
Eu prefiro isso ao meu porque não há necessidade de indexar o dataframe, que é retornado automaticamente por meio de avaliação de verdade.