es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Numpy: Condiciones anidadas en dos columnas de Pandas

Introducción: Tengo un dataframe de pandas con las columnas df = [openDate, high, low, open, close, volume, is_eligible]. En este dataframe:

  • openDate es de tipo fecha y hora,
  • high, low, open, close, volume son de tipo int64,
  • is_eligible es de tipo booleano.

Declaración del problema: Quiero añadir una columna más, end_date, que será calculada de acuerdo a lo siguiente:

Si is_eligible es true, entonces su end_time será la openDate más cercana cuyo valor de high es mayor o igual al de is_eligible true.

Ejemplo: Supongamos que la fila número 3 tiene is_eligible == true, high=20, low=10, open=15, close=12, entonces tenemos que encontrar la siguiente fila inmediata que tenga un valor de high mayor o igual a 20.

Mi enfoque: He intentado la siguiente solución utilizando un enfoque vectorizado pero no está funcionando.


temp_var = df[["openDate","is_eligible","high"]].copy()
df["end_date"] = np.where(
temp_var['is_eligible'] == True,
np.where(
df['high']> temp_var["high"],
df["openDate"],
datetime.now()
),
datetime.now()
)

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Solución

    Según el enunciado del problema, necesitamos agregar una nueva columna end_date que se calculará en función del valor high y el openDate de las filas.

    Aquí tienes una solución de trabajo para lograr esto:

    import pandas as pd
    import numpy as np
    
    # crear datos de ejemplo
    df = pd.DataFrame({
        'openDate': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05'],
        'high': [10, 20, 30, 40, 50],
        'low': [5, 10, 20, 30, 40],
        'open': [7, 18, 28, 38, 48],
        'close': [8, 17, 27, 37, 47],
        'volume': [100, 200, 300, 400, 500],
        'is_eligible': [False, False, True, False, False]
    })
    
    # convertir openDate a tipo datetime
    df['openDate'] = pd.to_datetime(df['openDate'])
    
    # crear una copia del dataframe con solo las columnas relevantes
    temp_df = df[['openDate', 'high', 'is_eligible']].copy()
    
    # crear una nueva columna end_date y establecerla en valores nulos
    df['end_date'] = pd.NaT
    
    # identificar las filas con is_eligible como verdadero
    eligible_rows = df[df['is_eligible']].index
    
    # recorrer las filas elegibles y encontrar la siguiente fila elegible
    for i in eligible_rows:
        try:
            next_row_index = temp_df[temp_df['high'] >= df.loc[i, 'high']].iloc[1].name
            df.at[i, 'end_date'] = df.loc[next_row_index, 'openDate']
        except IndexError:
            pass
    
    print(df)
    

    Explicación

    1. Comenzamos creando un dataframe de ejemplo con los atributos dados.
    2. Luego, convertimos el tipo de datos de la columna openDate a datetime.
    3. A continuación, creamos un nuevo dataframe solo con las columnas openDate, high, is_eligible.
    4. Luego, creamos una nueva columna llamada end_date en el dataframe original y la establecemos en valores nulos.
    5. Identificamos las filas en el dataframe original con is_eligible como verdadero y almacenamos sus índices en una lista.
    6. Iteramos sobre cada una de estas filas elegibles y usando un bloque try-except, encontramos la siguiente fila elegible basada en el valor high. Luego, actualizamos la columna end_date del dataframe original para esa fila con el openDate de la siguiente fila elegible. Si no hay una próxima fila elegible, simplemente omitimos esa fila.
    7. Finalmente, imprimimos el dataframe actualizado con la columna end_date agregada.

    Conclusión

    Esta solución debería resolver el problema original agregando una nueva columna end_date en el dataframe basada en el valor high y el openDate de las filas. Esto se logra iterando sobre las filas elegibles y encontrando la siguiente fila elegible usando un bloque try-except.

Comments are closed.