4

I am trying to use the replace method several times in order to change the indeces of a given level of a multiindex pandas' dataframe.

As seen here: Pandas: Modify a particular level of Multiindex, @John got a solution that works great so long the replace method is used once.

The problem is, that it does not work if I use this method several times. E.g.

df.index = df.index.set_levels(df.index.levels[0].str.replace("dataframe_",'').replace("_r",' r'), level=0)

I get the following error message:

AttributeError: 'Index' object has no attribute 'replace'

What am I missing?

rubebop
  • 392
  • 1
  • 7
  • 17

1 Answers1

6

Use str.replace twice:

idx = df.index.levels[0].str.replace("dataframe_",'').str.replace("_r",' r')
df.index = df.index.set_levels(idx, level=0)

Another solution is converting to_series and then replace by dictionary:

d = {'dataframe_':'','_r':' r'}
idx = df.index.levels[0].to_series().replace(d)
df.index = df.index.set_levels(idx, level=0)

And solution with map and fillna, if large data and performance is important:

d = {'dataframe_':'','_r':' r'}
s = df.index.levels[0].to_series()
df.index = df.index.set_levels(s.map(d).fillna(s), level=0)

Sample:

df = pd.DataFrame({
        'A':['dataframe_','_r', 'a'],
        'B':[7,8,9],
        'C':[1,3,5],

}).set_index(['A','B'])

print (df)
              C
A          B   
dataframe_ 7  1
_r         8  3
a          9  5

d = {'dataframe_':'','_r':' r'}
idx = df.index.levels[0].to_series().replace(d)
df.index = df.index.set_levels(idx, level=0)
print (df)
      C
A  B   
   7  1
 r 8  3
a  9  5
jezrael
  • 822,522
  • 95
  • 1,334
  • 1,252
  • Thanks a lot for your great and extensive answer! A learnt very useful stuff, and pardon my stupid initial question, as I missed that ".str" before the second replace method. – rubebop Nov 08 '18 at 15:43
  • 1
    I accepted it: sorry, I am rather new at this and was not aware about this feature. Thanks again! :) – rubebop Nov 09 '18 at 13:35
  • 1
    `map` soln works for multiple levels too, and also with level names: `df.index = df.index.set_levels((s1.map(d1).fillna(s1), s2.map(d2).fillna(s2)), level=('lev1', 'lev2'))` – fantabolous May 07 '23 at 23:35