2012-06-14 5 views
10

Voglio essere in grado di creare un Panda DataFrame con MultiIndex per le righe e l'indice delle colonne e leggerlo da un file di testo ASCII. I miei dati assomiglia:Come scrivere/leggere un DataFrame di Pandas con MultiIndex da/a un file 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 

Ho provato df.to_csv() e read_csv() ma non tenere l'indice.

Stavo pensando di creare un nuovo formato utilizzando delimitatori aggiuntivi. Ad esempio, utilizzando una riga di ---------------- per contrassegnare la fine degli indici di colonna e un | per contrassegnare la fine di un indice di riga. Quindi sarebbe simile a questa:

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 hanno un modo di scrivere/leggere DataFrames a/da file ASCII con MultiIndexes?

+0

Sì, imposta solo multi_sparse su False! :) –

risposta

11

Non sai quale versione di panda che si sta utilizzando, ma con 0.7.3 è possibile esportare il DataFrame in un file TSV e mantenere gli indici in questo modo:

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

Il motivo è necessario esportare in TSV contro CSV poiché le intestazioni delle colonne contengono caratteri ,. Questo dovrebbe risolvere la prima parte della tua domanda.

La seconda parte è un po 'più complicata dal momento che, per quanto posso dire, è necessario prima avere un'idea di ciò che si desidera che il DataFrame contenga. In particolare, è necessario sapere:

  1. Quali colonne sul TSV rappresentano la fila MultiIndex
  2. e che il resto delle colonne dovrebbe essere convertito in un MultiIndex

Per illustrare questo, Leggiamo di nuovo il file TSV abbiamo salvato sopra in un nuovo 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 

così siamo riusciti a leggere mydf.tsv in un DataFrame con lo stesso indice di riga dell'originale df. Ma:

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

E la ragione ecco perché i panda (per quanto ne so) non ha modo di analizzare la riga di intestazione in modo corretto in un MultiIndex.Come ho già detto, se si sa beorehand che l'intestazione del file TSV rappresenta un MultiIndex allora si può fare le seguenti operazioni per risolvere questo 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

Mi piace quello che ti è venuto in mente. Penso che creerò ancora il mio formato perché non so in anticipo quante colonne sono usate per l'indice. Grazie. – dailyglen

4

È possibile modificare le opzioni di stampa utilizzando set_option:

display.multi_sparse :
: boolean
    predefinito True, "sparsify" MultiIndex visualizzazione
    (non visualizzano ripetuto elementi nei livelli esterni all'interno dei gruppi)

Ora il dataframe viene stampato lo desideri:

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: nelle versioni precedenti panda questo era pd.set_printoptions(multi_sparse=False).