我有一个MultiIndex
版本的DataFrame,其中包含以下国家/地区的代码:
In [3]: idx = pd.MultiIndex.from_tuples([('AUS', 'a'), ('AUS', 'b'), ('BRA', 'a')])
In [4]: idx.names = ['country', 'foo']
In [5]: df = pd.DataFrame([4,5,6], index=idx)
In [6]: df
Out[6]:
0
country foo
AUS a 4
b 5
BRA a 6
我还有一个带有值的字典,用以下代码替换我的代码:
In [7]: codes = dict(AUS='Australia', BRA='Brazil')
我想做相当于df.replace(codes)
但是在索引级别上(无论是所有级别,还是特定级别,我都不介意)
输出如下:
0
country foo
Australia a 4
b 5
Brazil a 6
我目前正以非常愚蠢的方式做这件事:
In [21]: replaced = [pd.Series(df.index.get_level_values(i)).replace(codes) for i in range(len(df.index.levels))]
In [22]: replaced_tuples = zip(*replaced)
In [23]: new_idx = pd.MultiIndex.from_tuples(replaced_tuples)
In [27]: df_replaced = pd.DataFrame(df.values, index=new_idx)
In [28]: df_replaced
Out[28]:
0
Australia a 4
b 5
Brazil a 6
面对我的那种更好的方式是什么? (请注意,此方法甚至不保留级别名称,因此它是全面坏的。)
答案 0 :(得分:2)
您可以在多索引上调用set_levels
并传递新名称,您必须创建一个与您的级别名称相同的列表,因为这不保证顺序:
In [380]:
country_code_list = [codes[x] for x in df.index.get_level_values(0).unique()]
df.index.set_levels(country_code_list, level='country', inplace=True)
df
Out[380]:
0
country foo
Australia a 4
b 5
Brazil a 6
答案 1 :(得分:0)
这是一种看似合理的方式。不确定如何将效率/可读性与@ EdChum的回答进行比较:
In [46]: df.reset_index().replace(codes).set_index(df.index.names)
Out[46]:
0
country foo
Australia a 4
b 5
Brazil a 6
显然,这里的缺点是replace
将在DataFrame
中替换,而不仅仅在索引列中。
从好的方面来说,这样做可以像正则表达式一样访问replace
的所有功能。
如果您真的关心仅在中替换索引,您可以执行以下任一操作:
codes_dict = dict(country=codes)
或
codes_dict = {k: codes for k in df.index.names}
然后在codes
的调用中最后更改codes_dict
的{{1}}。完美!