¿Cómo puedo generalizar mis datos de pandas agrupando a más de 3 dimensiones?

Estoy utilizando el excelente paquete de pandas para manejar una gran cantidad de datos de diagnóstico meteorológico variados y me estoy quedando sin dimensiones rápidamente mientras uno los datos. Mirando la documentación, es posible que el uso del MultiIndex pueda resolver mi problema, pero no estoy seguro de cómo aplicarlo a mi situación. La documentación muestra ejemplos de cómo crear MultiIndexes con datos aleatorios y DataFrame s, pero no Series con pre -existentes datos de series de tiempo.

Fondo

La estructura de datos básica que estoy usando contiene dos campos principales:

  • metadata , que es un diccionario que consiste en pares clave-valor que describen cuáles son los números
  • data , que es una estructura de datos de pandas que contiene los números mismos.

El mínimo común denominador es la serie temporal de datos, por lo que la estructura básica tiene un objeto Series pandas como entrada de data , y el campo de metadata describe cuáles son esos números en realidad (por ejemplo, un error de RMS vector para un viento de 10 metros sobre el Pacífico oriental durante 24 horas). hora pronosticada a partir del experimento Test1).

Estoy pensando en tomar el mínimo común denominador y pegar las diversas series temporales para hacer que los resultados sean más útiles y permitan combinaciones fáciles. Por ejemplo, es posible que desee ver todos los diferentes tiempos de entrega: tengo una rutina de filtro que tomará mis series temporales que comparten las mismas entradas de metadatos, excepto el tiempo de entrega (por ejemplo, experimento, región, etc.) y devolveré un nuevo objeto donde el campo de metadata consta solo de las entradas comunes (es decir, se eliminó el Lead Time DataFrame ) y ahora el campo de data es un DataFrame data pandas con las tags de columna indicadas por el valor del Lead Time DataFrame . Puedo extender esto nuevamente y decir que quiero tomar los cuadros resultantes y agruparlos con solo otra entrada que varíe (por ejemplo, el Experiment ) para darme un Panel pandas. para mi entrada donde el índice del elemento viene dado por los valores de metadatos del Experiment de los marcos constituyentes y los nuevos metadatos del objeto no contienen el Lead Time o el Experiment .

Cuando itero sobre estos objetos compuestos, tengo una rutina de iterseries para el cuadro y la rutina de iterframes para el panel que reconstruye el par de metadatos / datos apropiados al soltar una dimensión (es decir, la serie del cuadro con tiempo de espera que varía a través de las columnas tener todos los metadatos de su padre más el campo de Lead Time entrega restaurado con el valor tomado de la etiqueta de la columna). Esto funciona muy bien.

Problema

Me he quedado sin dimensiones (hasta 3-D con un Panel) y tampoco puedo usar cosas como dropna para eliminar columnas vacías una vez que todo está alineado en el Panel (esto ha generado varios errores al trazar un resumen) estadística). Leer sobre el uso de pandas con datos de dimensiones superiores ha llevado a leer sobre el MultiIndex y su uso. He intentado los ejemplos que figuran en la documentación, pero aún no estoy seguro de cómo aplicarlos a mi situación. Cualquier dirección sería útil. Me gustaría poder:

  • Combine los datos basados ​​en mi Series en un DataFrame multi-indexado a DataFrame largo de un número arbitrario de dimensiones (esto sería genial – eliminaría una llamada para crear los marcos de la serie, y luego otra para crear los paneles a partir de los marcos)
  • Iterar sobre el DataFrame multi-indexado DataFrame , eliminando una sola dimensión para que pueda restablecer los metadatos del componente.

Editar – Agregar ejemplo de código

La respuesta de Wes McKinney a continuación es casi exactamente lo que necesito: el problema está en la traducción inicial de los objetos de almacenamiento respaldados por la Serie con los que tengo que trabajar con mis objetos respaldados por DataFrame una vez que comience a agrupar elementos. La clase respaldada por dataframe tiene el siguiente método que toma una lista de los objetos basados ​​en series y el campo de metadatos que variará en las columnas.

 @classmethod def from_list(cls, results_list, column_key): """ Populate object from a list of results that all share the metadata except for the field `column_key`. """ # Need two copies of the input results - one for building the object # data and one for building the object metadata for_data, for_metadata = itertools.tee(results_list) self = cls() self.column_key = column_key self.metadata = next(for_metadata).metadata.copy() if column_key in self.metadata: del self.metadata[column_key] self.data = pandas.DataFrame(dict(((transform(r[column_key]), r.data) for r in for_data))) return self 

