Suponha que eu tenho um df
que tem colunas de 'ID', 'col_1', 'col_2'
. E eu defino uma função:
f = lambda x, y : my_function_expression
.
Agora eu quero aplicar o f
a df
duas colunas 's 'col_1', 'col_2'
para calcular elemento-wise uma nova coluna 'col_3'
, um pouco como:
df['col_3'] = df[['col_1','col_2']].apply(f)
# Pandas gives : TypeError: ('<lambda>() takes exactly 2 arguments (1 given)'
Como fazer ?
** Adicione a amostra detalhada como abaixo ***
import pandas as pd
df = pd.DataFrame({'ID':['1','2','3'], 'col_1': [0,2,3], 'col_2':[1,4,5]})
mylist = ['a','b','c','d','e','f']
def get_sublist(sta,end):
return mylist[sta:end+1]
#df['col_3'] = df[['col_1','col_2']].apply(get_sublist,axis=1)
# expect above to output df as below
ID col_1 col_2 col_3
0 1 0 1 ['a', 'b']
1 2 2 4 ['c', 'd', 'e']
2 3 3 5 ['d', 'e', 'f']
f
está fazendoRespostas:
Aqui está um exemplo usando
apply
o dataframe, com o qual estou chamandoaxis = 1
.Observe que a diferença é que, em vez de tentar passar dois valores para a função
f
, reescreva a função para aceitar um objeto da série pandas e, em seguida, indexe a série para obter os valores necessários.Dependendo do seu caso de uso, às vezes é útil criar um
group
objeto pandas e usá-loapply
no grupo.fonte
sum
foi resolvida com sucesso por qualquer um dos métodos sugeridos até o momento.df
objeto que você definiu, outra abordagem (com resultados equivalentes) édf.apply(lambda x: x[0] + x[1], axis = 1)
.Existe uma maneira limpa e de uma linha de fazer isso no Pandas:
Isso permite
f
ser uma função definida pelo usuário com vários valores de entrada e usa nomes de coluna (seguros) em vez de índices numéricos (não seguros) para acessar as colunas.Exemplo com dados (com base na pergunta original):
Saída de
print(df)
:Se os nomes das colunas contiverem espaços ou compartilharem um nome com um atributo de quadro de dados existente, você poderá indexar com colchetes:
fonte
axis=1
coluna using and you for chamada,name
ela não retornará realmente os dados da coluna, mas simindex
. Semelhante a obter oname
em umgroupby()
. Eu resolvi isso renomeando minha coluna..loc
o exemplo. Pode ser necessário se você adaptar isso a outra configuração de problema (por exemplo, trabalhando com fatias).Uma solução simples é:
fonte
Uma pergunta interessante! minha resposta como abaixo:
Resultado:
Alterei o nome da coluna para ID, J1, J2, J3 para garantir a identificação <J1 <J2 <J3, para que a coluna seja exibida na seqüência correta.
Mais uma versão resumida:
fonte
O método que você está procurando é o Series.combine. No entanto, parece que alguns cuidados devem ser tomados em relação aos tipos de dados. No seu exemplo, você (como eu fiz ao testar a resposta) chamava ingenuamente
No entanto, isso gera o erro:
Meu melhor palpite é que parece esperar que o resultado seja do mesmo tipo que a série que chama o método (df.col_1 aqui). No entanto, o seguinte funciona:
fonte
O modo como você escreveu f precisa de duas entradas. Se você olhar para a mensagem de erro, ela diz que você não está fornecendo duas entradas para f, apenas uma. A mensagem de erro está correta.
A incompatibilidade ocorre porque df [['col1', 'col2']] retorna um único quadro de dados com duas colunas, não duas colunas separadas.
Você precisa alterar seu f para que ele receba uma única entrada, mantenha o quadro de dados acima como entrada e divida-o em x, y dentro do corpo da função. Em seguida, faça o que precisar e retorne um único valor.
Você precisa dessa assinatura de função porque a sintaxe é .apply (f) Portanto, f precisa pegar a única coisa = dataframe e não duas coisas que é o que seu f atual espera.
Como você não forneceu o corpo de f, não posso ajudar em mais detalhes - mas isso deve fornecer a saída sem alterar fundamentalmente seu código ou usar outros métodos, em vez de aplicar
fonte
Vou votar em np.vectorize. Ele permite que você fotografe mais de um número x de colunas e não lide com o quadro de dados na função, por isso é ótimo para funções que você não controla ou faz algo como enviar 2 colunas e uma constante em uma função (por exemplo, col_1, col_2, 'foo').
fonte
Retornar uma lista de
apply
é uma operação perigosa, pois não é garantido que o objeto resultante seja uma Série ou um DataFrame. E exceções podem ser levantadas em certos casos. Vamos percorrer um exemplo simples:Existem três resultados possíveis com o retorno de uma lista de
apply
1) Se o comprimento da lista retornada não for igual ao número de colunas, uma Série de listas será retornada.
2) Quando o comprimento da lista retornada é igual ao número de colunas, um DataFrame é retornado e cada coluna obtém o valor correspondente na lista.
3) Se o comprimento da lista retornada for igual ao número de colunas da primeira linha, mas tiver pelo menos uma linha em que a lista tenha um número diferente de elementos que o número de colunas, um ValueError será gerado.
Respondendo ao problema sem aplicar
Usar
apply
com o eixo = 1 é muito lento. É possível obter um desempenho muito melhor (especialmente em conjuntos de dados maiores) com métodos iterativos básicos.Crie um quadro de dados maior
Horários
@Thomas answer
fonte
Tenho certeza de que isso não é tão rápido quanto as soluções que usam operações Pandas ou Numpy, mas se você não deseja reescrever sua função, pode usar o mapa. Usando os dados de exemplo originais -
Poderíamos passar tantos argumentos quanto desejássemos para a função dessa maneira. A saída é o que queríamos
fonte
apply
comaxis=1
Meu exemplo para suas perguntas:
fonte
Se você tiver um conjunto de dados enorme, poderá usar uma maneira fácil, mas mais rápida (tempo de execução) de fazer isso usando o swifter:
fonte
Suponho que você não queira alterar a
get_sublist
função e apenas queira usar oapply
método do DataFrame para fazer o trabalho. Para obter o resultado desejado, escrevi duas funções de ajuda:get_sublist_list
eunlist
. Como o nome da função sugere, primeiro obtenha a lista de sub-listas, depois extraia-os da lista. Finalmente, precisamos chamarapply
function para aplicar essas duas funções aodf[['col_1','col_2']]
DataFrame posteriormente.Se você não usar
[]
aget_sublist
função,get_sublist_list
ela retornará uma lista simples e aumentaráValueError: could not broadcast input array from shape (3) into shape (2)
, como @Ted Petrou havia mencionado.fonte