2016-08-22 3 views
2

Gibt es eine Möglichkeit, das Ergebnis get_level_values für mehr als eine Spalte zu erhalten?pandas get_level_values ​​für mehrere Spalten

Angesichts der folgenden DataFrame:

  d 
a b c  
1 4 10 16 
    11 17 
    5 12 18 
2 5 13 19 
    6 14 20 
3 7 15 21 

Ich möchte die Werte erhalten (dh Liste von Tupeln) der Ebenen a und c:

[(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 

Hinweise:

  • Es ist unmöglich, get_level_values mehr als eine Ebene anzugeben (z.df.index.get_level_values(['a','c'])

  • Es gibt eine Abhilfe, in das man sich get_level_values über jede gewünschte Spalte und zip gemeinsam nutzen könnte:

Zum Beispiel:

a_list = df.index.get_level_values('a').values 
c_list = df.index.get_level_values('c').values 

print([i for i in zip(a_list,c_list)]) 
[(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 

aber es bekommt umständlich als die Anzahl von Spalten wachsen.

  • Der Code am Beispiel DataFrame zu bauen:

df = pd.DataFrame({'a':[1,1,1,2,2,3],'b':[4,4,5,5,6,7,],'c':[10,11,12,13,14,15], 'd':[16,17,18,19,20,21]}).set_index(['a','b','c'])

Antwort

3

Die .tolist() Methode eines MultiIndex gibt eine Liste von Tupeln für alle Ebenen in der MultiIndex. Zum Beispiel mit Ihrem Beispiel DataFrame,

df.index.tolist() 
# => [(1, 4, 10), (1, 4, 11), (1, 5, 12), (2, 5, 13), (2, 6, 14), (3, 7, 15)] 

hier sind also zwei Ideen:

  1. die Liste von Tupeln aus den ursprünglichen MultiIndex Holen und das Ergebnis filtern.

    [(a, c) for a, b, c in df.index.tolist()] 
    # => [(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 
    

    Der Nachteil dieser einfachen Methode ist, dass Sie manuell die Reihenfolge der Ebenen, die Sie wollen angeben. Sie können itertools.compress verwenden, um sie stattdessen anhand des Namens auszuwählen.

    from itertools import compress 
    
    mask = [1 if name in ['a', 'c'] else 0 for name in df.index.names] 
    [tuple(compress(t, mask)) for t in df.index.tolist()] 
    # => [(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 
    
  2. einen Multiindex erstellen, die genau die Ebene haben Sie wollen und .tolist() auf es nennen.

    df.index.droplevel('b').tolist() 
    # => [(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 
    

    Wenn Sie lieber die Ebenen Sie — statt diejenigen halten wollen nennen, die Sie wollen — fallen könnten Sie so etwas wie

    df.index.droplevel([level for level in df.index.names 
           if not level in ['a', 'c']]).tolist() 
    # => [(1, 10), (1, 11), (1, 12), (2, 13), (2, 14), (3, 15)] 
    
+0

Nizza Verwendung von 'droplevel' tun in der letzte Fall :) – IanS

0

Dies ist weniger umständlich, soweit Sie die Liste der Indexnamen weitergeben können Sie auswählen möchten:

df.reset_index()[['a', 'c']].to_dict(orient='split')['data'] 

Ich habe keine Möglichkeit gefunden, die Ebenen 'a' und 'b' aus dem Index auszuwählen Objekt direkt, daher die Verwendung von reset_index.

Beachten Sie, dass to_dict gibt eine Liste der Listen und nicht Tupeln:

[[1, 10], [1, 11], [1, 12], [2, 13], [2, 14], [3, 15]] 
Verwandte Themen