2015-08-06 17 views
5

ho alcuni dati in cui ho manipolato i dataframe utilizzando il seguente codice:panda - Multi indice tramando

import pandas as pd 
import numpy as np 

data = pd.DataFrame([[0,0,0,3,6,5,6,1],[1,1,1,3,4,5,2,0],[2,1,0,3,6,5,6,1],[3,0,0,2,9,4,2,1],[4,0,1,3,4,8,1,1],[5,1,1,3,3,5,9,1],[6,1,0,3,3,5,6,1],[7,0,1,3,4,8,9,1]], columns=["id", "sex", "split", "group0Low", "group0High", "group1Low", "group1High", "trim"]) 
data 

#remove all where trim == 0 
trimmed = data[(data.trim == 1)] 
trimmed 

#create df with columns to be split 
columns = ['group0Low', 'group0High', 'group1Low', 'group1High'] 
to_split = trimmed[columns] 
to_split 

level_group = np.where(to_split.columns.str.contains('0'), 0, 1) 
# output: array([0, 0, 1, 1]) 
level_low_high = np.where(to_split.columns.str.contains('Low'), 'low', 'high') 
# output: array(['low', 'high', 'low', 'high'], dtype='<U4') 

multi_level_columns = pd.MultiIndex.from_arrays([level_group, level_low_high], names=['group', 'val']) 
to_split.columns = multi_level_columns 
to_split.stack(level='group') 

sex = trimmed['sex'] 
split = trimmed['split'] 
horizontalStack = pd.concat([sex, split, to_split], axis=1) 
horizontalStack 

finalData = horizontalStack.groupby(['split', 'sex', 'group']) 
finalData.mean() 

La mia domanda è, come faccio a tracciare i dati medi utilizzando ggplot o Seaborn tale che per ogni livello di "split" ottengo un grafico che assomiglia a questo:

enter image description here

in fondo il codice è possibile vedere che ho cercato di dividere il fattore di gruppo in modo da poter separare le sbarre, ma che ha provocato un errore (KeyError: 'group') e penso che sia relat ed al modo in cui ho usato l'indicizzazione multipla

+2

è possibile copiare il codice e dei dati nella tua domanda? – maxymoo

risposta

12

Vorrei usare un diagramma fattoriale di Seaborn.

dire che hai i dati di questo tipo:

import numpy as np 
import pandas 

import seaborn 
seaborn.set(style='ticks') 
np.random.seed(0) 

groups = ('Group 1', 'Group 2') 
sexes = ('Male', 'Female') 
means = ('Low', 'High') 
index = pandas.MultiIndex.from_product(
    [groups, sexes, means], 
    names=['Group', 'Sex', 'Mean'] 
) 

values = np.random.randint(low=20, high=100, size=len(index)) 
data = pandas.DataFrame(data={'val': values}, index=index).reset_index() 
print(data) 

    Group  Sex Mean val 
0 Group 1 Male Low 64 
1 Group 1 Male High 67 
2 Group 1 Female Low 84 
3 Group 1 Female High 87 
4 Group 2 Male Low 87 
5 Group 2 Male High 29 
6 Group 2 Female Low 41 
7 Group 2 Female High 56 

È possibile quindi creare la trama fattore con un solo comando + una linea in più per rimuovere alcuni ridondanti (per i dati) X-etichette:

fg = seaborn.factorplot(x='Group', y='val', hue='Mean', 
         col='Sex', data=data, kind='bar') 
fg.set_xlabels('') 

che mi dà:

enter image description here

+0

Questo è perfetto, grazie! C'è un modo per tracciare le barre di errore, dove l'errore rappresentato è l'errore standard della media? – Simon

+0

@Nem Non riesco a guardare in alcuno strumento di scorrimento. Ma questo risponde alla tua domanda originale. Per il follow-up, questa domanda SO è il primo risultato che ottengo su google alla ricerca di "barre di errore seaborn" http://stackoverflow.com/questions/24878095/plotting-errors-bars-from-dataframe-using-seaborn-facetgrid –

+0

Wow. Leggere attentamente il tuo codice mi ha fatto imparare molto sul multi-indexing e sul plot che avevo già dovuto affrontare. Davvero fantastico per la sua semplicità! –

4

In a related question Ho trovato una soluzione alternativa di @Stein che codifica i livelli multiindex come etichette diverse. Ecco come sembra per il tuo esempio:

import pandas as pd 
import matplotlib.pyplot as plt 
from itertools import groupby 
import numpy as np 
%matplotlib inline 

groups = ('Group 1', 'Group 2') 
sexes = ('Male', 'Female') 
means = ('Low', 'High') 
index = pd.MultiIndex.from_product(
    [groups, sexes, means], 
    names=['Group', 'Sex', 'Mean'] 
) 

values = np.random.randint(low=20, high=100, size=len(index)) 
data = pd.DataFrame(data={'val': values}, index=index) 
# unstack last level to plot two separate columns 
data = data.unstack(level=-1) 

def add_line(ax, xpos, ypos): 
    line = plt.Line2D([xpos, xpos], [ypos + .1, ypos], 
         transform=ax.transAxes, color='gray') 
    line.set_clip_on(False) 
    ax.add_line(line) 

def label_len(my_index,level): 
    labels = my_index.get_level_values(level) 
    return [(k, sum(1 for i in g)) for k,g in groupby(labels)] 

def label_group_bar_table(ax, df): 
    ypos = -.1 
    scale = 1./df.index.size 
    for level in range(df.index.nlevels)[::-1]: 
     pos = 0 
     for label, rpos in label_len(df.index,level): 
      lxpos = (pos + .5 * rpos)*scale 
      ax.text(lxpos, ypos, label, ha='center', transform=ax.transAxes) 
      add_line(ax, pos*scale, ypos) 
      pos += rpos 
     add_line(ax, pos*scale , ypos) 
     ypos -= .1 

ax = df['val'].plot(kind='bar') 
#Below 2 lines remove default labels 
ax.set_xticklabels('') 
ax.set_xlabel('') 
label_group_bar_table(ax, df) 

Questo dà:

enter image description here

Problemi correlati