2017-02-15 5 views
2

Я искал this post, что почти решило мою проблему. Однако в моем случае я хочу работать на основе 2-го уровня df, но пытаюсь не указывать имена столбцов 1-го уровня явно.Замена значений в столбце второго уровня на MultiIndex df в Pandas

Заимствование оригинальный dataframe:

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

Я хочу, чтобы назначить NA ко всем столбцам a и b где b<0. Я выбирал их на основе: df.xs('b',axis=1,level=1)<b, но тогда я не могу выполнить замену. Тем не менее, у меня есть разные имена 1-го уровня, поэтому индексация там не может быть сделана на основе A и B явно, но возможно через df.columns.values?

Нужный результат будет

##df 
    A B 
    a b a b 
0 -1 0 NA NA 
1 -1 1 NA NA 
2 0 2 0 0 
3 10 3 10 100 
4 NA NA 20 200 

Я ценю все советы, спасибо заранее.

ответ

2

Вы можете использовать DataFrame.mask с reindex для тех же индексов и имена столбцов в качестве исходной DataFrame созданных reindex:

mask = df.xs('b',axis=1,level=1) < 0 
print (mask) 
     A  B 
0 False True 
1 False True 
2 False False 
3 False False 
4 True False 

print (mask.reindex(columns = df.columns, level=0)) 
     A    B  
     a  b  a  b 
0 False False True True 
1 False False True True 
2 False False False False 
3 False False False False 
4 True True False False 

df = df.mask(mask.reindex(columns = df.columns, level=0)) 
print (df) 
     A   B  
     a b  a  b 
0 -1.0 0.0 NaN NaN 
1 -1.0 1.0 NaN NaN 
2 0.0 2.0 0.0 0.0 
3 10.0 3.0 10.0 100.0 
4 NaN NaN 20.0 200.0 

Редактировать О.П.: Я спросил в комментариях, как рассмотреть несколько условий (например, df.xs('b',axis=1,level=1) < 0 ИЛИ df.xs('b',axis=1,level=1) является NA). @Jezrael любезно указал, что если бы я хотел это сделать, я должен рассмотреть

mask=(df.xs('b',axis=1,level=1) < 0 | df.xs('b',axis=1,level=1).isnull()) 
+1

изменить 'или' на '|' то это работает. – jezrael

+1

@Sosi - спасибо за редактирование. – jezrael