Come rimuovo le parti indesiderate dalle stringhe in una colonna?
6 anni dopo la pubblicazione della domanda originale, Panda ora ha un buon numero di funzioni di stringa "vettorializzate" che possono eseguire in modo succinto queste operazioni di manipolazione delle stringhe.
Questa risposta esplorerà alcune di queste funzioni di stringa, suggerirà alternative più veloci e alla fine farà un confronto dei tempi.
Specificare la sottostringa / motivo da abbinare e la sottostringa con cui sostituirlo.
pd.__version__
# '0.24.1'
df
time result
1 09:00 +52A
2 10:00 +62B
3 11:00 +44a
4 12:00 +30b
5 13:00 -110a
df['result'] = df['result'].str.replace(r'\D', '')
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Se devi convertire il risultato in un numero intero, puoi utilizzare Series.astype
,
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Se non si desidera modificare df
sul posto, utilizzare DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
Utile per l'estrazione delle sottostringhe che si desidera conservare.
df['result'] = df['result'].str.extract(r'(\d+)', expand=False)
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Con extract
, è necessario specificare almeno un gruppo di acquisizione. expand=False
restituirà una serie con gli oggetti catturati dal primo gruppo di acquisizione.
La divisione delle opere presuppone che tutte le stringhe seguano questa struttura coerente.
# df['result'] = df['result'].str.split(r'\D').str[1]
df['result'] = df['result'].str.split(r'\D').str.get(1)
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Non raccomandare se stai cercando una soluzione generale.
Se sei soddisfatto delle soluzioni succinte e leggibili str
basate su accessori di cui sopra, puoi fermarti qui. Tuttavia, se sei interessato a alternative più veloci e più performanti, continua a leggere.
Ottimizzazione: elenco delle comprensioni
In alcune circostanze, la comprensione dell'elenco dovrebbe essere favorita rispetto alle funzioni di stringa panda. Il motivo è che le funzioni di stringa sono intrinsecamente difficili da vettorializzare (nel vero senso della parola), quindi la maggior parte delle funzioni di stringa e regex sono solo avvolgenti attorno a loop con più sovraccarico.
Il mio articolo, I for-loop nei panda sono davvero cattivi? Quando dovrei preoccuparmi? , entra in maggior dettaglio.
L' str.replace
opzione può essere riscritta usandore.sub
import re
# Pre-compile your regex pattern for more performance.
p = re.compile(r'\D')
df['result'] = [p.sub('', x) for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
L' str.extract
esempio può essere riscritto usando una comprensione dell'elenco con re.search
,
p = re.compile(r'\d+')
df['result'] = [p.search(x)[0] for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Se NaN o nessuna corrispondenza sono possibili, dovrai riscrivere quanto sopra per includere un controllo degli errori. Lo faccio usando una funzione.
def try_extract(pattern, string):
try:
m = pattern.search(string)
return m.group(0)
except (TypeError, ValueError, AttributeError):
return np.nan
p = re.compile(r'\d+')
df['result'] = [try_extract(p, x) for x in df['result']]
df
time result
1 09:00 52
2 10:00 62
3 11:00 44
4 12:00 30
5 13:00 110
Possiamo anche riscrivere le risposte di @eumiro e @ MonkeyButter usando la comprensione dell'elenco:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
E,
df['result'] = [x[1:-1] for x in df['result']]
Si applicano le stesse regole per la gestione delle NaN, ecc.
Confronto delle prestazioni
Grafici generati usando perfplot . Elenco completo del codice, per riferimento. Le funzioni pertinenti sono elencate di seguito.
Alcuni di questi confronti sono ingiusti perché sfruttano la struttura dei dati di OP, ma ne traggono ciò che vuoi. Una cosa da notare è che ogni funzione di comprensione dell'elenco è più veloce o comparabile della sua variante di panda equivalente.
funzioni
def eumiro(df):
return df.assign(
result=df['result'].map(lambda x: x.lstrip('+-').rstrip('aAbBcC')))
def coder375(df):
return df.assign(
result=df['result'].replace(r'\D', r'', regex=True))
def monkeybutter(df):
return df.assign(result=df['result'].map(lambda x: x[1:-1]))
def wes(df):
return df.assign(result=df['result'].str.lstrip('+-').str.rstrip('aAbBcC'))
def cs1(df):
return df.assign(result=df['result'].str.replace(r'\D', ''))
def cs2_ted(df):
# `str.extract` based solution, similar to @Ted Petrou's. so timing together.
return df.assign(result=df['result'].str.extract(r'(\d+)', expand=False))
def cs1_listcomp(df):
return df.assign(result=[p1.sub('', x) for x in df['result']])
def cs2_listcomp(df):
return df.assign(result=[p2.search(x)[0] for x in df['result']])
def cs_eumiro_listcomp(df):
return df.assign(
result=[x.lstrip('+-').rstrip('aAbBcC') for x in df['result']])
def cs_mb_listcomp(df):
return df.assign(result=[x[1:-1] for x in df['result']])