Tengo un escenario en el que mi marco de datos de pandas tiene una condición almacenada como una cadena que necesito ejecutar y almacenar el resultado como una columna diferente. El siguiente ejemplo le ayudará a comprender mejor;

DataFrame existente:

ID   Val    Cond
1     5      >10
1     15     >10

Marco de datos esperado:

ID   Val    Cond    Result
1     5      >10     False
1     15     >10     True

Como ve, necesito concatenar Val y Cond y hacer una evaluación a nivel de fila.

2
Bhavesh Jain 7 dic. 2020 a las 21:44

2 respuestas

La mejor respuesta

Si sus condiciones se forman a partir de operaciones básicas (& lt ;, & lt; =, ==,! =, & Gt ;, & gt; =), entonces podemos hacer esto de manera más eficiente usando getattr. Usamos .str.extract para analizar la condición y separar la comparación y el valor. Usando nuestro diccionario, asignamos la comparación a los atributos de la serie que luego podemos llamar para cada comparación única por separado en un grupo simple.

import pandas as pd

print(df)
   ID  Val  Cond
0   1    5   >10
1   1   15   >10
2   1   20  ==20
3   1   25  <=25
4   1   26  <=25

# All operations we might have. 
d = {'>': 'gt', '<': 'lt', '>=': 'ge', '<=': 'le', '==': 'eq', '!=': 'ne'}

# Create a DataFrame with the LHS value, comparator, RHS value
tmp = pd.concat([df['Val'], 
                 df['Cond'].str.extract('(.*?)(\d+)').rename(columns={0: 'cond', 1: 'comp'})], 
                axis=1)
tmp[['Val', 'comp']] = tmp[['Val', 'comp']].apply(pd.to_numeric)
#   Val cond  comp
#0    5    >    10
#1   15    >    10
#2   20   ==    20
#3   25   <=    25
#4   26   <=    25
#5   10   !=    10

# Aligns on row Index
df['Result'] = pd.concat([getattr(gp['Val'], d[idx])(gp['comp']) 
                          for idx, gp in tmp.groupby('cond')])
#   ID  Val  Cond  Result
#0   1    5   >10   False
#1   1   15   >10    True
#2   1   20  ==20    True
#3   1   25  <=25    True
#4   1   26  <=25   False
#5   1   10  !=10   False

Simple, pero ineficiente y peligroso, es eval en cada fila, creando una cadena de su condición. eval es peligroso ya que puede evaluar cualquier código, por lo tanto, utilícelo solo si realmente confía y conoce los datos.

df['Result'] = df.apply(lambda x: eval(str(x.Val) + x.Cond), axis=1)
#    ID  Val  Cond  Result
#0   1    5   >10   False
#1   1   15   >10    True
#2   1   20  ==20    True
#3   1   25  <=25    True
#4   1   26  <=25   False
#5   1   10  !=10   False
1
ALollz 7 dic. 2020 a las 19:15

También puedes hacer algo como esto:

df["Result"] = [eval(x + y) for x, y in zip(df["Val"].astype(str), df["Cond"]]

Haga la columna "Resultado" concatenando las cadenas df ["Val"] y df ["Cond"], luego aplicando eval a eso.

0
Daniel 7 dic. 2020 a las 18:53