¿Cómo elimino las partes no deseadas de las cadenas en una columna?
6 años después de que se publicó la pregunta original, los pandas ahora tienen un buen número de funciones de cadena "vectorizadas" que pueden realizar de manera sucinta estas operaciones de manipulación de cadenas.
Esta respuesta explorará algunas de estas funciones de cadena, sugerirá alternativas más rápidas y realizará una comparación de tiempos al final.
Especifique la subcadena / patrón para que coincida y la subcadena para reemplazarlo.
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
Si necesita convertir el resultado en un entero, puede usar Series.astype
,
df['result'] = df['result'].str.replace(r'\D', '').astype(int)
df.dtypes
time object
result int64
dtype: object
Si no desea modificar df
en el lugar, use DataFrame.assign
:
df2 = df.assign(result=df['result'].str.replace(r'\D', ''))
df
# Unchanged
Útil para extraer la (s) subcadena (s) que desea conservar.
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
, es necesario especificar al menos un grupo de captura. expand=False
devolverá una serie con los elementos capturados del primer grupo de captura.
La división funciona suponiendo que todas sus cadenas sigan esta estructura consistente.
# 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
No lo recomiende si está buscando una solución general.
Si está satisfecho con las str
soluciones sucintas y legibles basadas en accesores anteriores, puede detenerse aquí. Sin embargo, si está interesado en alternativas más rápidas y con mejor rendimiento, siga leyendo.
Optimización: Lista de comprensiones
En algunas circunstancias, las comprensiones de listas deben ser favorecidas sobre las funciones de cadena de pandas. La razón es que las funciones de cadena son inherentemente difíciles de vectorizar (en el verdadero sentido de la palabra), por lo que la mayoría de las funciones de cadena y expresión regular son solo envoltorios alrededor de bucles con más sobrecarga.
Mi artículo, ¿son realmente malos los bucles for pandas? ¿Cuándo debería importarme?, entra en mayor detalle.
La str.replace
opción puede reescribirse 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
El str.extract
ejemplo puede reescribirse usando una lista de comprensión 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
Si NaNs o no coincide son una posibilidad, deberá volver a escribir lo anterior para incluir alguna comprobación de errores. Hago esto usando una función.
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
También podemos reescribir las respuestas de @eumiro y @MonkeyButter usando listas de comprensión:
df['result'] = [x.lstrip('+-').rstrip('aAbBcC') for x in df['result']]
Y,
df['result'] = [x[1:-1] for x in df['result']]
Se aplican las mismas reglas para manejar NaN, etc.
Comparación de rendimiento
Gráficos generados usando perfplot . Listado completo de códigos, para su referencia. Las funciones relevantes se enumeran a continuación.
Algunas de estas comparaciones son injustas porque aprovechan la estructura de los datos de OP, pero toman de ella lo que quieran. Una cosa a tener en cuenta es que cada función de comprensión de la lista es más rápida o comparable que su variante de pandas equivalente.
Las funciones
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']])