Wybierz wiersze w ramce danych pandy MultiIndex

Jakie są najczęstsze sposoby wybierania / filtrowania wierszy ramki danych, której indeks jest MultiIndex?

  • krojenie na podstawie pojedynczej wartości / etykiety
  • krojenie na podstawie wielu etykiet z jednego lub więcej poziomów
  • filtrowanie na warunkach logicznych i wyrażeniach
  • jakie metody mają zastosowanie w jakich okolicznościach

Założenia dla prostoty:

  1. ramka danych wejściowych nie posiada zduplikowane klucze indeksu
  2. ramka danych wejściowych poniżej ma tylko dwa poziomy. (Większość rozwiązań pokazanych tutaj uogólnia się na N poziomów)

Przykładowe wejście:

mux = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    list('tuvwtuvwtuvwtuvw')
], names=['one', 'two'])

df = pd.DataFrame({'col': np.arange(len(mux))}, mux)

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    u      5
    v      6
    w      7
    t      8
c   u      9
    v     10
d   w     11
    t     12
    u     13
    v     14
    w     15

Pytanie 1: Wybór pojedynczego elementu

Jak wybrać wiersze posiadające " a "na poziomie"1"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3

Dodatkowo, jak mógłbym być w stanie obniżyć poziom "jeden" w wyjściu?

     col
two     
t      0
u      1
v      2
w      3

Pytanie 1b
Jak pokroić wszystkie wiersze z wartością "t" na poziomie "dwa"?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

Pytanie 2: Wybór wielu wartości na poziomie

Jak mogę wybrać wiersze odpowiadające elementom " b " I " d "na poziomie"pierwszy"?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

Pytanie 2b
Jak uzyskać wszystkie wartości odpowiadające " t " i " w "na poziomie"drugim"?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

Pytanie 3: krojenie pojedynczego przekroju (x, y)

Jak odzyskać przekrój, tzn. pojedynczy wiersz o określonej wartości dla indeksu z df? W szczególności, jak Pobierz przekrój ('c', 'u'), podany przez

         col
one two     
c   u      9

Pytanie 4: Krojenie Wielu Przekrojów [(a, b), (c, d), ...]

Jak wybrać dwa wiersze odpowiadające ('c', 'u') i ('a', 'w')?

         col
one two     
c   u      9
a   w      3

Pytanie 5: jeden element pokrojony na poziom

Jak mogę pobrać wszystkie wiersze odpowiadające " a "na poziomie" pierwszy " lub " t "na poziomie"drugi"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12
Pytanie 6: Dowolne Krojenie]}

Jak pokroić konkretne przekroje? Dla " a " i " b " chciałbym wybierz wszystkie wiersze z podpoziomem " u " I "v", A dla" d "chciałbym wybrać wiersze z podpoziomem"w".

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

Pytanie 7 użyje unikalnej konfiguracji składającej się z poziomu liczbowego:

np.random.seed(0)
mux2 = pd.MultiIndex.from_arrays([
    list('aaaabbbbbccddddd'),
    np.random.choice(10, size=16)
], names=['one', 'two'])

df2 = pd.DataFrame({'col': np.arange(len(mux2))}, mux2)

         col
one two     
a   5      0
    0      1
    3      2
    3      3
b   7      4
    9      5
    3      6
    5      7
    2      8
c   4      9
    7     10
d   6     11
    8     12
    8     13
    1     14
    6     15

Pytanie 7: filtrowanie przez nierówności liczbowe na poszczególnych poziomach multiindex

Jak uzyskać wszystkie wiersze, w których wartości na poziomie "dwa" są większe niż 5?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

Uwaga: Ten post będzie Nie przejść przez jak tworzyć Multiindexy, jak wykonywać operacje przyporządkowania na nich, lub wszelkie dyskusje związane z wydajnością (są to oddzielne tematy na inny raz).

Author: cs95, 2018-12-26

2 answers

MultiIndex / Zaawansowane Indeksowanie

Uwaga
Ten post będzie zorganizowany w następujący sposób:

  1. pytania postawione w PO będą rozwiązywane, jeden po drugim
  2. dla każdego pytania zostanie zademonstrowana jedna lub więcej metod mających zastosowanie do rozwiązania tego problemu i uzyskania oczekiwanego wyniku.