Una vez que tengo el marco dado por esta rutina, puedo aplicar fácilmente las diversas operaciones que se sugieren a continuación: una utilidad particular es poder usar el campo de names cuando llamo a concat . Esto elimina la necesidad de almacenar el nombre de la clave de columna internamente, ya que se almacena en el MultiIndex como el nombre de esa dimensión de índice.

Me gustaría poder implementar la solución a continuación y simplemente ver la lista de clases respaldadas por la serie y una lista de claves y hacer la agrupación de forma secuencial. Sin embargo, no sé qué representarán las columnas antes de tiempo, así que:

  • Realmente no tiene sentido para mí almacenar los datos de la serie en un DataFrame 1-D
  • No veo cómo establecer el nombre del índice y las columnas de la Serie inicial -> Agrupación de cuadros

Podría sugerir el uso de pandas.concat junto con su argumento de keys para pegar los Series DataFrames para crear un MultiIndex en las columnas:

 In [20]: data Out[20]: {'a': 2012-04-16 0 2012-04-17 1 2012-04-18 2 2012-04-19 3 2012-04-20 4 2012-04-21 5 2012-04-22 6 2012-04-23 7 2012-04-24 8 2012-04-25 9 Freq: D, 'b': 2012-04-16 0 2012-04-17 1 2012-04-18 2 2012-04-19 3 2012-04-20 4 2012-04-21 5 2012-04-22 6 2012-04-23 7 2012-04-24 8 2012-04-25 9 Freq: D, 'c': 2012-04-16 0 2012-04-17 1 2012-04-18 2 2012-04-19 3 2012-04-20 4 2012-04-21 5 2012-04-22 6 2012-04-23 7 2012-04-24 8 2012-04-25 9 Freq: D} In [21]: df = pd.concat(data, axis=1, keys=['a', 'b', 'c']) In [22]: df Out[22]: abc 2012-04-16 0 0 0 2012-04-17 1 1 1 2012-04-18 2 2 2 2012-04-19 3 3 3 2012-04-20 4 4 4 2012-04-21 5 5 5 2012-04-22 6 6 6 2012-04-23 7 7 7 2012-04-24 8 8 8 2012-04-25 9 9 9 In [23]: df2 = pd.concat([df, df], axis=1, keys=['group1', 'group2']) In [24]: df2 Out[24]: group1 group2 abcabc 2012-04-16 0 0 0 0 0 0 2012-04-17 1 1 1 1 1 1 2012-04-18 2 2 2 2 2 2 2012-04-19 3 3 3 3 3 3 2012-04-20 4 4 4 4 4 4 2012-04-21 5 5 5 5 5 5 2012-04-22 6 6 6 6 6 6 2012-04-23 7 7 7 7 7 7 2012-04-24 8 8 8 8 8 8 2012-04-25 9 9 9 9 9 9 

Usted tiene entonces:

 In [25]: df2['group2'] Out[25]: abc 2012-04-16 0 0 0 2012-04-17 1 1 1 2012-04-18 2 2 2 2012-04-19 3 3 3 2012-04-20 4 4 4 2012-04-21 5 5 5 2012-04-22 6 6 6 2012-04-23 7 7 7 2012-04-24 8 8 8 2012-04-25 9 9 9 

o incluso

 In [27]: df2.xs('b', axis=1, level=1) Out[27]: group1 group2 2012-04-16 0 0 2012-04-17 1 1 2012-04-18 2 2 2012-04-19 3 3 2012-04-20 4 4 2012-04-21 5 5 2012-04-22 6 6 2012-04-23 7 7 2012-04-24 8 8 2012-04-25 9 9 

Puedes tener arbitrariamente muchos niveles:

 In [29]: pd.concat([df2, df2], axis=1, keys=['tier1', 'tier2']) Out[29]: tier1 tier2 group1 group2 group1 group2 abcabcabcabc 2012-04-16 0 0 0 0 0 0 0 0 0 0 0 0 2012-04-17 1 1 1 1 1 1 1 1 1 1 1 1 2012-04-18 2 2 2 2 2 2 2 2 2 2 2 2 2012-04-19 3 3 3 3 3 3 3 3 3 3 3 3 2012-04-20 4 4 4 4 4 4 4 4 4 4 4 4 2012-04-21 5 5 5 5 5 5 5 5 5 5 5 5 2012-04-22 6 6 6 6 6 6 6 6 6 6 6 6 2012-04-23 7 7 7 7 7 7 7 7 7 7 7 7 2012-04-24 8 8 8 8 8 8 8 8 8 8 8 8 2012-04-25 9 9 9 9 9 9 9 9 9 9 9 9