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.

¿Existe una manera más rápida de combinar y multiplicar valores de un Dataframe basándose en los valores de índice?

Tengo dos marcos de datos:
uno (multiíndice) de tamaño (1113, 7897) que contiene valores para diferentes países y sectores en columnas y diferentes IDs en la fila, ejemplo:

Marco de datos F_Frame:

     AT              BE            ...
     Food   Energy   Food   Energy ...
ID1  
ID2
...

En otro marco de datos (CC_LO) tengo valores de factores con los correspondientes países e IDs que me gustaría emparejar con el marco de datos anterior (F_frame), de modo que multiplique los valores en F_frame con los valores de factores en CC_LO si coinciden por país e ID. Si no coinciden, coloco un cero.

El código que tengo hasta ahora parece funcionar, pero se ejecuta muy lentamente. ¿Existe una forma más inteligente de emparejar las tablas basándose en los nombres de índice/cabecera?
(El código recorre en bucle 49 países y multiplica por el mismo factor para cada 163 sectores dentro del país)

LO_impacts = pd.DataFrame(np.zeros((1113,7987)))

for i in range(0, len(F_frame)):
for j in range(0, 49):
for k in range(0, len(CF_LO)):
if (F_frame.index.get_level_values(1)[i] == CF_LO.iloc[k,1] and
F_frame.columns.get_level_values(0)[j163] == CF_LO.iloc[k,2]):
LO_impacts.iloc[i,(j
163):((j+1)163)] = F_frame.iloc[i,(j163):((j+1)163)] * CF_LO.iloc[k,4]
else:
LO_impacts.iloc[i,(j
163):((j+1)*163)] == 0

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Solución propuesta

    Existen algunas mejoras que se pueden realizar a tu código actual para que se ejecute más rápido:

    • Utiliza operaciones vectorizadas en lugar de bucles siempre que sea posible.
    • Evita llamar a get_level_values() e iloc() dentro de tus bucles, ya que estas operaciones pueden ser costosas.
    • En lugar de verificar cada fila de CC_LO con cada fila de F_frame, combina ambos dataframes utilizando las columnas comunes ID y Country, y luego realiza los cálculos en el dataframe fusionado.

    Aquí tienes un ejemplo de cómo implementar estas mejoras:

    merged_df = F_frame.reset_index().merge(
        CC_LO.rename(columns={'Country': 'Country_LO', 'ID': 'ID_LO'}),
        on=['Country', 'ID'],
        how='left'
    )
    
    # Crea una máscara booleana para identificar las filas donde la fusión fue exitosa
    mask = ~pd.isna(merged_df['Factor'])
    
    # Multiplica los valores en F_frame por los valores de factor en CC_LO donde hay coincidencia, o cero en caso contrario
    LO_impacts = merged_df.iloc[:, 2:] * merged_df['Factor'].fillna(0).to_numpy().reshape(-1, 1)
    LO_impacts[~mask] = 0
    

    Este código primero fusiona los dos dataframes utilizando las columnas comunes Country e ID. El método reset_index() se utiliza para convertir el índice ID de F_frame en una columna regular antes de fusionar. El dataframe resultante merged_df tiene la misma cantidad de filas que F_frame, pero también incluye la columna Factor de CC_LO donde hay coincidencia.

    A continuación, se crea una máscara booleana para identificar qué filas tienen una coincidencia (es decir, Factor no es NaN). El método fill_na(0) se utiliza para reemplazar los valores NaN por ceros y luego se llama al método to_numpy() para convertir la serie resultante en un arreglo numpy unidimensional, que puede ser transmitido a lo largo de las columnas de F_frame.

    Finalmente, se calcula la multiplicación elemento por elemento entre merged_df.iloc[:, 2:] (es decir, todas las columnas excepto ID y Country) y el arreglo numpy de valores de factor, y se asignan valores cero al dataframe resultante LO_impacts para las filas donde no hay coincidencia (es decir, mask es Falso).

    Este código debería ser mucho más rápido que tu implementación original, especialmente para dataframes grandes.

Comments are closed.