Uwagas (podobnie jak ta) zostanie dołączona dla czytelników zainteresowanych nauką o dodatkowych funkcjonalnościach, szczegółach implementacji, i inne info pobieżne do omawianego tematu. Te notatki zostały skompilowane poprzez przeszukiwanie dokumentów i odkrywanie różnych niejasnych funkcji, oraz z własnego (co prawda ograniczonego) doświadczenia.

Wszystkie próbki kodu zostały stworzone i przetestowane na pandas v0.23.4, python3. 7. Jeśli coś nie jest jasne, lub faktyczne nieprawidłowe, lub jeśli nie znajdź rozwiązanie odpowiednie do twojego przypadku użycia, prosimy o zaproponuj edycję, poproś o wyjaśnienie w komentarzach lub Otwórz nowy pytanie.....

[144]} oto wprowadzenie do niektórych popularnych idiomów (odtąd zwanych czterema idiomami), które będziemy często odwiedzać [148]}
  1. DataFrame.loc - ogólne rozwiązanie wyboru według etykiety (+ pd.IndexSlice dla bardziej złożonych aplikacji obejmujących plastry)

  2. DataFrame.xs - ekstrakt określony przekrój z serii / ramki danych.

  3. DataFrame.query - określa operacje wycinania i/lub filtrowania dynamicznie (np. jako wyrażenie, które jest dynamicznie oceniane. Ma większe zastosowanie w niektórych scenariuszach niż w innych. Zobacz również tę sekcję dokumentów do zapytań o Multiindexy.

  4. Indeksowanie logiczne z maską generowaną przy użyciu MultiIndex.get_level_values (często w połączeniu z Index.isin, szczególnie przy filtrowaniu z wieloma wartościami). Jest to również bardzo przydatne w niektórych okolicznościach.

[144]}dobrze będzie przyjrzeć się różnym problemom krojenia i filtrowania w kategoriach czterech idiomów, aby lepiej zrozumieć, co można zastosować w danej sytuacji. Bardzo ważne jest, aby zrozumieć, że nie wszystkie idiomy będą działać równie dobrze (jeśli w ogóle) w każdej sytuacji. Jeśli idiom nie został wymieniony jako potencjalne rozwiązanie problemu poniżej, oznacza to, że idiom nie może być skutecznie zastosowany do tego problemu.

Pytanie 1

Jak wybrać wiersze posiadające "a "na poziomie"1"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
Możesz użyć

, jako rozwiązania ogólnego przeznaczenia, mającego zastosowanie w większości sytuacji:

df.loc[['a']]

W tym momencie, jeśli otrzymasz

TypeError: Expected tuple, got str

To oznacza, że używasz starszej wersji pand. Rozważ modernizację! W przeciwnym razie użyj df.loc[('a', slice(None)), :].

Alternatywnie, możesz użyć xs tutaj, ponieważ wydobywamy pojedynczy przekrój. Zwróć uwagę na argumenty levels i axis (można tu założyć rozsądne wartości domyślne).

df.xs('a', level=0, axis=0, drop_level=False)
# df.xs('a', drop_level=False)

Tutaj, drop_level=False argument jest potrzebny, aby zapobiec xs spadaniu poziomu "jeden" w wyniku (poziom, na którym się pokroiliśmy).

Jeszcze jedną opcją jest użycie query:

df.query("one == 'a'")

Jeśli indeks nie ma nazwy, musisz zmienić łańcuch zapytania, aby był "ilevel_0 == 'a'".

Wreszcie, używając get_level_values:

df[df.index.get_level_values('one') == 'a']
# If your levels are unnamed, or if you need to select by position (not label),
# df[df.index.get_level_values(0) == 'a']

Dodatkowo, jak mógłbym być w stanie obniżyć poziom "jeden" w wyjściu?

     col
two     
t      0
u      1
v      2
w      3

To może być łatwo zrobione za pomocą

df.loc['a'] # Notice the single string argument instead the list.

Lub,

df.xs('a', level=0, axis=0, drop_level=True)
# df.xs('a')

Zauważ, że możemy pominąć argument drop_level (domyślnie zakłada się, że to True).

Uwaga
Można zauważyć, że przefiltrowana ramka danych może nadal mieć wszystkie poziomy, nawet jeśli nie pokazują podczas drukowania ramki danych. Na przykład,

