GiveGet_15
GiveGet_15

Reputation: 107

Changing second level multiindex label when first level condition is met

I have a multi index df with two levels of index like this:

    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

I want to change the index labels only where the first level index has a specific value. i.e. Change the zz index only where the first label is 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

If I use .rename() all of the indexes matching get changed

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

I've tried the following code lines but this doesn't seem to do anything.

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

I consulted the documentation and I've struggled to find a solution. What am I doing wrong here?

Upvotes: 3

Views: 412

Answers (3)

anky
anky

Reputation: 75100

Another similar way:

1: Create a dataframe from the Multiindex

2: conditionally assign values

3: Turn back to Multiindex and assign:

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

Upvotes: 2

Shubham Sharma
Shubham Sharma

Reputation: 71687

We can use 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

Upvotes: 4

Anurag Dabas
Anurag Dabas

Reputation: 24314

You can try via pd.MultiIndex.from_tuples()+list comprehension:

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

OR

The other way is to reset the index then check the values and change it then set the index back:

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

Upvotes: 2

Related Questions