aggiungi un prefisso di stringa a ciascun valore in una colonna di stringhe utilizzando Pandas


119

Vorrei aggiungere una stringa all'inizio di ogni valore in una detta colonna di un dataframe panda (elegantemente). Ho già capito come farlo e attualmente sto usando:

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

Questa sembra una cosa inelegante da fare - conosci un altro modo (che forse aggiunge anche il carattere alle righe in cui quella colonna è 0 o NaN)?

Nel caso in cui ciò non sia ancora chiaro, vorrei trasformare:

    col 
1     a
2     0

in:

       col 
1     stra
2     str0

Cosa stai chiedendo esattamente? per favore scrivi una spiegazione su ciò che il tuo codice fa / desidera che abbia fatto
Ryan Saxe

1
Ho pensato che ciò che fa il codice di esempio fosse molto chiaro per l'utente medio dei panda. Ho aggiunto esempi di casi d'uso per tua comodità.
TheChymera

3
La tua descrizione è in qualche modo in contrasto con il tuo codice. Che succede con il != Falsebusiness? Vuoi aggiungere strad ogni valore o solo ad alcuni?
BrenBarn

a ogni valore, come mostrato nei miei dataframe di esempio.
TheChymera

1
il tuo esempio è ancora un po 'poco chiaro, vuoi qualcosa di simile df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar

Risposte:


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

Esempio:

>>> 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

1
grazie. se di interesse, gli indici di dataframe supportano anche tali manipolazioni di stringhe.
tagoma

2
Come faccio se le condizioni devono essere soddisfatte prima della concatenazione?
acecabana

1
@tagoma, dopo 4 anni, sì: supporta anche gli indici dei dataframe. Puoi creare una nuova colonna e aggiungere al valore dell'indice come: df ['col'] = 'str' + df.index.astype (str)
MEdwin

"astype (str)" potrebbe rovinare la codifica se stai cercando di salvare in un file alla fine.
Raein Hashemi

2
Quando provo questo e qualsiasi altro approccio ottengo un SettingWithCopyWarning. C'è un modo per evitarlo?
Madan Ivan

13

In alternativa, puoi anche usare una applycombinazione con format(o meglio con f-string) che trovo leggermente più leggibile se ad esempio si vuole anche aggiungere un suffisso o manipolare l'elemento stesso:

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

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

che produce anche l'output desiderato:

    col
0  stra
1  str0

Se stai usando Python 3.6+, puoi anche usare f-string:

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

producendo lo stesso output.

La versione f-string è veloce quasi quanto la soluzione di @ 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)

L'utilizzo format, tuttavia, è davvero molto più 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)

stesso risultato, ma molto più lento ;-)
Philipp_Kats

1
@Philipp_Kats: ho aggiunto alcuni tempi, grazie per il suggerimento! Sembra che le stringhe f siano quasi altrettanto veloci; formateffettivamente funziona peggio. Come ti sei confrontato?
Cleb

Oh bello! nella mia comprensione .applyè sempre veloce o più lento delle operazioni vettorializzate "dirette"; anche se non sono più lenti, preferisco evitarli ove possibile.
Philipp_Kats

@Philipp_Kats: sono d'accordo, tuttavia, in questo caso particolare lo trovo più leggibile quando aggiungo anche un suffisso, faccio qualcosa con xse stesso ecc., Ma è solo una questione di gusti ... :)
Cleb

4

Puoi usare pandas.Series.map:

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

Applicherà la parola "str" ​​prima di tutti i tuoi valori.


3

Se carichi il file della tabella con dtype=str
o converti il ​​tipo di colonna in stringa df['a'] = df['a'].astype(str)
, puoi utilizzare questo approccio:

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

Questo approccio consente di anteporre, accodare e subset di stringhe df.
Funziona su Pandas v0.23.4, v0.24.1. Non so delle versioni precedenti.


0

Un'altra soluzione con .loc:

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

Non è veloce come le soluzioni precedenti (> 1 ms per loop più lento) ma può essere utile nel caso in cui sia necessaria una modifica condizionale, come:

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)

Perché .indexin df[mask].index?
AMC

@AMC perché per .loc hai bisogno degli indici del dataframe. Significa che - df [mask] restituisce il dataframe che corrisponde alla condizione e df [mask] .index restituisce gli indici del dataframe. Ma è vero che puoi fare lo stesso anche con df.loc [(df ['col'] == 'a'), 'col'] o df.loc [mask, 'col'].
Lukas

1
perché per .loc hai bisogno degli indici del dataframe. Se df.loc[mask]funziona, e lo fa, allora .indexè superfluo, giusto?
AMC

@AMC esattamente :). Ho modificato la soluzione. Grazie.
Lukas
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.