v = df.loc[['a']]
print(v)
         col
one two     
a   t      0
    u      1
    v      2
    w      3

print(v.index)
MultiIndex(levels=[['a', 'b', 'c', 'd'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

Możesz pozbyć się tych poziomów za pomocą MultiIndex.remove_unused_levels:

v.index = v.index.remove_unused_levels()
print(v.index)
MultiIndex(levels=[['a'], ['t', 'u', 'v', 'w']],
           labels=[[0, 0, 0, 0], [0, 1, 2, 3]],
           names=['one', 'two'])

Pytanie 1b

Jak pokroić wszystkie wiersze z wartością " t "na poziomie "dwa"?

         col
one two     
a   t      0
b   t      4
    t      8
d   t     12

Intuicyjnie, chciałbyś coś angażującego slice():

df.loc[(slice(None), 't'), :]
To Po Prostu Działa! Ale jest niezgrabny. Możemy ułatwić bardziej naturalne krojenie składnia przy użyciu API pd.IndexSlice tutaj.
idx = pd.IndexSlice
df.loc[idx[:, 't'], :]
To jest dużo, dużo czystsze.

Uwaga
Dlaczego wymagany jest końcowy kawałek : w kolumnach? To dlatego, loc może być używany do zaznaczania i wycinania wzdłuż obu osi (axis=0 lub axis=1). Bez wyraźnego określenia, która oś krojenia ma być zrobione na, operacja staje się niejednoznaczna. Zobacz duże czerwone pudełko w dokumentacji na temat krojenia.

Jeśli chcesz usunąć każdy cień niejednoznaczności, loc przyjmuje axis parametr:

df.loc(axis=0)[pd.IndexSlice[:, 't']]

Bez parametru axis (tzn. po prostu wykonując df.loc[pd.IndexSlice[:, 't']]) zakłada się, że na kolumnach, i KeyError zostanie podniesiony w tej sytuacji.

Jest to udokumentowane w krajalnice . Na potrzeby tego postu będziemy jednak wyraźnie określać wszystkie osie.

Z xs, jest

df.xs('t', axis=0, level=1, drop_level=False)

Z query, jest

df.query("two == 't'")
# Or, if the first level has no name, 
# df.query("ilevel_1 == 't'") 

I wreszcie, z get_level_values, ty may do

df[df.index.get_level_values('two') == 't']
# Or, to perform selection by position/integer,
# df[df.index.get_level_values(1) == 't']
/ Align = "left" /

Pytanie 2

Jak Mogę wybrać wiersze odpowiadające elementom " b " I " d "na poziomie"pierwszy"?

         col
one two     
b   t      4
    u      5
    v      6
    w      7
    t      8
d   w     11
    t     12
    u     13
    v     14
    w     15

Używając loc, robi się to w podobny sposób poprzez podanie listy.

df.loc[['b', 'd']]

Aby rozwiązać powyższy problem wyboru "b" I "d", możesz również użyć query:

items = ['b', 'd']
df.query("one in @items")
# df.query("one == @items", parser='pandas')
# df.query("one in ['b', 'd']")
# df.query("one == ['b', 'd']", parser='pandas')

Uwaga
Tak, domyślnym parserem jest 'pandas', ale ważne jest, aby wyróżnić ta składnia nie jest konwencjonalnie Pythonem. Na Pandy parser generuje nieco inne drzewo Parsów od ekspresja. Ma to na celu uczynienie niektórych operacji bardziej intuicyjnymi do sprecyzuj. Aby uzyskać więcej informacji, przeczytaj mój post na dynamiczna ocena ekspresji w pandach za pomocą pd.eval () .

I, z get_level_values + Index.isin:

df[df.index.get_level_values("one").isin(['b', 'd'])]

Pytanie 2b

Jak uzyskać wszystkie wartości odpowiadające" t "i" w " w poziomie "dwa"?

         col
one two     
a   t      0
    w      3
b   t      4
    w      7
    t      8
d   w     11
    t     12
    w     15

Z loc, jest to możliwe tylko w połączeniu z pd.IndexSlice.

df.loc[pd.IndexSlice[:, ['t', 'w']], :] 

Pierwszy dwukropek : w pd.IndexSlice[:, ['t', 'w']] oznacza przecięcie pierwszego poziomu. Wraz ze wzrostem głębokości pytanego poziomu, będziesz musiał podać więcej plasterków, po jednym na każdy poziom. Nie musisz jednak podawać więcej poziomów poza ten, który jest pokrojony.

Z query, to jest

items = ['t', 'w']
df.query("two in @items")
# df.query("two == @items", parser='pandas') 
# df.query("two in ['t', 'w']")
# df.query("two == ['t', 'w']", parser='pandas')

Z get_level_values i Index.isin (podobnie jak wyżej):

df[df.index.get_level_values('two').isin(['t', 'w'])]

Pytanie 3

Jak odzyskać przekrój, czyli pojedynczy wiersz o określonej wartości dla indeksu z df? Konkretnie, jak odzyskać krzyż sekcja ('c', 'u'), podana przez

         col
one two     
c   u      9

Użyj loc przez podanie krotki kluczy:

df.loc[('c', 'u'), :]

Lub,

df.loc[pd.IndexSlice[('c', 'u')]]

Uwaga
W tym momencie możesz natknąć się na PerformanceWarning to wygląda tak:

PerformanceWarning: indexing past lexsort depth may impact performance.

To oznacza, że Twój indeks nie jest posortowany. pandy zależą od sortowania indeksu (w tym przypadku leksykograficznie, ponieważ mamy do czynienia z wartościami ciągów) w celu optymalnego wyszukiwania i wyszukiwania. Szybkim rozwiązaniem byłoby posortowanie DataFrame z góry za pomocą DataFrame.sort_index. Jest to szczególnie pożądane z punktu widzenia wydajności, jeśli planujesz robić wiele takich zapytań w tandemie:

df_sort = df.sort_index()
df_sort.loc[('c', 'u')]

Możesz również użyć MultiIndex.is_lexsorted() aby sprawdzić, czy indeks jest uporządkowane czy nie. Funkcja zwraca odpowiednio True lub False. Można wywołać tę funkcję, aby określić, czy dodatkowe sortowanie krok jest wymagany lub nie.

Jest to pierwszy argument, w którym wszystkie pozostałe argumenty są ustawione na odpowiednie wartości domyślne:]}
df.xs(('c', 'u'))

Z query, rzeczy stają się nieco niezgrabne:

df.query("one == 'c' and two == 'u'")

Widzisz teraz, że będzie to stosunkowo trudne do uogólnienia. Ale nadal jest OK dla tego konkretnego problemu.

Z dostępami na wielu poziomach można nadal korzystać, ale nie jest to zalecane:]}
m1 = (df.index.get_level_values('one') == 'c')
m2 = (df.index.get_level_values('two') == 'u')
df[m1 & m2]

