2016-03-20 2 views
4

У меня есть dataframe с мультииндекс. Я хочу изменить значение второго индекса при выполнении определенных условий для первого индекса. Я нашел аналогичный (но другой) вопрос здесь: Replace a value in MultiIndex (pandas) , который не отвечает моей точке, потому что речь шла об изменении одной строки, и решение передало значение первого индекса (который тоже не нуждался в изменении) тоже , В моем случае я имею дело с несколькими строками, и я не смог адаптировать это решение к моему делу.Замена значений в мультииндексе pandas

Ниже приведен минимальный пример моих данных. Благодаря!

import pandas as pd 
import numpy as np 

consdf=pd.DataFrame() 

for mylocation in ['North','South']: 
    for scenario in np.arange(1,4): 
     df= pd.DataFrame() 
     df['mylocation'] = [mylocation] 
     df['scenario']= [scenario] 
     df['this'] = np.random.randint(10,100) 
     df['that'] = df['this'] * 2 
     df['something else'] = df['this'] * 3 
     consdf=pd.concat((consdf, df), axis=0, ignore_index=True) 

mypiv = consdf.pivot('mylocation','scenario').transpose() 

level_list =['this','that'] 
# if level 0 is in level_list --> set level 1 to np.nan 
mypiv.iloc[mypiv.index.get_level_values(0).isin(level_list)].index.set_levels([np.nan], level =1, inplace=True) 

Последняя строка не работает: я получаю:

ValueError: On level 1, label max (2) >= length of level (1). NOTE: this index is in an inconsistent state 
+0

было бы вариантом для сброса индекса или вы хотите его сохранить? – MaxU

+0

Я бы хотел его сохранить. Могу я, возможно, сбросить его, а затем добавить его обратно? –

+0

Вместо 'mypiv.iloc [mypiv.index.get_level_values ​​(0) .isin (level_list)]' вы можете использовать 'mypiv.loc [(level_list,)]'. –

ответ

0

Вот решение, используя reset_index() метод:

In [95]: new = mypiv.reset_index() 

In [96]: new 
Out[96]: 
mylocation   level_0 scenario North South 
0      this   1  32  64 
1      this   2  18  40 
2      this   3  76  56 
3      that   1  64 128 
4      that   2  36  80 
5      that   3 152 112 
6   something else   1  96 192 
7   something else   2  54 120 
8   something else   3 228 168 

In [100]: new.ix[new.level_0.isin(level_list), 'scenario'] = np.nan 

In [101]: new 
Out[101]: 
mylocation   level_0 scenario North South 
0      this  NaN  32  64 
1      this  NaN  18  40 
2      this  NaN  76  56 
3      that  NaN  64 128 
4      that  NaN  36  80 
5      that  NaN 152 112 
6   something else  1.0  96 192 
7   something else  2.0  54 120 
8   something else  3.0 228 168 

In [103]: mypiv = new.set_index(['level_0', 'scenario']) 

In [104]: mypiv 
Out[104]: 
mylocation    North South 
level_0  scenario 
this   NaN   32  64 
       NaN   18  40 
       NaN   76  56 
that   NaN   64 128 
       NaN   36  80 
       NaN   152 112 
something else 1.0   96 192 
       2.0   54 120 
       3.0   228 168 

Но я подозреваю, что есть более элегантное решение ,

1

IIUC можно добавить новое значение для значений уровня, а затем изменить метки для индекса, используя advanced indexing, get_level_values, set_levels и set_labels методы:

len_ind = len(mypiv.loc[(level_list,)].index.get_level_values(1)) 
mypiv.index.set_levels([1, 2, 3, np.nan], level=1, inplace=True) 
mypiv.index.set_labels([3]*len_ind + mypiv.index.labels[1][len_ind:].tolist(), level=1, inplace=True) 

In [219]: mypiv 
Out[219]: 
mylocation    North South 
       scenario    
this   NaN   26  46 
       NaN   32  67 
       NaN   75  30 
that   NaN   52  92 
       NaN   64 134 
       NaN   150  60 
something else 1.0   78 138 
       2.0   96 201 
       3.0  225  90 

Примечание Вы значения для других scenario будет конвертировать в float, потому что он должен быть одного типа, а np.nan имеет тип float.

Смежные вопросы