2015-01-17 2 views
9

Ich bin mir nicht sicher, wie dies ohne verkettete Zuweisungen funktioniert (was wahrscheinlich sowieso nicht funktionieren würde, weil ich eine Kopie erstellen würde).Pandas: Korrekte Art, Werte auf der Basis der Bedingung für eine Teilmenge von Multiindex-Datenrahmen zu setzen

Ich möchte eine Teilmenge eines Multiindex-Pandas-Datenrahmens nehmen, auf Werte kleiner als Null testen und sie auf Null setzen.

Zum Beispiel:

df = pd.DataFrame({('A','a'): [-1,-1,0,10,12], 
        ('A','b'): [0,1,2,3,-1], 
        ('B','a'): [-20,-10,0,10,20], 
        ('B','b'): [-200,-100,0,100,200]}) 

df[df['A']<0] = 0.0 

gibt

In [37]: 

df 

Out[37]: 
    A B 
    a b a b 
0 -1 0 -20 -200 
1 -1 1 -10 -100 
2 0 2 0 0 
3 10 3 10 100 
4 12 -1 20 200 

was zeigt, dass es nicht in der Lage war, unter der Bedingung, basierend einzustellen. Alternativ, wenn ich eine verkettete Zuweisung tue

df.loc[:,'A'][df['A']<0] = 0.0 

Dies ergibt das gleiche Ergebnis (und mit Kopie Warneinstellung)

Ich kann Schleife durch jede Spalte unter der Bedingung aus, dass die erste Ebene ist die, die ich wollen:

for one,two in df.columns.values: 
    if one == 'A': 
     df.loc[df[(one,two)]<0, (one,two)] = 0.0 

, die das gewünschte Ergebnis liefert:

In [64]: 

df 

Out[64]: 
    A B 
    a b a b 
0 0 0 -20 -200 
1 0 1 -10 -100 
2 0 2 0 0 
3 10 3 10 100 
4 12 0 20 200 

Aber irgendwie habe ich das Gefühl, dass es einen besseren Weg gibt, dies zu tun, als durch die Spalten zu laufen. Was ist der beste Weg, dies in Pandas zu tun?

Antwort

9

Dies ist eine Anwendung von (und einer der wichtigsten Beweggründe für Multiindex Slicer verwenden), siehe docs here

In [20]: df = pd.DataFrame({('A','a'): [-1,-1,0,10,12], 
        ('A','b'): [0,1,2,3,-1], 
        ('B','a'): [-20,-10,0,10,20], 
        ('B','b'): [-200,-100,0,100,200]}) 

In [21]: df 
Out[21]: 
    A  B  
    a b a b 
0 -1 0 -20 -200 
1 -1 1 -10 -100 
2 0 2 0 0 
3 10 3 10 100 
4 12 -1 20 200 

In [22]: idx = pd.IndexSlice 

In [23]: mask = df.loc[:,idx['A',:]]<0 

In [24]: mask 
Out[24]: 
     A  
     a  b 
0 True False 
1 True False 
2 False False 
3 False False 
4 False True 

In [25]: df[mask] = 0 

In [26]: df 
Out[26]: 
    A  B  
    a b a b 
0 0 0 -20 -200 
1 0 1 -10 -100 
2 0 2 0 0 
3 10 3 10 100 
4 12 0 20 200 

Da Sie mit der 1. Ebene des Spalten-Index arbeiten, werden die folgenden Arbeiten wie Gut. Das obige Beispiel ist allgemeiner, sagen Sie, dass Sie das für 'a' tun wollten.

In [30]: df[df[['A']]<0] = 0 

In [31]: df 
Out[31]: 
    A  B  
    a b a b 
0 0 0 -20 -200 
1 0 1 -10 -100 
2 0 2 0 0 
3 10 3 10 100 
4 12 0 20 200 
+1

Ah okay danke! Die Verwendung der Slicer zum Erstellen einer Maske sieht sehr nützlich aus (muss möglicherweise in mehr von meinem Code verwendet werden). Das zweite Beispiel löst mein spezifisches Problem. Ich war mir des Unterschieds zwischen 'df ['A'] 'und' df [['A']] 'nicht bewusst – pbreach