Eu tenho um dicionário que se parece com isso: di = {1: "A", 2: "B"}
Gostaria de aplicá-lo à coluna "col1" de um dataframe semelhante a:
col1 col2
0 w a
1 1 2
2 2 NaN
para obter:
col1 col2
0 w a
1 A 2
2 B NaN
Como posso fazer isso da melhor maneira? Por alguma razão, os termos do Google relacionados a isso mostram apenas links sobre como criar colunas a partir de dictos e vice-versa: - /
python
dictionary
pandas
remap
TheChymera
fonte
fonte
col```` is tuple. The error info is
não pode comparar 'ndarray (dtipo = objeto)' tipos e 'tuple'```'3.6.1 |Anaconda custom (64-bit)| (default, May 11 2017, 13:25:24) [MSC v.1900 64 bit (AMD64)]'
map
pode ser muito mais rápido quereplace
Se o seu dicionário tiver mais do que algumas teclas, o uso
map
poderá ser muito mais rápido quereplace
. Existem duas versões dessa abordagem, dependendo se o seu dicionário mapeia exaustivamente todos os valores possíveis (e também se você deseja que as não correspondências mantenham seus valores ou sejam convertidas em NaNs):Mapeamento exaustivo
Nesse caso, o formulário é muito simples:
Embora
map
o argumento mais comum seja uma função, ela pode usar um dicionário ou uma série: Documentation for Pandas.series.mapMapeamento não exaustivo
Se você possui um mapeamento não exaustivo e deseja manter as variáveis existentes para não correspondências, você pode adicionar
fillna
:Como na resposta da @ jpp aqui: Substitua valores em uma série de pandas via dicionário de maneira eficiente
Benchmarks
Usando os seguintes dados com o pandas versão 0.23.1:
e testando com
%timeit
, parece quemap
é aproximadamente 10x mais rápido quereplace
.Observe que sua aceleração
map
varia de acordo com seus dados. A maior aceleração parece ser com dicionários grandes e substituições exaustivas. Veja @jpp answer (link acima) para benchmarks e discussões mais abrangentes.fonte
df.replace
função, embora arrumada e útil para dictos pequenos, falhou após ser executada por 20 minutos ou mais.map
também funciona em um índice onde eu não conseguia descobrir uma maneira de fazer isso com #replace
Há um pouco de ambiguidade na sua pergunta. Há pelo menos
trêsduas interpretações:di
referem-se aos valores do índicedi
referem-se adf['col1']
valoresdi
referem-se aos locais do índice (não a pergunta do OP, mas lançada por diversão).Abaixo está uma solução para cada caso.
Caso 1: se as chaves de
di
se referirem aos valores do índice, você pode usar oupdate
método:Por exemplo,
rendimentos
Eu modifiquei os valores da sua postagem original para ficar mais claro o que
update
está fazendo. Observe como as chavesdi
estão associadas aos valores do índice. A ordem dos valores do índice - ou seja, os locais do índice - não importa.Caso 2: se as chaves se
di
referirem adf['col1']
valores, @DanAllan e @DSM mostram como conseguir isso comreplace
:rendimentos
Note como neste caso, as chaves no
di
foram alterados para coincidir com valores emdf['col1']
.Caso 3: se as chaves se
di
referirem aos locais do índice, você pode usarDesde a
rendimentos
Aqui, a primeira e a terceira linhas foram alteradas, porque as chaves
di
são são0
e2
, que com a indexação baseada em 0 do Python, se referem aos primeiro e terceiro locais.fonte
replace
é igualmente bom e talvez uma palavra melhor para o que está acontecendo aqui.update()
parece um pouco arrogante em comparação comreplace()
, mas pelo menos funciona.Adicionando a esta pergunta se você tiver mais de uma coluna para remapear em um dataframe de dados:
Espero que possa ser útil para alguém.
Felicidades
fonte
DataFrame.replace()
, embora eu não saiba quando foi adicionada.O DSM tem a resposta aceita, mas a codificação parece não funcionar para todos. Aqui está um que funciona com a versão atual do pandas (0.23.4 a partir de 8/2018):
Você verá que se parece com:
Os documentos para pandas.DataFrame.replace estão aqui .
fonte
Series.map()
parece mais flexível.Ou faça
apply
:Demo:
fonte
di
ditado é um ditado de listas? Como você pode mapear apenas um valor na lista?Dado que
map
é mais rápido que substituir (solução da @ JohnE), você precisa ter cuidado com os mapeamentos não exaustivos para os quais pretende mapear valores específicosNaN
. O método apropriado, neste caso, requer que vocêmask
a série quando você.fillna
, senão você desfaz o mapeamentoNaN
.fonte
Uma boa solução completa que mantém um mapa dos rótulos das suas turmas:
Dessa forma, você pode, a qualquer momento, consultar o rótulo da classe original em labels_dict.
fonte
Como uma extensão do que foi proposto por Nico Coallier (aplicar a várias colunas) e U10-Forward (usando o estilo de métodos de aplicação), e resumindo-o em uma linha, proponho:
Os
.transform()
processos de cada coluna como uma série. Ao contrário do.apply()
que passa as colunas agregadas em um DataFrame.Conseqüentemente, você pode aplicar o método Series
map()
.Finalmente, e eu descobri esse comportamento graças ao U10, você pode usar toda a série na expressão .get (). A menos que eu tenha entendido mal o seu comportamento e ele processe seqüencialmente a série, em vez de de maneira pouco inteligente.
As
.get(x,x)
contas dos valores que você não mencionou no seu dicionário de mapeamento, que seriam consideradas Nan de outra forma pelo.map()
métodofonte
.transform()
processos de cada coluna como uma série. Ao contrário do.apply()
que passa as colunas agregadas em um DataFrame. Eu apenas tentei,apply()
funciona bem. Também não há necessidade de usarloc
, isso parece muito complexo.df[["col1", "col2"]].apply(lambda col: col.map(lambda elem: my_dict.get(elem, elem)))
deve funcionar muito bem. As.get(x,x)
contas dos valores que você não mencionou no seu dicionário de mapeamento, que seriam consideradas Nan de outra forma pelo.map()
método Você também pode usarfillna()
posteriormente.Uma abordagem mais nativa dos pandas é aplicar uma função de substituição como abaixo:
Depois de definir a função, você pode aplicá-la ao seu quadro de dados.
fonte