Pytanie 4

Jak wybrać dwa wiersze odpowiadające ('c', 'u') i ('a', 'w')?

         col
one two     
c   u      9
a   w      3

Z loc, to jest jeszcze tak proste jak:

df.loc[[('c', 'u'), ('a', 'w')]]
# df.loc[pd.IndexSlice[[('c', 'u'), ('a', 'w')]]]

Z query, będziesz musiał dynamicznie wygenerować ciąg zapytania przez iterowanie nad przekrojami i poziomami:

cses = [('c', 'u'), ('a', 'w')]
levels = ['one', 'two']
# This is a useful check to make in advance.
assert all(len(levels) == len(cs) for cs in cses) 

query = '(' + ') or ('.join([
    ' and '.join([f"({l} == {repr(c)})" for l, c in zip(levels, cs)]) 
    for cs in cses
]) + ')'

print(query)
# ((one == 'c') and (two == 'u')) or ((one == 'a') and (two == 'w'))

df.query(query)

W 100% NIE POLECAM! Ale to możliwe.

Co zrobić, jeśli mam wiele poziomów?
Jedną z opcji w tym scenariuszu byłoby użycie droplevel aby upuścić poziomy, których nie sprawdzasz, użyj isin aby przetestować członkostwo, a następnie indeks boolean na wynik końcowy.

df[df.index.droplevel(unused_level).isin([('c', 'u'), ('a', 'w')])]

Pytanie 5

Jak mogę odzyskać wszystkie wiersze odpowiadające " a " w poziomie "jeden" lub "t" na poziomie "2"?

         col
