Изменение многоиндексной метки второго уровня при выполнении условия первого уровня

#python #pandas #multi-index

Вопрос:

У меня есть многоиндексный df с двумя уровнями индекса, такими как этот:

     dfx = pd.DataFrame(np.random.rand(4, 2),
                  index=[['a', 'a', 'b', 'b'], ['aa', 'zz', 'gg', 'zz']],
                  columns=['data1', 'data2'])
    dfx

         data1     data2
a aa  0.847741  0.723235
  zz  0.236876  0.343141
b gg  0.759153  0.546190
  zz  0.481285  0.600514

 

Я хочу изменить метки индексов только там, где индекс первого уровня имеет определенное значение. т. Е. Изменить индекс zz только там, где первая метка b

 Objective, get:

         data1     data2
a aa    0.847741  0.723235
  zz    0.236876  0.343141
b gg    0.759153  0.546190
  water 0.481285  0.600514

 

Если я использую .rename() все соответствующие индексы, они будут изменены

 dfx.rename(index={('zz') : 'water'}, inplace = True)
dfx

            data1     data2
a aa     0.847741  0.723235
  water  0.236876  0.343141
b gg     0.759153  0.546190
  water  0.481285  0.600514

 

Я попробовал следующие строки кода, но это, похоже, ничего не дает.

 dfx.loc['b','zz'].rename(index={'zz' : 'water'}, inplace = True)
 
 dfx.loc['b'].rename(index={'zz' : 'water'},  inplace = True)
 

Я ознакомился с документацией и изо всех сил пытался найти решение.
Что я здесь делаю не так?

Комментарии:

1. вы не передаете level параметр: dfx=dfx.rename(index={'zz' : 'water'},level=1)

2. Это не решает проблему. Мне нужно изменить » zz » на «вода» только там, где индекс первого уровня равен b.

Ответ №1:

Мы можем использовать MultiIndex.map

 d = {('b', 'zz'): ('b', 'water')}
dfx.index = dfx.index.map(lambda i: d.get(i, i))
 

             data1     data2
a aa     0.567847  0.844618
  zz     0.752874  0.794704
b gg     0.854358  0.512400
  water  0.237905  0.211369
 

Комментарии:

1. Это лучший рабочий метод, так как он легко позволяет мне добавлять другие потенциальные замены, которые обязательно возникнут на этом пути. Я просто добавляю это в d.

Ответ №2:

Вы можете попробовать через pd.MultiIndex.from_tuples() понимание списка:

 dfx.index=pd.MultiIndex.from_tuples(
        [(x,y) if (x,y)!=('b','zz') else ('b','water') for x,y in dfx.index]
                                    )
 

или

Другой способ сбросить индекс затем проверить значения и изменить их а затем установить индекс обратно:

 dfx=dfx.reset_index()
dfx.loc[(dfx['level_0'].eq('b') amp; dfx['level_1'].eq('zz')),'level_1']='water'
dfx=dfx.set_index(['level_0','level_1']).rename_axis(index=[None,None])
 

Комментарии:

1. Это тоже работает, однако я бы предпочел не сбрасывать индекс как часть моего предыдущего кода, и при споре о данных происходит многократный сброс индекса. Я не уточнял этого раньше и не думал об этом до тех пор, пока не увидел ваш ответ. Но спасибо за ответ!.

Ответ №3:

Еще один подобный способ:

1. Создайте фрейм данных из мультииндекса

2: условное присвоение значений

3. Вернитесь к мультииндексации и назначьте:

 d = pd.DataFrame(dfx.index.tolist())
d.loc[d[0].eq("b")amp;d[1].eq("zz"),1]='water'
dfx.index = pd.MultiIndex.from_frame(d,names=[None,None])