2015-08-06 15 views
5

mam pewne dane gdzie mam manipulował dataframe stosując następujący kod:pandy - Multi Indeks kreślenia

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() 

Moje pytanie brzmi, jak mogę wykreślić średnie dane za pomocą ggplot lub Seaborn takie, że dla każdego poziom „split” mam wykres, który wygląda tak:

enter image description here

na dole kodu można zobaczyć Próbowałam podzielić czynnik grupy, więc mogę oddzielić barów, ale że spowodował błąd (KeyError: "group") i myślę, że jest to relat w sposób, w jaki używałem wielu indeksów,

+2

można skopiować kod i dane na swoje pytanie? – maxymoo

Odpowiedz

12

Użyłbym wykresu współczynnika z seaborn.

że masz dane, takie jak ten:

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 

Następnie można utworzyć wykres czynnikiem jednego polecenia + plus dodatkową linię usunąć niektóre zbędne (dla danych) X-etykiety:

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

co daje mi:

enter image description here

+0

To jest idealne, dzięki! Czy istnieje sposób na wykreślenie słupków błędów, gdzie przedstawiony błąd jest standardowym błędem średniej? – Simon

+0

@Nem Nie mogę teraz zajrzeć w creep żadnego zakresu. Ale to odpowiada na twoje pierwotne pytanie. W związku z tym pytanie to jest pierwszym trafieniem, które uzyskuję w wyszukiwarce Google dla "pasków błędu seaborn" http://stackoverflow.com/questions/24878095/plotting-errors-bars-from-dataframe-using-seaborn-facetgrid –

+0

Wow. Przeczytanie kodu uważnie sprawiło, że nauczyłem się wiele o indeksowaniu i kreśleniu, z którymi wcześniej walczyłem. Naprawdę niesamowite z powodu swojej prostoty! –

4

W a related question Znalazłem alternatywne rozwiązanie @Stein, które koduje poziomy wieluindeksów jako różne etykiety. Oto jak to wygląda dla przykładu:

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) 

Daje:

enter image description here

Powiązane problemy