Esta pregunta ya ha sido respondida, pero creo que sería bueno incluir en la mezcla algunos métodos útiles que no se discutieron anteriormente y comparar todos los métodos propuestos hasta ahora en términos de rendimiento.
A continuación, se muestran algunas soluciones útiles a este problema, en orden creciente de rendimiento.
Este es un str.format
enfoque de base simple .
df['baz'] = df.agg('{0[bar]} is {0[foo]}'.format, axis=1)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
También puede usar el formato de cadena f aquí:
df['baz'] = df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
char.array
concatenación basada en
Convierta las columnas para concatenar como chararrays
, luego súmelas.
a = np.char.array(df['bar'].values)
b = np.char.array(df['foo'].values)
df['baz'] = (a + b' is ' + b).astype(str)
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
No puedo exagerar lo subestimados que están las listas por comprensión en pandas.
df['baz'] = [str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])]
Alternativamente, usando str.join
para concat (también escalará mejor):
df['baz'] = [
' '.join([str(x), 'is', y]) for x, y in zip(df['bar'], df['foo'])]
df
foo bar baz
0 a 1 1 is a
1 b 2 2 is b
2 c 3 3 is c
Las listas por comprensión sobresalen en la manipulación de cadenas, porque las operaciones de cadenas son intrínsecamente difíciles de vectorizar, y la mayoría de las funciones "vectorizadas" de los pandas son básicamente envoltorios de bucles. He escrito mucho sobre este tema en For bucles con pandas: ¿cuándo debería importarme? . En general, si no tiene que preocuparse por la alineación del índice, use una lista de comprensión cuando se trate de operaciones de cadenas y expresiones regulares.
La lista de compilación anterior de forma predeterminada no maneja NaN. Sin embargo, siempre puede escribir una función que envuelva un intento, excepto si necesita manejarlo.
def try_concat(x, y):
try:
return str(x) + ' is ' + y
except (ValueError, TypeError):
return np.nan
df['baz'] = [try_concat(x, y) for x, y in zip(df['bar'], df['foo'])]
perfplot
Medidas de desempeño
Gráfico generado usando perfplot . Aquí está la lista completa de códigos .
Funciones
def brenbarn(df):
return df.assign(baz=df.bar.map(str) + " is " + df.foo)
def danielvelkov(df):
return df.assign(baz=df.apply(
lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1))
def chrimuelle(df):
return df.assign(
baz=df['bar'].astype(str).str.cat(df['foo'].values, sep=' is '))
def vladimiryashin(df):
return df.assign(baz=df.astype(str).apply(lambda x: ' is '.join(x), axis=1))
def erickfis(df):
return df.assign(
baz=df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1))
def cs1_format(df):
return df.assign(baz=df.agg('{0[bar]} is {0[foo]}'.format, axis=1))
def cs1_fstrings(df):
return df.assign(baz=df.agg(lambda x: f"{x['bar']} is {x['foo']}", axis=1))
def cs2(df):
a = np.char.array(df['bar'].values)
b = np.char.array(df['foo'].values)
return df.assign(baz=(a + b' is ' + b).astype(str))
def cs3(df):
return df.assign(
baz=[str(x) + ' is ' + y for x, y in zip(df['bar'], df['foo'])])
df['bar'].tolist()
ydf['foo'].tolist()
adentrocs3()
? Supongo que aumentaría ligeramente el tiempo "base", pero escalaría mejor.El problema en su código es que desea aplicar la operación en cada fila. Sin embargo, la forma en que lo ha escrito toma todas las columnas 'bar' y 'foo', las convierte en cadenas y le devuelve una cadena grande. Puedes escribirlo como:
df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1)
Es más larga que la otra respuesta pero es más genérica (se puede usar con valores que no son cadenas).
fuente
También podrías usar
df['bar'] = df['bar'].str.cat(df['foo'].values.astype(str), sep=' is ')
fuente
df['bar'] = df['bar'].astype(str).str.cat(df['foo'], sep=' is ')
.df.astype(str).apply(lambda x: ' is '.join(x), axis=1) 0 1 is a 1 2 is b 2 3 is c dtype: object
fuente
La respuesta de @DanielVelkov es la adecuada, PERO usar cadenas literales es más rápido:
# Daniel's %timeit df.apply(lambda x:'%s is %s' % (x['bar'],x['foo']),axis=1) ## 963 µs ± 157 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each) # String literals - python 3 %timeit df.apply(lambda x: f"{x['bar']} is {x['foo']}", axis=1) ## 849 µs ± 4.28 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
fuente
series.str.cat
es la forma más flexible de abordar este problema:por
df = pd.DataFrame({'foo':['a','b','c'], 'bar':[1, 2, 3]})
df.foo.str.cat(df.bar.astype(str), sep=' is ') >>> 0 a is 1 1 b is 2 2 c is 3 Name: foo, dtype: object
O
df.bar.astype(str).str.cat(df.foo, sep=' is ') >>> 0 1 is a 1 2 is b 2 3 is c Name: bar, dtype: object
Lo más importante (ya diferencia de
.join()
), esto le permite ignorar o reemplazarNull
valores con elna_rep
parámetro.fuente
.join()
me confunde