Consideraciones de diseño de pandas para marcos de datos multiindexados

El propósito de esta pregunta es explorar más a fondo los marcos de datos MultiIndex y hacer preguntas sobre el mejor enfoque para diversas tareas.

Crear el dataframe

import pandas as pd df = pd.DataFrame({'index_date' : ['12/07/2016','12/07/2016','12/07/2016','12/07/2016','12/07/2016'], 'portfolio' : ['A','B','C','D','E'], 'reporting_ccy' : ['GBP','GBP','GBP','GBP','GBP'], 'portfolio_ccy' : ['JPY','USD','USD','EUR','EUR'], 'amount' : [100,200,300,400,500], 'injection' : [1,2,3,4,5], 'to_usd' : [1.3167,1.3167,1.3167,1.3167,1.3167], 'to_ccy' : [0.009564,1,1,1.1093,1.1093], 'm5' : [2,4,6,8,10], 'm6' : [1,3,5,7,9]}); 

Gire el dataframe

 df_pivot = df.pivot_table(index='index_date',columns=['portfolio','portfolio_ccy','reporting_ccy']).swaplevel(0, 1, axis=1).sortlevel(axis=1) 

Renombrar las columnas

 df_pivot.columns.names = ['portfolio','measures', 'portfolio_ccy', 'reporting_ccy'] 

Esto produce una representación pivotada de los datos tal que:

  1. Una cartera puede tener 1 o muchas medidas.
  2. muestra la moneda por defecto de la cartera
  3. muestra la cartera de moneda de presentación de informes
  4. una medida puede tener 1 o muchas divisas de reporte.

I términos de 4. ¿Cuál es el mejor enfoque para la implementación dado que tenemos los xRates para las monedas?

De tal manera que creamos un dataframe como el que se deriva aquí:

Crear dataframe

 df1 = pd.DataFrame({'index_date' : ['12/07/2016','12/07/2016','12/07/2016','12/07/2016','12/07/2016'], 'portfolio' : ['A','B','C','D','E'], 'reporting_ccy' : ['JPY','USD','USD','EUR','EUR'], 'portfolio_ccy' : ['JPY','USD','USD','EUR','EUR'], 'amount' : [13767.2522, 263.34, 395.01, 474.785901, 593.4823763], 'injection' : [1,2,3,4,5], 'to_usd' : [0.009564, 1, 1, 1.1093, 1.1093], 'to_ccy' : [1.3167, 1.3167, 1.3167, 1.3167, 1.3167], 'm5' : [2,4,6,8,10], 'm6' : [1,3,5,7,9]}); 

Concatenar y pivotar los marcos de datos

 df_concat = pd.concat([df,df1]) df_pivot1 = df_concat.pivot_table(index='index_date',columns=['portfolio','portfolio_ccy','reporting_ccy']).swaplevel(0, 1, axis=1).sortlevel(axis=1) df_pivot1.columns.names = ['portfolio','measures', 'portfolio_ccy', 'reporting_ccy'] 

Esto ahora muestra 1 medida que tiene muchas monedas.

 df_pivot1.xs(('amount', 'A'), level=('measures','portfolio'), drop_level=False, axis=1) 

Pregunta

¿Hay alguna forma mejor, como agregar datos directamente a un dataframe con múltiples índices en el nivel 3 df_pivot1.columns.get_level_values(3).unique() ?

Me gustaría poder recorrer cada nivel y agregar nuevas medidas derivadas de otras medidas utilizando df.assign() u otros métodos.

El caso de uso aquí es agregar otras monedas a las medidas cuando corresponda. La concatenación y el re-pivote como arriba no parecen óptimos.

Puede agregar df1 fila por fila en df_pivot en lugar de reconstruir el pivote con ambos cuadros concat juntos.

Anexar al final del DataFrame sería menos costoso en memoria que concatenar y reconstruir los pivotes desde cero cada vez que se reciben nuevos datos.

 import pandas as pd df = pd.DataFrame({'index_date' : ['12/07/2016','12/07/2016','12/07/2016','12/07/2016','12/07/2016'], 'portfolio' : ['A','B','C','D','E'], 'reporting_ccy' : ['GBP','GBP','GBP','GBP','GBP'], 'portfolio_ccy' : ['JPY','USD','USD','EUR','EUR'], 'amount' : [100,200,300,400,500], 'injection' : [1,2,3,4,5], 'to_usd' : [1.3167,1.3167,1.3167,1.3167,1.3167], 'to_ccy' : [0.009564,1,1,1.1093,1.1093], 'm5' : [2,4,6,8,10], 'm6' : [1,3,5,7,9]}); # %% df_pivot = df.pivot_table(index='index_date',columns=['portfolio','portfolio_ccy','reporting_ccy']).swaplevel(0, 1, axis=1).sortlevel(axis=1) df1 = pd.DataFrame({'index_date' : ['12/07/2016','12/07/2016','12/07/2016','12/07/2016','12/07/2016'], 'portfolio' : ['A','B','C','D','E'], 'reporting_ccy' : ['JPY','USD','USD','EUR','EUR'], 'portfolio_ccy' : ['JPY','USD','USD','EUR','EUR'], 'amount' : [13767.2522, 263.34, 395.01, 474.785901, 593.4823763], 'injection' : [1,2,3,4,5], 'to_usd' : [0.009564, 1, 1, 1.1093, 1.1093], 'to_ccy' : [1.3167, 1.3167, 1.3167, 1.3167, 1.3167], 'm5' : [2,4,6,8,10], 'm6' : [1,3,5,7,9]}); df_pivot.columns.names = ['portfolio','measures', 'portfolio_ccy', 'reporting_ccy'] # instead of joining the 2 df's add df1 to df_pivot 1 row at a time. for i in range(len(df1)): row = df1.iloc[i] for measure in 'amount injection m5 m6 to_ccy to_usd'.split(): df_pivot.ix[row.index_date, (row.portfolio,measure,row.portfolio_ccy, row.reporting_ccy)] = row[measure] #%% check the end result print(df_pivot.xs(('amount', 'A'), level=('measures','portfolio'), drop_level=False, axis=1)) 

Estoy muy confundido por la sobrecarga de información.
Sin embargo, si entiendo correctamente:

Lo que estoy dando a entender es que no hay una manera fácil de agregar a un nivel inferior en un dataframe Multi-Index.


considerar df

 df = pd.DataFrame(np.arange(64).reshape(-1, 8), list('abcdefgh'), list('ABCDEFGH')) df 

introduzca la descripción de la imagen aquí


Podemos añadir fácilmente un nivel al nivel interior del índice.

 df.index = [df.index, list('XY') * 4] df 

introduzca la descripción de la imagen aquí