Crear una nueva columna basada en la condición if-elif-else

100

Tengo un DataFrame df:

    A    B
a   2    2 
b   3    1
c   1    3

Quiero crear una nueva columna según los siguientes criterios:

si fila A == B: 0

si filaA > B: 1

si fila A < B: -1

así que dada la tabla anterior, debería ser:

    A    B    C
a   2    2    0
b   3    1    1
c   1    3   -1 

Para los if elsecasos típicos que hago np.where(df.A > df.B, 1, -1), ¿los pandas proporcionan una sintaxis especial para resolver mi problema con un paso (sin la necesidad de crear 3 columnas nuevas y luego combinar el resultado)?

loco
fuente
Simplemente podría definir una función y pasar esto applyy establecer axis=1funcionaría, no estoy seguro de poder pensar en una operación que le dé lo que desea
EdChum
Su solución implica crear 3 columnas y combinarlas en 1 columna, ¿o tiene algo diferente en mente?
Nutship
Sigues diciendo "creando 3 columnas", pero no estoy seguro de a qué te refieres.
DSM
1
@DSM ha respondido a esta pregunta, pero me refiero a algo como df['C']=df.apply(myFunc(row), axis=1)donde myFunc hace lo que quieres, esto no implica la creación de '3 columnas'
EdChum
1
Posible duplicado de la creación condicional
Georgy

Respuestas:

146

Para formalizar algunos de los enfoques expuestos anteriormente:

Cree una función que opere en las filas de su marco de datos así:

def f(row):
    if row['A'] == row['B']:
        val = 0
    elif row['A'] > row['B']:
        val = 1
    else:
        val = -1
    return val

Luego, aplíquelo a su marco de datos pasando la axis=1opción:

In [1]: df['C'] = df.apply(f, axis=1)

In [2]: df
Out[2]:
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1

Por supuesto, esto no está vectorizado, por lo que el rendimiento puede no ser tan bueno cuando se escala a una gran cantidad de registros. Aún así, creo que es mucho más legible. Especialmente viniendo de un fondo SAS.

Editar

Aquí está la versión vectorizada

df['C'] = np.where(
    df['A'] == df['B'], 0, np.where(
    df['A'] >  df['B'], 1, -1)) 
Zelazny7
fuente
1
Gracias, estoy comenzando con pandas y esto fue muy útil +1
nutship
4
¿Qué pasa si quiero pasar otro parámetro junto con la fila en la función? Si lo hago, dice fila no definida ..
prashanth manohar
3
Tienes que usar el argsparámetro de la .applyfunción: pandas.pydata.org/pandas-docs/stable/generated/…
Zelazny7
1
Soy un antiguo usuario de SAS que está aprendiendo Python, ¡y definitivamente hay una curva de aprendizaje! :-) Por ejemplo, el código anterior podría escribirse en SAS como: data df; set df; if A=B then C=0; else if A>B then C=1; else C=-1; run;Muy elegante y simple.
RobertF
1
Una respuesta bien definida
Sahil Nagpal
51
df.loc[df['A'] == df['B'], 'C'] = 0
df.loc[df['A'] > df['B'], 'C'] = 1
df.loc[df['A'] < df['B'], 'C'] = -1

Fácil de resolver mediante indexación. La primera línea de código se lee así, si la columna Aes igual a la columna B, cree y establezca la columna Cigual a 0.

Brian
fuente
17

Para esta relación en particular, puede utilizar np.sign:

>>> df["C"] = np.sign(df.A - df.B)
>>> df
   A  B  C
a  2  2  0
b  3  1  1
c  1  3 -1
DSM
fuente
6

ingrese la descripción de la imagen aquí

Digamos que el anterior es su marco de datos original y desea agregar una nueva columna 'antigua'

Si la edad es mayor de 50 años, la consideramos mayor = sí en caso contrario Falso

paso 1: obtener los índices de las filas cuya antigüedad sea mayor a 50

row_indexes=df[df['age']>=50].index

paso 2: usando .loc podemos asignar un nuevo valor a la columna

df.loc[row_indexes,'elderly']="yes"

lo mismo para la edad menor de 50

row_indexes=df[df['age']<50].index

df[row_indexes,'elderly']="no"

Ravi G
fuente