2012-06-14 11 views
10

Quiero ser capaz de crear un Pandas DataFrame con MultiIndexes para las filas y el índice de columnas y leerlo desde un archivo de texto ASCII. Mis datos se parece a:¿Cómo escribir/leer un marco de datos de pandas con MultiIndex desde/hacia un archivo ASCII?

col_indx = MultiIndex.from_tuples([('A', 'B', 'C'), ('A', 'B', 'C2'), ('A', 'B', 'C3'), 
            ('A', 'B2', 'C'), ('A', 'B2', 'C2'), ('A', 'B2', 'C3'), 
            ('A', 'B3', 'C'), ('A', 'B3', 'C2'), ('A', 'B3', 'C3'), 
            ('A2', 'B', 'C'), ('A2', 'B', 'C2'), ('A2', 'B', 'C3'), 
            ('A2', 'B2', 'C'), ('A2', 'B2', 'C2'), ('A2', 'B2', 'C3'), 
            ('A2', 'B3', 'C'), ('A2', 'B3', 'C2'), ('A2', 'B3', 'C3')], 
            names=['one','two','three']) 
row_indx = MultiIndex.from_tuples([(0, 'North', 'M'), 
            (1, 'East', 'F'), 
            (2, 'West', 'M'), 
            (3, 'South', 'M'), 
            (4, 'South', 'F'), 
            (5, 'West', 'F'), 
            (6, 'North', 'M'), 
            (7, 'North', 'M'), 
            (8, 'East', 'F'), 
            (9, 'South', 'M')], 
            names=['n', 'location', 'sex']) 
size=len(row_indx), len(col_indx) 
data = np.random.randint(0,10, size) 
df = DataFrame(data, index=row_indx, columns=col_indx) 
print df 

He intentado df.to_csv() y read_csv() pero no guardo el índice.

Estaba pensando en tal vez crear un nuevo formato usando delímetros adicionales. Por ejemplo, usando una fila de ---------------- para marcar el final de los índices de columna y | para marcar el final del índice de una fila. Por lo que se vería así:

one   | A A A A A A A A A A2 A2 A2 A2 A2 A2 A2 A2 A2 
two   | B B B B2 B2 B2 B3 B3 B3 B B B B2 B2 B2 B3 B3 B3 
three   | C C2 C3 C C2 C3 C C2 C3 C C2 C3 C C2 C3 C C2 C3 
-------------------------------------------------------------------------------------- 
n location sex :                  
0 North M | 2 3 9 1 0 6 5 9 5 9 4 4 0 9 6 2 6 1 
1 East  F | 6 2 9 2 7 0 0 3 7 4 8 1 3 2 1 7 7 5 
2 West  M | 5 8 9 7 6 0 3 0 2 5 0 3 9 6 7 3 4 9 
3 South M | 6 2 3 6 4 0 4 0 1 9 3 6 2 1 0 6 9 3 
4 South F | 9 6 0 0 6 1 7 0 8 1 7 6 2 0 8 1 5 3 
5 West  F | 7 9 7 8 2 0 4 3 8 9 0 3 4 9 2 5 1 7 
6 North M | 3 3 5 7 9 4 2 6 3 2 7 5 5 5 6 4 2 9 
7 North M | 7 4 8 6 8 4 5 7 9 0 2 9 1 9 7 9 5 6 
8 East  F | 1 6 5 3 6 4 6 9 6 9 2 4 2 9 8 4 2 4 
9 South M | 9 6 6 1 3 1 3 5 7 4 8 6 7 7 8 9 2 3 

Does pandas tienen una manera de escribir/leer tramas de datos a/desde ficheros ASCII con MultiIndexes?

+0

Sí, ¡simplemente establece multi_sparse en False! :) –

Respuesta

11

No está seguro de qué versión de pandas que está utilizando pero con 0.7.3 puede exportar su DataFrame a un archivo TSV y retener a los índices al hacer esto:

df.to_csv('mydf.tsv', sep='\t') 

La razón por la que necesita para exportar a TSV frente CSV es porque los encabezados de columna tienen , caracteres en ellos. Esto debería resolver la primera parte de tu pregunta.

La segunda parte es un poco más complicada ya que, por lo que puedo ver, es necesario que tenga una idea previa de lo que quiere que contenga su DataFrame. En particular, lo que necesita saber:

  1. las columnas que en su TSV representan la fila MultiIndex
  2. y que el resto de las columnas también se puede convertir en un MultiIndex

Para ilustrar esto, deja para leer de nuevo el archivo TSV hemos salvado anteriormente en una nueva DataFrame:

In [1]: t_df = read_table('mydf.tsv', index_col=[0,1,2]) 
In [2]: all(t_df.index == df.index) 
Out[2]: True 

Así que consiguió leer mydf.tsv en un DataFrame que tiene el mismo índice de fila que el original df. Pero:

In [3]: all(t_df.columns == df.columns) 
Out[3]: False 

Y la razón aquí es porque los pandas (por lo que puedo decir) no tiene manera de analizar la fila de encabezado correctamente en un MultiIndex.Como he mencionado anteriormente, si se sabe beorehand que su encabezado del archivo TSV representa un MultiIndex entonces usted puede hacer lo siguiente para solucionar este problema:

In [4]: from ast import literal_eval 
In [5]: t_df.columns = MultiIndex.from_tuples(t_df.columns.map(literal_eval).tolist(), 
               names=['one','two','three']) 
In [6]: all(t_df.columns == df.columns) 
Out[6]: True 
+0

Me gusta lo que se te ocurrió. Creo que aún crearé mi propio formato ya que no sé de antemano cuántas columnas se usan para el índice. Gracias. – dailyglen

4

Puede cambiar las opciones de impresión mediante set_option:

display.multi_sparse :
: boolean
    defecto True, "sparsify" MultiIndex pantalla
    (no se muestran repiten elementos en niveles externos dentro de los grupos)

Ahora la trama de datos se imprimirán como deseado:

In [11]: pd.set_option('multi_sparse', False) 

In [12]: df 
Out[12]: 
one    A A A A A A A A A A2 A2 A2 A2 A2 A2 A2 A2 A2 
two    B B B B2 B2 B2 B3 B3 B3 B B B B2 B2 B2 B3 B3 B3 
three   C C2 C3 C C2 C3 C C2 C3 C C2 C3 C C2 C3 C C2 C3 
n location sex                  
0 North M 2 1 6 4 6 4 7 1 1 0 4 3 9 2 0 0 6 4 
1 East  F 3 5 5 6 4 8 0 3 2 3 9 8 1 6 7 4 7 2 
2 West  M 7 9 3 5 0 1 2 8 1 6 0 7 9 9 3 2 2 4 
3 South M 1 0 0 3 5 7 7 0 9 3 0 3 3 6 8 3 6 1 
4 South F 8 0 0 7 3 8 0 8 0 5 5 6 0 0 0 1 8 7 
5 West  F 6 5 9 4 7 2 5 6 1 2 9 4 7 5 5 4 3 6 
6 North M 3 3 0 1 1 3 6 3 8 6 4 1 0 5 5 5 4 9 
7 North M 0 4 9 8 5 7 7 0 5 8 4 1 5 7 6 3 6 8 
8 East  F 5 6 2 7 0 6 2 7 1 2 0 5 6 1 4 8 0 3 
9 South M 1 2 0 6 9 7 5 3 3 8 7 6 0 5 4 3 5 9 

Nota: en las versiones anteriores de pandas esto era pd.set_printoptions(multi_sparse=False).

Cuestiones relacionadas