Eu tenho um pandas trama de dados, df_test
. Ele contém uma coluna 'tamanho' que representa o tamanho em bytes. Calculei KB, MB e GB usando o seguinte código:
df_test = pd.DataFrame([
{'dir': '/Users/uname1', 'size': 994933},
{'dir': '/Users/uname2', 'size': 109338711},
])
df_test['size_kb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0, grouping=True) + ' KB')
df_test['size_mb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0 ** 2, grouping=True) + ' MB')
df_test['size_gb'] = df_test['size'].astype(int).apply(lambda x: locale.format("%.1f", x / 1024.0 ** 3, grouping=True) + ' GB')
df_test
dir size size_kb size_mb size_gb
0 /Users/uname1 994933 971.6 KB 0.9 MB 0.0 GB
1 /Users/uname2 109338711 106,776.1 KB 104.3 MB 0.1 GB
[2 rows x 5 columns]
Executei isso em mais de 120.000 linhas e leva cerca de 2,97 segundos por coluna * 3 = ~ 9 segundos de acordo com% timeit.
Existe alguma maneira de tornar isso mais rápido? Por exemplo, posso, em vez de retornar uma coluna por vez do apply e executá-lo 3 vezes, posso retornar todas as três colunas em uma passagem para inserir de volta no dataframe original?
Todas as outras perguntas que encontrei desejam assumir vários valores e retornar um único valor . Quero pegar um único valor e retornar várias colunas .
rows_list
nesta resposta?pd.Series(data, index=...)
. Caso contrário, você obterá erros criptográficos ao tentar atribuir o resultado de volta ao dataframe pai.Use aplicar e zip 3 vezes mais rápido do que o modo de série.
Os resultados do teste são:
fonte
Algumas das respostas atuais funcionam bem, mas quero oferecer outra opção, talvez mais "pandificada". Isso funciona para mim com o atual pandas 0.23 (não tenho certeza se funcionará nas versões anteriores):
Observe que o truque está no
result_type
parâmetro deapply
, que expandirá seu resultado em umDataFrame
que pode ser atribuído diretamente a colunas novas / antigas.fonte
Apenas outra forma legível. Este código adicionará três novas colunas e seus valores, retornando séries sem usar parâmetros na função de aplicação.
Um exemplo geral de: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.apply.html
fonte
Respostas muito legais! Obrigado Jesse e jaumebonet! Apenas algumas observações em relação a:
zip(* ...
... result_type="expand")
Embora expandir seja um pouco mais elegante ( pandificado ), o zip é pelo menos ** 2x mais rápido . Neste exemplo simples abaixo, fiquei 4x mais rápido .
fonte
O desempenho entre as principais respostas é significativamente variado, e Jesse e famaral42 já discutiram isso, mas vale a pena compartilhar uma comparação justa entre as principais respostas e elaborar um detalhe sutil, mas importante da resposta de Jesse: o argumento passado para o função, também afeta o desempenho .
(Python 3.7.4, Pandas 1.0.3)
Aqui estão os resultados:
Observe como retornar tuplas é o método mais rápido, mas o que é passado em como um argumento, também afeta o desempenho. A diferença no código é sutil, mas a melhoria de desempenho é significativa.
O teste nº 4 (aprovação em um único valor) é duas vezes mais rápido que o teste nº 3 (aprovação em série), embora a operação realizada seja aparentemente idêntica.
Mas tem mais ...
Em alguns casos (# 1a e # 4a), aplicar a função a um DataFrame no qual as colunas de saída já existem é mais rápido do que criá-las a partir da função.
Aqui está o código para executar os testes:
fonte
Acredito que a versão 1.1 quebra o comportamento sugerido na resposta principal aqui.
O código acima executado no pandas 1.1.0 retorna:
Enquanto no pandas 1.0.5 ele retornou:
O que eu acho que você esperaria.
Não tenho certeza de como as notas de lançamento explicam esse comportamento, no entanto, conforme explicado aqui, evitar a mutação das linhas originais copiando-as ressuscita o comportamento antigo. ie:
fonte
Geralmente, para retornar vários valores, isso é o que eu faço
Retornar um dataframe definitivamente tem suas vantagens, mas às vezes não é obrigatório. Você pode ver o que
apply()
retorna e brincar um pouco com as funções;)fonte
Ele fornece um novo dataframe com duas colunas do original.
fonte