agregue un prefijo de cadena a cada valor en una columna de cadena usando Pandas

Me gustaría agregar una cadena al inicio de cada valor en una columna de un dataframe de pandas (con elegancia). Ya me di cuenta de cómo hacer esto y actualmente estoy usando:

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

Parece una cosa muy poco elegante que hacer. ¿Conoces alguna otra forma (que quizás también agregue el carácter a las filas donde esa columna es 0 o NaN)?

En caso de que esto aún no esté claro, me gustaría volver:

  col 1 a 2 0 

dentro:

  col 1 stra 2 str0 

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

Ejemplo:

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

Como alternativa, también puede usar una apply combinada con un format que encuentro un poco más legible si, por ejemplo, también desea agregar un sufijo o manipular el elemento en sí:

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

que también produce el resultado deseado:

  col 0 stra 1 str0 

Si está utilizando Python 3.6+, también puede usar f-strings:

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

dando la misma salida.

La versión de f-string es casi tan rápida como la solución 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 , sin embargo, es mucho más 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) 

Aquí hay algunas soluciones “elegantes” para usted. Puede averiguar qué solución funciona mejor según sus requisitos de datos, rendimiento y legibilidad. Se han proporcionado soluciones que funcionan para columnas de cadena pura, así como para manejar el caso general de tipos mixtos y NaN.

Concatenación de cuerdas vectorizadas

 df = pd.DataFrame({'col': ['a', '5', 'eee']}) df2 = pd.DataFrame({'col': ['a', 5, 'eee', np.nan]}) df col 0 a 1 5 2 eee df2 col 0 a 1 5 2 eee 3 NaN 

Si su (s) columna (s) son completamente cadenas (es decir, sin NaN o tipos mixtos, numéricos, etc.), la solución es simple:

 'str' + df col 0 stra 1 str5 2 streee 

Para concat ‘str’ a sólo la columna específica,

 'str' + df['col'] 0 stra 1 str5 2 streee Name: col, dtype: object 

El resultado se puede volver a asignar, ya sea en el lugar,

 df['col'] = 'str' + df['col'] 

O bien, con DataFrame.assign :

 df.assign(col='str' + df['col']) 

Si necesita manejar datos faltantes o tipos de datos mixtos (es decir, como en df2 ), puede usar Series.isna para generar una máscara para pasar a Series.where .

 u = df2['col'].where(df2['col'].isna(), df2['col'].astype(str)) u 0 a 1 5 2 eee 3 NaN Name: col, dtype: object 

 'str' + u 0 stra 1 str5 2 streee 3 NaN Name: col, dtype: object 

Series.radd

 df['col'].radd('str') 0 stra 1 str5 2 streee Name: col, dtype: object 

Para dtypes / NaNs mixtos,

 u = df2['col'].where(df2['col'].isna(), df2['col'].astype(str)) u.radd('str') 0 stra 1 str5 2 streee 3 NaN Name: col, dtype: object 

numpy.char.add / numpy.core.defchararray.add

 np.char.add('str', df.col) # array(['stra', 'str5', 'streee'], dtype=' 

Para tipos de dato mixtos y NaN, siga un procedimiento a uno que se muestra anteriormente con add :

 u = (pd.Series(np.char.add('str', df2['col'].values.astype(str))) .where(df2['col'].notna())) df2.assign(col=u) col 0 stra 1 str5 2 streee 3 NaN 

Series.map y str.format

 df['col'].map('str{0}'.format) col 0 stra 1 str5 2 streee 

Y, para el caso general, uso.

 df2['col'].map('str{0}'.format).where(df2['col'].notna()) 0 stra 1 str5 2 streee 3 NaN Name: col, dtype: object 


Lista de Comprensiones

Voy a arriesgarme y diré que las comprensiones de listas son probablemente las soluciones más rápidas aquí. El problema es que las operaciones de cadena son intrínsecamente más difíciles de vectorizar, por lo que la mayoría de las funciones "vectorizadas" de los pandas son básicamente envoltorios para los bucles. Si no necesita la sobrecarga, puede eliminarla escribiendo a mano sus propios bucles. He escrito mucho sobre esto en For loops with pandas - ¿Cuándo debería importarme? .

 ['str' + x for x in df['col']] # ['stra', 'str5', 'streee'] df.assign(col=['str' + x for x in df['col']]) col 0 stra 1 str5 2 streee 

O, usando str.format :

 df.assign(col=[f'str{x}' for x in df['col']]) col 0 stra 1 str5 2 streee 

Estas soluciones también tienen un equivalente general:

 df2.assign(col=[ 'str' + str(x) if pd.notna(x) else np.nan for x in df2['col']]) col 0 stra 1 str5 2 streee 3 NaN 

 df2.assign(col=[f'str{x}' if pd.notna(x) else np.nan for x in df2['col']]) col 0 stra 1 str5 2 streee 3 NaN 

Si carga su archivo de tabla con dtype=str
o convierta el tipo de columna a la cadena df['a'] = df['a'].astype(str)
entonces usted puede utilizar este enfoque:

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

Este enfoque permite pre-añadir, añadir y subgrupo de df .
Funciona en Pandas v0.23.4, v0.24.1. No sé acerca de las versiones anteriores.