one two     
a   t      0
    u      1
    v      2
    w      3
b   t      4
    t      8
d   t     12

Jest to w rzeczywistości bardzo trudne do zrobienia z loc przy jednoczesnym zapewnieniu poprawności i przy zachowaniu przejrzystości kodu. df.loc[pd.IndexSlice['a', 't']] jest niepoprawne, interpretuje się je jako df.loc[pd.IndexSlice[('a', 't')]] (tzn. wybierając przekrój). Można pomyśleć o rozwiązaniu z pd.concat do obsługi każdej etykiety osobno:

pd.concat([
    df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])

         col
one two     
a   t      0
    u      1
    v      2
    w      3
    t      0   # Does this look right to you? No, it isn't!
b   t      4
    t      8
d   t     12

Ale zauważysz, że jeden z wierszy jest duplikowany. Rząd ten spełniał bowiem oba warunki krojenia i tak pojawił się dwukrotnie. Zamiast tego będziesz musiał zrobić

v = pd.concat([
        df.loc[['a'],:], df.loc[pd.IndexSlice[:, 't'],:]
])
v[~v.index.duplicated()]

Ale jeśli ramka danych z natury zawiera zduplikowane indeksy( które chcesz), to nie zachowa ich. stosować z najwyższą ostrożnością.

Z query, to jest głupio proste:

df.query("one == 'a' or two == 't'")

Z get_level_values, to nadal proste, ale nie tak eleganckie:

m1 = (df.index.get_level_values('one') == 'a')
m2 = (df.index.get_level_values('two') == 't')
df[m1 | m2] 

Pytanie 6

Jak pokroić konkretne przekroje? Dla "a" i " b "chciałbym wybrać wszystkie wiersze z podpoziomami" u" i "v", oraz dla "d" chciałbym wybrać wiersze z podpoziomem "w".

         col
one two     
a   u      1
    v      2
b   u      5
    v      6
d   w     11
    w     15

Jest to szczególny przypadek, który dodałem, aby pomóc zrozumieć przydatność czterech idiomów-jest to jeden przypadek, w którym żaden z nich nie będzie działał skutecznie, ponieważ krojenie jest {169]}bardzo {172]} specyficzne i nie podąża za żadnym prawdziwym wzorcem.

Zazwyczaj takie problemy wymagają jawnego przekazania listy kluczy do loc. Jednym ze sposobów jest z:

keys = [('a', 'u'), ('a', 'v'), ('b', 'u'), ('b', 'v'), ('d', 'w')]
df.loc[keys, :]

Jeśli chcesz zachować trochę pisania, rozpoznasz, że istnieje wzór do krojenia "a", " b " i jego podpoziomów, więc możemy rozdzielić zadanie krojenia na dwie części i concat wynik:

pd.concat([
     df.loc[(('a', 'b'), ('u', 'v')), :], 
     df.loc[('d', 'w'), :]
   ], axis=0)

Specyfikacja krojenia dla "a" i "b" jest nieco czystsza (('a', 'b'), ('u', 'v')), ponieważ te same poziomy indeksowane są takie same dla każdego poziomu.


Pytanie 7

Jak uzyskać wszystkie wiersze, w których wartości na poziomie "dwa" są większe niż 5?

         col
one two     
b   7      4
    9      5
c   7     10
d   6     11
    8     12
    8     13
    6     15

Można to zrobić za pomocą query,

df2.query("two > 5")

I get_level_values.

df2[df2.index.get_level_values('two') > 5]

Uwaga
Podobnie jak w tym przykładzie, możemy filtrować na podstawie dowolnego warunku za pomocą tych konstrukcji. Ogólnie rzecz biorąc, warto pamiętać, że loc i xs są specjalnie przeznaczone do indeksowania opartego na etykietach, podczas gdy query i get_level_values są pomocne w budowaniu ogólnych masek warunkowych do filtrowania.


Bonus Pytanie

Co jeśli będę musiał pokroić MultiIndex kolumna ?

Właściwie, większość rozwiązań tutaj stosuje się również do kolumn, z niewielkimi zmianami. Rozważyć:

np.random.seed(0)
mux3 = pd.MultiIndex.from_product([
        list('ABCD'), list('efgh')
], names=['one','two'])

df3 = pd.DataFrame(np.random.choice(10, (3, len(mux))), columns=mux3)
print(df3)

