2013-08-27 13 views
11

mam DataFrame z kolumnami MultiIndex, który wygląda tak:Jak wybrać tylko określone kolumny z DataFrame z kolumnami MultiIndex?

# sample data 
col = pd.MultiIndex.from_arrays([['one', 'one', 'one', 'two', 'two', 'two'], 
           ['a', 'b', 'c', 'a', 'b', 'c']]) 
data = pd.DataFrame(np.random.randn(4, 6), columns=col) 
data 

sample data

Jaka jest właściwa, prosty sposób wybierania tylko określonych kolumn (np ['a', 'c'], a nie zakres) z drugiego poziomu?

Obecnie robię to tak:

import itertools 
tuples = [i for i in itertools.product(['one', 'two'], ['a', 'c'])] 
new_index = pd.MultiIndex.from_tuples(tuples) 
print(new_index) 
data.reindex_axis(new_index, axis=1) 

expected result

Nie czuję się jak dobre rozwiązanie, jednak, ponieważ mam do odpadniesz itertools, budować kolejną MultiIndex ręcznie i następnie reindex (a mój aktualny kod jest jeszcze bardziej zawiły, ponieważ listy kolumn nie są tak proste do pobrania). Jestem pewien, że musi to być jakiś sposób na zrobienie tego, ale wszystko, co próbowałem, spowodowało błędy.

+0

Czy próbowałeś używać słowników? – darmat

+0

Nie, nie mam. Masz na myśli szybsze konstruowanie MultiIndex? Jeśli tak, to nie o to chodzi - chciałbym go ominąć i zindeksować bezpośrednio z czymś takim jak 'data.xs (['a', 'c'], axis = 1, level = 1)' – metakermit

+0

załóżmy, że to: – darmat

Odpowiedz

6

to nie jest wielki, ale może:

>>> data 
     one       two      
      a   b   c   a   b   c 
0 -0.927134 -1.204302 0.711426 0.854065 -0.608661 1.140052 
1 -0.690745 0.517359 -0.631856 0.178464 -0.312543 -0.418541 
2 1.086432 0.194193 0.808235 -0.418109 1.055057 1.886883 
3 -0.373822 -0.012812 1.329105 1.774723 -2.229428 -0.617690 
>>> data.ix[:,data.columns.get_level_values(1).isin({"a", "c"})] 
     one     two   
      a   c   a   c 
0 -0.927134 0.711426 0.854065 1.140052 
1 -0.690745 -0.631856 0.178464 -0.418541 
2 1.086432 0.808235 -0.418109 1.886883 
3 -0.373822 1.329105 1.774723 -0.617690 

będzie działać?

+0

Właściwie uważam, że jest to optymalny sposób filtrowania listy etykiet na dowolnym poziomie MultiIndex bez tworzenia wszystkich krotek. Po prostu użyłbym 'loc' dla jasności. –

+0

Aby zachować kolejność kolumn, lepiej użyć 'isin ([" a "," b "])'. – Peaceful

+0

@Peaceful: co? To niczego nie zmienia. Wynikiem wywołania isin jest seria bool, a jej kolejność jest określona na podstawie kolejności oryginalnej serii, a nie argumentu dla isin. – DSM

8

Można użyć, loc lub ix pokażę przykład z loc:

data.loc[:, [('one', 'a'), ('one', 'c'), ('two', 'a'), ('two', 'c')]] 

Kiedy masz MultiIndexed DataFrame i chcesz, aby odfiltrować tylko niektóre z kolumn, trzeba przekazać listę krotek pasujących do tych kolumn. Zatem podejście itertools było prawie OK, ale nie trzeba, aby utworzyć nowy MultiIndex:

data.loc[:, list(itertools.product(['one', 'two'], ['a', 'c']))] 
+0

Dzięki, to także dobre rozwiązanie! – metakermit

13

myślę, że jest o wiele lepszy sposób (teraz), który jest dlaczego przeszkadzało ciągnąc to pytanie (który był szczyt wynik Google) z cienia:

data.select(lambda x: x[1] in ['a', 'b'], axis=1) 

daje oczekiwany wynik w sposób szybkie i czyste jedno-liner:

 one     two   
      a   b   a   b 
0 -0.341326 0.374504 0.534559 0.429019 
1 0.272518 0.116542 -0.085850 -0.330562 
2 1.982431 -0.420668 -0.444052 1.049747 
3 0.162984 -0.898307 1.762208 -0.101360 

to głównie self-wyjaśniając, [1] odnosi się do poziomu.

4

Aby zaznaczyć wszystkie kolumny o nazwach 'a' i 'c' na drugim poziomie swojej indekser kolumny, można użyć krajalnice:

>>> data.loc[:, (slice(None), ('a', 'c'))] 

     one     two   
      a   c   a   c 
0 -0.983172 -2.495022 -0.967064 0.124740 
1 0.282661 -0.729463 -0.864767 1.716009 
2 0.942445 1.276769 -0.595756 -0.973924 
3 2.182908 -0.267660 0.281916 -0.587835 

Here można przeczytać więcej o krajalnice.

Powiązane problemy