Pandas: ¿Cómo puedo usar la función apply () para una sola columna?

260

Tengo un marco de datos de pandas con dos columnas. Necesito cambiar los valores de la primera columna sin afectar la segunda y recuperar todo el marco de datos con solo los valores de la primera columna cambiados. ¿Cómo puedo hacer eso usando aplicar en pandas?

Amani
fuente
44
Publique algunos datos de muestra de entrada y la salida deseada.
Fabio Lamanna
Casi nunca deberías usarlo applyen una situación como esta. Operar en la columna directamente en su lugar.
Ted Petrou
Como dijo Ted Petrou, evite usar applytanto como sea posible. Si no está seguro de que necesita usarlo, probablemente no lo haga. Recomiendo echar un vistazo a ¿ Cuándo debería utilizar pandas apply () en mi código? .
cs95
La pregunta no está completamente clara: ¿se aplica una función a cada elemento de una columna o se aplica una función a la columna en su conjunto (por ejemplo: invertir la columna)?
Pierre ALBARÈDE

Respuestas:

339

Dado un marco de datos de muestra dfcomo:

a,b
1,2
2,3
3,4
4,5

lo que quieres es:

df['a'] = df['a'].apply(lambda x: x + 1)

eso devuelve:

   a  b
0  2  2
1  3  3
2  4  4
3  5  5
Fabio Lamanna
fuente
99
applynunca debe usarse en una situación como esta
Ted Petrou
55
@TedPetrou tiene toda la razón, fue solo un ejemplo de cómo aplicar una función general en una sola columna, como preguntó el OP.
Fabio Lamanna
14
Cuando intento hacer esto, aparece la siguiente advertencia: "Se está intentando establecer un valor en una copia de un segmento de un DataFrame. Intente usar .loc [row_indexer, col_indexer] = value en su lugar"
dagrun
24
Como curiosidad: ¿por qué no se debe aplicar en esa situación? ¿Cuál es la situación exactamente?
Tío Ben Ben
19
@UncleBenBen en general applyusa un bucle interno sobre las filas que es mucho más lento que las funciones vectorizadas, como por ejemplo df.a = df.a / 2(ver la respuesta de Mike Muller).
Fabio Lamanna
66

Para una sola columna mejor para usar map(), así:

df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9



df['a'] = df['a'].map(lambda a: a / 2.)

      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9
George Petrov
fuente
78
¿Por qué es map()mejor que apply()para una sola columna?
ChaimG
2
Esto fue muy útil. Lo usé para extraer nombres de archivos de rutas almacenadas en una columnadf['file_name'] = df['Path'].map(lambda a: os.path.basename(a))
mmann1123
46
map () es para Series (es decir, columnas individuales) y opera en una celda a la vez, mientras que apply () es para DataFrame y opera en una fila completa a la vez.
jpcgt
3
@jpcgt ¿Eso significa que el mapa es más rápido de lo que se aplica en este caso?
Viragos
@ChaimG veo que este sistema operativo explica bien: stackoverflow.com/a/19798528/571828
象 嘉 道
41

No necesitas una función en absoluto. Puede trabajar en una columna completa directamente.

Datos de ejemplo:

>>> df = pd.DataFrame({'a': [100, 1000], 'b': [200, 2000], 'c': [300, 3000]})
>>> df

      a     b     c
0   100   200   300
1  1000  2000  3000

La mitad de todos los valores en la columna a:

>>> df.a = df.a / 2
>>> df

     a     b     c
0   50   200   300
1  500  2000  3000
Mike Müller
fuente
¿Qué sucede si quiero dividir cada elemento en una columna por "/" y tomar la primera parte?
K47
12

Aunque las respuestas dadas son correctas, modifican el marco de datos inicial, lo que no siempre es deseable (y, dado que el OP solicitó ejemplos "usando apply", podría ser que quisieran una versión que devuelva un nuevo marco de datos, como lo applyhace).

Esto es posible usando assign: es válido para assignlas columnas existentes, como dice la documentación (el énfasis es mío):

Asigne nuevas columnas a un DataFrame.

Devuelve un nuevo objeto con todas las columnas originales además de las nuevas. Las columnas existentes que se reasignan se sobrescribirán .

En breve:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame([{'a': 15, 'b': 15, 'c': 5}, {'a': 20, 'b': 10, 'c': 7}, {'a': 25, 'b': 30, 'c': 9}])

In [3]: df.assign(a=lambda df: df.a / 2)
Out[3]: 
      a   b  c
0   7.5  15  5
1  10.0  10  7
2  12.5  30  9

In [4]: df
Out[4]: 
    a   b  c
0  15  15  5
1  20  10  7
2  25  30  9

Tenga en cuenta que la función pasará todo el marco de datos, no solo la columna que desea modificar, por lo que deberá asegurarse de seleccionar la columna correcta en su lambda.

Thibaut Dubernet
fuente
9

Si está realmente preocupado por la velocidad de ejecución de su función de aplicación y tiene un gran conjunto de datos para trabajar, puede usar más rápido para hacer una ejecución más rápida, aquí hay un ejemplo para un marco de datos más rápido en pandas:

import pandas as pd
import swifter

def fnc(m):
    return m*3+4

df = pd.DataFrame({"m": [1,2,3,4,5,6], "c": [1,1,1,1,1,1], "x":[5,3,6,2,6,1]})

# apply a self created function to a single column in pandas
df["y"] = df.m.swifter.apply(fnc)

Esto permitirá que todos sus núcleos de CPU calculen el resultado, por lo tanto, será mucho más rápido que las funciones de aplicación normales. Intenta avisarme si te resulta útil.

durjoy
fuente
1

Permítanme probar un cálculo complejo usando datetime y considerando nulos o espacios vacíos. Estoy reduciendo 30 años en una columna de fecha y hora y utilizando el applymétodo lambday la conversión del formato de fecha y hora. Line if x != '' else xse encargará de todos los espacios vacíos o nulos en consecuencia.

df['Date'] = df['Date'].fillna('')
df['Date'] = df['Date'].apply(lambda x : ((datetime.datetime.strptime(str(x), '%m/%d/%Y') - datetime.timedelta(days=30*365)).strftime('%Y%m%d')) if x != '' else x)
Harry_pb
fuente