Estou trabalhando com a biblioteca pandas e quero adicionar duas novas colunas a um dataframe df
com n colunas (n> 0).
Essas novas colunas resultam da aplicação de uma função a uma das colunas no dataframe.
A função a ser aplicada é como:
def calculate(x):
...operate...
return z, y
Um método para criar uma nova coluna para uma função que retorna apenas um valor é:
df['new_col']) = df['column_A'].map(a_function)
Então, o que eu quero, e tentei sem sucesso (*), é algo como:
(df['new_col_zetas'], df['new_col_ys']) = df['column_A'].map(calculate)
Qual poderia ser a melhor maneira de fazer isso? Eu examinei a documentação sem nenhuma pista.
** df['column_A'].map(calculate)
retorna uma série pandas em que cada item consiste em uma tupla z, y. E tentar atribuir isso a duas colunas de dataframe produz um ValueError. *
A principal resposta é falha em minha opinião. Felizmente, ninguém está importando em massa todos os pandas para seu namespace com
from pandas import *
. Além disso, omap
método deve ser reservado para aqueles momentos em que é passado um dicionário ou série. Pode ter uma função, mas é para isso queapply
é usado.Então, se você deve usar a abordagem acima, eu escreveria assim
Na verdade, não há razão para usar o zip aqui. Você pode simplesmente fazer isso:
Este segundo método também é muito mais rápido em DataFrames maiores
DataFrame criado com 300.000 linhas
60x mais rápido do que zip
Em geral, evite usar aplicar
Aplicar geralmente não é muito mais rápido do que iterar em uma lista Python. Vamos testar o desempenho de um loop for para fazer a mesma coisa que acima
Portanto, é duas vezes mais lento, o que não é uma regressão de desempenho terrível, mas se citonizarmos o acima, obteremos um desempenho muito melhor. Supondo que você esteja usando ipython:
Atribuir diretamente sem aplicar
Você pode obter melhorias de velocidade ainda maiores se usar as operações vetorizadas diretas.
Isso aproveita as operações vetorizadas extremamente rápidas do NumPy em vez de nossos loops. Agora temos um aumento de 30x em relação ao original.
O teste de velocidade mais simples com
apply
O exemplo acima deve mostrar claramente o quão lento
apply
pode ser, mas só para ficar mais claro, vamos dar uma olhada no exemplo mais básico. Vamos elevar ao quadrado uma série de 10 milhões de números com e sem aplicaçãoSem aplicar é 50x mais rápido
fonte
applymap
caso quando você tem que implementar uma função específica para cada elemento do dataframe?func(series)
vez deseries.apply(func)
só se aplica quando a função é totalmente definida usando operações que se comportam de maneira semelhante em um valor individual e em uma série. Esse é o caso no exemplo da primeira resposta, mas não é o caso na pergunta do OP, que está perguntando de forma mais geral sobre a aplicação de funções a colunas. 1/2DataFrame({'a': ['Aaron', 'Bert', 'Christopher'], 'b': ['Bold', 'Courageous', 'Distrusted']})
ecalc
é:def calc(x): return x[0], len(x)
entãotdf.a.apply(calc))
ecalc(tdf.a)
retorna coisas muito diferentes.