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?
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