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

119

Me gustaría agregar una cadena al inicio de cada valor en dicha columna de un marco de datos de pandas (elegantemente). Ya descubrí cómo hacer esto y actualmente estoy usando:

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

Esto parece una cosa increíblemente poco elegante, ¿conoce alguna otra forma (que tal vez 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 convertir:

    col 
1     a
2     0

dentro:

       col 
1     stra
2     str0
TheChymera
fuente
¿Qué preguntas exactamente? por favor escriba una explicación sobre lo que hace su código / desearía que hiciera
Ryan Saxe
1
Pensé que lo que hace el código de ejemplo era muy claro para el usuario promedio de pandas. He agregado ejemplos de casos de uso para su conveniencia.
TheChymera
3
Su descripción está algo reñida con su código. ¿Qué pasa con el != Falsenegocio? ¿Quieres agregar stra todos los valores o solo a algunos?
BrenBarn
a cada valor, como se muestra en mis marcos de datos de ejemplo.
TheChymera
1
tu ejemplo aún no está claro, ¿quieres algo como df['col'] = 'str' + df['col'].astype(str)?
Roman Pekar

Respuestas:

223
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
Roman Pekar
fuente
1
gracias. si es de interés, los índices de marcos de datos también admiten dichas manipulaciones de cadenas.
tagoma
2
¿Cómo hago esto si se deben cumplir las condiciones antes de la concatenación?
acecabana
1
@tagoma, después de 4 años, sí: también es compatible con los índices de marcos de datos. Puede crear una nueva columna y agregarla al valor del índice como: df ['col'] = 'str' + df.index.astype (str)
MEdwin
"astype (str)" podría arruinar la codificación si al final está intentando guardar en un archivo.
Raein Hashemi
2
Cuando intento esto, así como cualquier otro enfoque, obtengo un SettingWithCopyWarning. ¿Hay alguna forma de evitarlo?
Madan Ivan
13

Como alternativa, también puede usar un applycombinado con format(o mejor con f-strings) que encuentro un poco más legible si uno, por ejemplo, también quiere 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á usando Python 3.6+, también puede usar f-strings:

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

dando el mismo resultado.

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)

El uso format, sin embargo, es de hecho 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)
Cleb
fuente
mismo resultado, pero mucho más lento ;-)
Philipp_Kats
1
@Philipp_Kats: Agregué algunos horarios, ¡gracias por la sugerencia! Parece que las cuerdas de fa son casi tan rápidas; formatde hecho funciona peor. ¿Cómo te comparaste?
Cleb
¡Oh bien! en mi opinión, .applyes siempre tan rápido o más lento que las operaciones vectorizadas "directas"; incluso si no son más lentos, prefiero evitarlos siempre que sea posible.
Philipp_Kats
@Philipp_Kats: Estoy de acuerdo, sin embargo, en este caso particular lo encuentro más legible cuando también agrego un sufijo, hago algo consigo xmismo, etc., pero eso es solo una cuestión de gustos ... :)
Cleb
4

Puede usar pandas.Series.map:

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

Aplicará la palabra "str" ​​antes de todos sus valores.

Boxtell
fuente
3

Si carga su archivo de tabla con dtype=str
o convierte el tipo de columna a cadena df['a'] = df['a'].astype(str)
, puede usar dicho enfoque:

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

Este enfoque permite anteponer, agregar y subconjuntar cadenas de df.
Funciona en Pandas v0.23.4, v0.24.1. No conozco versiones anteriores.

Vasyl Vaskivskyi
fuente
0

Otra solución con .loc:

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

Esto no es tan rápido como las soluciones anteriores (> 1 ms por ciclo más lento) pero puede ser útil en caso de que necesite un cambio condicional, como:

mask = (df['col'] == 0)
df.loc[mask, 'col'] = 'string' + df['col'].astype(str)
Lukas
fuente
¿Por qué .indexen df[mask].index?
AMC
@AMC porque para .loc necesitas índices del marco de datos. Significa: df [máscara] devuelve un marco de datos que coincide con la condición y df [máscara] .index devuelve índices del marco de datos. Pero es cierto que también puede hacer lo mismo con df.loc [(df ['col'] == 'a'), 'col'] o df.loc [mask, 'col'].
Lukas
1
porque para .loc necesitas índices del marco de datos. Si df.loc[mask]funciona, y lo hace, entonces .indexes superfluo, ¿verdad?
AMC
@AMC exactamente :). Edité la solución. Gracias.
Lukas