web-dev-qa-db-fra.com

Pandas: moyen approprié de définir des valeurs en fonction de la condition pour un sous-ensemble de données multi-index

Je ne sais pas comment faire cela sans les affectations enchaînées (qui ne fonctionneraient probablement pas de toute façon parce que je définirais une copie).

Je ne veux pas prendre un sous-ensemble d'un multiindex pandas dataframe, tester des valeurs inférieures à zéro et les mettre à zéro.

Par exemple:

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

donne

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

Ce qui montre qu'il n'a pas pu être réglé en fonction de la condition. Alternativement, si j'ai fait une affectation en chaîne:

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

Cela donne le même résultat (et réglage avec avertissement de copie)

Je pourrais parcourir chaque colonne en fonction de la condition que le premier niveau soit celui que je veux:

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

ce qui donne le résultat souhaité:

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

Mais d'une certaine manière, je pense qu'il y a une meilleure façon de le faire que de parcourir les colonnes. Quelle est la meilleure façon de le faire chez les pandas?

17
pbreach

Ceci est une application de (et l'une des principales motivations pour utiliser des trancheuses MultiIndex), voir les documents ici

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

Puisque vous travaillez avec le 1er niveau de l'index des colonnes, ce qui suit fonctionnera également. L'exemple ci-dessus est plus général, disons que vous vouliez le faire pour "a".

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
17
Jeff