python - Cortar la columna Dataframe en función de la longitud de las cadenas
pandas (6)
Me gustaría eliminar los primeros 3 caracteres de las cadenas en una columna de Dataframe donde la longitud de la cadena es> 4
Si no, deberían seguir siendo los mismos.
P.ej
bloomberg_ticker_y
AIM9
DJEM9 # (should be M9)
FAM9
IXPM9 # (should be M9)
Puedo filtrar las cuerdas por longitud:
merged[''bloomberg_ticker_y''].str.len() > 4
y cortar las cuerdas:
merged[''bloomberg_ticker_y''].str[-2:]
Pero no estoy seguro de cómo poner esto junto y aplicarlo a mi marco de datos
Cualquier ayuda sería apreciada.
Otro enfoque es usar expresiones regulares:
df["bloomberg_ticker_y"].str.replace(r".{3,}(?=.{2}$)", "")
#0 AIM9
#1 M9
#2 FAM9
#3 M9
El patrón significa:
-
.{3,}
: combina 3 o más caracteres -
(?=.{2}$)
: anticipación positiva de exactamente 2 caracteres seguidos del final de la cadena.
Puede usar
numpy.where
para aplicar una condición para seleccionar segmentos en función de la longitud de la cadena.
np.where(df[''bloomberg_ticker_y''].str.len() > 4,
df[''bloomberg_ticker_y''].str[3:],
df[''bloomberg_ticker_y''])
# array([''AIM9'', ''M9'', ''FAM9'', ''M9''], dtype=object)
df[''bloomberg_ticker_sliced''] = (
np.where(df[''bloomberg_ticker_y''].str.len() > 4,
df[''bloomberg_ticker_y''].str[3:],
df[''bloomberg_ticker_y'']))
df
bloomberg_ticker_y bloomberg_ticker_sliced
0 AIM9 AIM9
1 DJEM9 M9
2 FAM9 FAM9
3 IXPM9 M9
Si te apetece una solución basada en un
map
vectorizado, es
df[''bloomberg_ticker_y''].map(lambda x: x[3:] if len(x) > 4 else x)
0 AIM9
1 M9
2 FAM9
3 M9
Name: bloomberg_ticker_y, dtype: object
Puede utilizar una lista de comprensión:
df = pd.DataFrame({''bloomberg_ticker_y'' : [''AIM9'', ''DJEM9'', ''FAM9'', ''IXPM9'']})
df[''new''] = [x[-2:] if len(x)>4 else x for x in df[''bloomberg_ticker_y'']]
Salida:
bloomberg_ticker_y new
0 AIM9 AIM9
1 DJEM9 M9
2 FAM9 FAM9
3 IXPM9 M9
Puedes usar
DataFrame.mask
:
df[''bloomberg_ticker_y''] = (df.bloomberg_ticker_y.mask(
df.bloomberg_ticker_y.str.len().gt(4),
other=df.bloomberg_ticker_y.str[-2:]))
bloomberg_ticker_y
0 AIM9
1 M9
2 FAM9
3 M9
También puede utilizar DataFrame.apply :
import pandas as pd
df = pd.DataFrame({''bloomberg_ticker_y'' : [''AIM9'', ''DJEM9'', ''FAM9'', ''IXPM9'']})
df[''bloomberg_ticker_y''] = df.apply(lambda x: (x[''bloomberg_ticker_y''][3:] if len(x[''bloomberg_ticker_y'']) > 4 else x[''bloomberg_ticker_y'']) , axis=1)
Salida:
bloomberg_ticker_y
0 AIM9
1 M9
2 FAM9
3 M9
Vio una gran variedad de respuestas, así que decidí compararlas en términos de velocidad:
# Create big size test dataframe
df = pd.DataFrame({''bloomberg_ticker_y'' : [''AIM9'', ''DJEM9'', ''FAM9'', ''IXPM9'']})
df = pd.concat([df]*100000)
df.shape
#Out
(400000, 1)
CS95 # 1
np.where
%%timeit
np.where(df[''bloomberg_ticker_y''].str.len() > 4,
df[''bloomberg_ticker_y''].str[3:],
df[''bloomberg_ticker_y''])
Resultado:
163 ms ± 12.8 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
CS95 # 2 solución basada en
map
vectorizados
%%timeit
df[''bloomberg_ticker_y''].map(lambda x: x[3:] if len(x) > 4 else x)
Resultado:
86 ms ± 7.31 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
Yatu
DataFrame.mask
%%timeit
df.bloomberg_ticker_y.mask(df.bloomberg_ticker_y.str.len().gt(4),
other=df.bloomberg_ticker_y.str[-2:])
Resultado:
187 ms ± 18.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Vlemaistre
list comprehension
%%timeit
[x[-2:] if len(x)>4 else x for x in df[''bloomberg_ticker_y'']]
Resultado:
84.8 ms ± 4.85 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
pault
str.replace
con
regex
%%timeit
df["bloomberg_ticker_y"].str.replace(r".{3,}(?=.{2}$)", "")
Resultado:
324 ms ± 17.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Cobra
DataFrame.apply
%%timeit
df.apply(lambda x: (x[''bloomberg_ticker_y''][3:] if len(x[''bloomberg_ticker_y'']) > 4 else x[''bloomberg_ticker_y'']) , axis=1)
Resultado:
6.83 s ± 387 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
Conclusión
-
El método más rápido es la
list comprehension
seguida de cerca por una solución basada enmap
vectorizados. -
El método más lento es
DataFrame.apply
con diferencia (como se esperaba) seguido destr.replace
conregex