one  A           B           C           D         
two  e  f  g  h  e  f  g  h  e  f  g  h  e  f  g  h
0    5  0  3  3  7  9  3  5  2  4  7  6  8  8  1  6
1    7  7  8  1  5  9  8  9  4  3  0  3  5  0  2  3
2    8  1  3  3  3  7  0  1  9  9  0  4  7  3  2  7

Są to następujące zmiany, które musisz wprowadzić do czterech idiomów, aby mogły pracować z kolumnami.

  1. Aby pokroić z loc, użyj

     df3.loc[:, ....] # Notice how we slice across the index with `:`. 
    

    Lub,

     df3.loc[:, pd.IndexSlice[...]]
    
  2. Aby użyć xs, wystarczy podać argument axis=1.

  3. Możesz uzyskać dostęp do wartości poziomu kolumn bezpośrednio za pomocą df.columns.get_level_values. Następnie będziesz musiał zrobić coś takiego jak

     df.loc[:, {condition}] 
    

    Gdzie {condition} reprezentuje pewien warunek zbudowany przy użyciu columns.get_level_values.

  4. Aby użyć query, jedyną opcją jest transpozycja, Zapytanie o indeks i transpozycja ponownie:

     df3.T.query(...).T
    

    Nie zaleca się, użyj jednej z pozostałych 3 opcji.

 223
Author: cs95,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-10-26 11:27:15

Ostatnio natknąłem się na przypadek użycia, w którym miałem wielopoziomową ramkę danych 3+, w której nie mogłem sprawić, by żadne z powyższych rozwiązań przyniosło wyniki, których szukałem. Jest całkiem możliwe, że powyższe rozwiązania oczywiście działają w moim przypadku użycia, a ja próbowałem kilku, jednak nie byłem w stanie zmusić ich do pracy z czasem, który miałem dostępny.

Jestem daleki od eksperta, ale natknąłem się na rozwiązanie, które nie było wymienione w wyczerpujących odpowiedziach powyżej. Nie gwarantuję, że rozwiązania są w jakikolwiek sposób optymalne.

Jest to inny sposób na uzyskanie nieco innego wyniku niż pytanie # 6 powyżej. (i prawdopodobnie również inne pytania)

Konkretnie szukałam:

  1. sposób wyboru dwóch + wartości z jednego poziomu indeksu i jednej wartości z innego poziomu indeksu oraz
  2. sposób na pozostawienie wartości indeksu z poprzedniej operacji na wyjściu ramki danych.

Jako Małpi klucz w zębatkach (jednak całkowicie naprawialny):

  1. indeksy były nienazwane.

Na ramce danych zabawki poniżej:

    index = pd.MultiIndex.from_product([['a','b'],
                               ['stock1','stock2','stock3'],
                               ['price','volume','velocity']])

    df = pd.DataFrame([1,2,3,4,5,6,7,8,9,
                      10,11,12,13,14,15,16,17,18], 
                       index)

                        0
    a stock1 price      1
             volume     2
             velocity   3
      stock2 price      4
             volume     5
             velocity   6
      stock3 price      7
             volume     8
             velocity   9
    b stock1 price     10
             volume    11
             velocity  12
      stock2 price     13
             volume    14
             velocity  15
      stock3 price     16
             volume    17
             velocity  18

Korzystanie z poniższych prac, oczywiście:

    df.xs(('stock1', 'velocity'), level=(1,2))

        0
    a   3
    b  12

Ale chciałem inny wynik, więc moja metoda, aby uzyskać ten wynik była:

   df.iloc[df.index.isin(['stock1'], level=1) & 
           df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
    b stock1 velocity  12

I gdybym chciał dwie wartości+ z jednego poziomu i jedną (lub 2+) wartość z innego poziomu:

    df.iloc[df.index.isin(['stock1','stock3'], level=1) & 
            df.index.isin(['velocity'], level=2)] 

                        0
    a stock1 velocity   3
      stock3 velocity   9
    b stock1 velocity  12
      stock3 velocity  18

Powyższa metoda jest prawdopodobnie trochę niezgrabna, jednak okazało się, że spełnia moje potrzeby i jako bonus było mi łatwiej zrozumieć i czytać.

 8
Author: r a,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-11-04 10:38:57