adicione um prefixo de string a cada valor em uma coluna de string usando Pandas

119

Eu gostaria de acrescentar uma string ao início de cada valor em uma coluna de um dataframe pandas (elegantemente). Já descobri como fazer isso e atualmente estou usando:

df.ix[(df['col'] != False), 'col'] = 'str'+df[(df['col'] != False), 'col']

Isso parece uma coisa muito deselegante de se fazer - você conhece alguma outra maneira (que talvez também adicione o caractere às linhas em que a coluna é 0 ou NaN)?

Caso isso ainda não esteja claro, gostaria de virar:

    col 
1     a
2     0

para dentro:

       col 
1     stra
2     str0
TheChymera
fonte
O que exatamente você está perguntando? por favor escreva uma explicação sobre o que seu código faz / gostaria que fizesse
Ryan Saxe
1
Achei que o que o código de exemplo faz era muito claro para o usuário médio do pandas. Eu adicionei exemplos de casos de uso para sua conveniência.
TheChymera de
3
Sua descrição está um pouco em desacordo com seu código. O que está acontecendo com o != Falsenegócio? Você quer agregar stra todos os valores ou apenas a alguns?
BrenBarn
para cada valor, conforme mostrado em meus dataframes de exemplo.
TheChymera de
1
seu exemplo ainda não está claro, você quer algo assim df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar de

Respostas:

223
df['col'] = 'str' + df['col'].astype(str)

Exemplo:

>>> df = pd.DataFrame({'col':['a',0]})
>>> df
  col
0   a
1   0
>>> df['col'] = 'str' + df['col'].astype(str)
>>> df
    col
0  stra
1  str0
Roman Pekar
fonte
1
obrigado. se for de interesse, os índices de dataframe também suportam tais manipulações de strings.
tagoma
2
Como faço isso se as condições devem ser atendidas antes da concatenação?
acecabana de
1
@tagoma, após 4 anos, Sim: também suporta os índices de dataframe. Você pode criar uma nova coluna e anexar ao valor do índice como: df ['col'] = 'str' + df.index.astype (str)
MEdwin
"astype (str)" pode arruinar a codificação se você estiver tentando salvar em um arquivo no final.
Raein Hashemi
2
Quando tento isso, assim como qualquer outra abordagem, recebo um SettingWithCopyWarning. Existe uma maneira de evitá-lo?
Madan Ivan
13

Como alternativa, você também pode usar um applycombinado com format(ou melhor, com f-strings) que considero um pouco mais legível se alguém, por exemplo, também quiser adicionar um sufixo ou manipular o próprio elemento:

df = pd.DataFrame({'col':['a', 0]})

df['col'] = df['col'].apply(lambda x: "{}{}".format('str', x))

que também produz a saída desejada:

    col
0  stra
1  str0

Se estiver usando o Python 3.6+, você também pode usar f-strings:

df['col'] = df['col'].apply(lambda x: f"str{x}")

produzindo a mesma saída.

A versão da string f é quase tão rápida quanto a solução de @RomanPekar (python 3.6.4):

df = pd.DataFrame({'col':['a', 0]*200000})

%timeit df['col'].apply(lambda x: f"str{x}")
117 ms ± 451 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

%timeit 'str' + df['col'].astype(str)
112 ms ± 1.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

Usar format, no entanto, é realmente muito mais lento:

%timeit df['col'].apply(lambda x: "{}{}".format('str', x))
185 ms ± 1.07 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Cleb
fonte
mesmo resultado, mas muito mais lento ;-)
Philipp_Kats
1
@Philipp_Kats: Eu adicionei alguns horários, obrigado pela sugestão! Parece que as cordas f são quase tão rápidas; formatna verdade, tem um desempenho pior. Como você se compara?
Cleb
Ah legal! no meu entendimento .applyé sempre tão rápido ou mais lento do que as operações vetorizadas "diretas"; mesmo que não sejam mais lentos, prefiro evitá-los sempre que possível.
Philipp_Kats
@Philipp_Kats: Concordo, no entanto, neste caso em particular acho mais legível quando também adiciono um sufixo, faço algo consigo xmesmo etc., mas isso é apenas uma questão de gosto ... :)
Cleb
4

Você pode usar o pandas.Series.map:

df['col'].map('str{}'.format)

Ele aplicará a palavra "str" ​​antes de todos os seus valores.

Boxtell
fonte
3

Se você carregar seu arquivo de tabela dtype=str
ou converter o tipo de coluna em string df['a'] = df['a'].astype(str)
, poderá usar essa abordagem:

df['a']= 'col' + df['a'].str[:]

Esta abordagem permite prefixar, acrescentar e subconjunto de strings de df.
Funciona no Pandas v0.23.4, v0.24.1. Não sei sobre as versões anteriores.

Vasyl Vaskivskyi
fonte
0

Outra solução com .loc:

df = pd.DataFrame({'col': ['a', 0]})
df.loc[df.index, 'col'] = 'string' + df['col'].astype(str)

Isso não é tão rápido quanto as soluções acima (> 1 ms por loop mais lento), mas pode ser útil no caso de você precisar de mudança condicional, como:

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)
Lukas
fonte
Por que .indexem df[mask].index?
AMC
@AMC porque para .loc você precisa de índices do dataframe. Isso significa que - df [máscara] retorna o quadro de dados que corresponde à condição e o df [máscara] .index retorna os índices do quadro de dados. Mas é verdade que você pode fazer o mesmo com df.loc [(df ['col'] == 'a'), 'col'] ou df.loc [máscara, 'col'] também.
Lukas,
1
porque para .loc você precisa de índices do dataframe. Se df.loc[mask]funcionar, e funciona, então .indexé supérfluo, certo?
AMC
@AMC exatamente :). Eu editei a solução. Obrigado.
Lukas