重命名 Pandas 中的多索引列
- 2025-04-17 09:02:00
- admin 原创
- 18
问题描述:
df = pd.DataFrame([[1,2,3], [10,20,30], [100,200,300]])
df.columns = pd.MultiIndex.from_tuples((("a", "b"), ("a", "c"), ("d", "f")))
df
返回
a d
b c f
0 1 2 3
1 10 20 30
2 100 200 300
和
df.columns.levels[1]
返回
Index([u'b', u'c', u'f'], dtype='object')
我想重命名"f"
为"e"
。根据pandas.MultiIndex.rename
我运行:
df.columns.rename(["b1", "c1", "f1"], level=1)
但它提出了
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-110-b171a2b5706c> in <module>()
----> 1 df.columns.rename(["b1", "c1", "f1"], level=1)
C:UsersUSERNAMEAppDataLocalContinuumMiniconda2libsite-packagespandasindexesase.pyc in set_names(self, names, level, inplace)
994 if level is not None and not is_list_like(level) and is_list_like(
995 names):
--> 996 raise TypeError("Names must be a string")
997
998 if not is_list_like(names) and level is None and self.nlevels > 1:
TypeError: Names must be a string
我使用Python 2.7.12 |Continuum Analytics, Inc.| (default, Jun 29 2016, 11:07:13) [MSC v.1500 64 bit (AMD64)]'
和pandas 0.19.1
解决方案 1:
使用set_levels
:
In [22]:
df.columns.set_levels(['b1','c1','f1'],level=1,inplace=True)
df
Out[22]:
a d
b1 c1 f1
0 1 2 3
1 10 20 30
2 100 200 300
rename
设置索引的名称,它不会重命名列名:
In [26]:
df.columns = df.columns.rename("b1", level=1)
df
Out[26]:
a d
b1 b c f
0 1 2 3
1 10 20 30
2 100 200 300
这就是你收到错误的原因
解决方案 2:
在 Pandas 中0.21.0+
使用参数level=1
:
d = dict(zip(df.columns.levels[1], ["b1", "c1", "f1"]))
print (d)
{'c': 'c1', 'b': 'b1', 'f': 'f1'}
df = df.rename(columns=d, level=1)
print (df)
a d
b1 c1 f1
0 1 2 3
1 10 20 30
2 100 200 300
解决方案 3:
您可以pandas.DataFrame.rename()
直接使用
假设您有以下数据框
print(df)
a d
b c f
0 1 2 3
1 10 20 30
2 100 200 300
df = df.rename(columns={'f': 'f1', 'd': 'd1'})
print(df)
a d1
b c f1
0 1 2 3
1 10 20 30
2 100 200 300
您会看到,列名映射器与级别无关。
假设您有以下数据框
a d
b f f
0 1 2 3
1 10 20 30
2 100 200 300
如果你想重命名f
下a
,你可以这样做
df.columns = df.columns.values
df.columns = pd.MultiIndex.from_tuples(df.rename(columns={('a', 'f'): ('a', 'af')}))
# or in one line
df.columns = pd.MultiIndex.from_tuples(df.set_axis(df.columns.values, axis=1)
.rename(columns={('a', 'f'): ('a', 'af')}))
print(df)
a d
b af f
0 1 2 3
1 10 20 30
2 100 200 300
解决方案 4:
还有(代码)index.set_names
df.index.set_names(["b1", "c1", "f1"], inplace=True)
解决方案 5:
另一件你不能做的事情是
df.rename(columns={('d', 'f'): ('e', 'g')})
,即使它看起来正确。换句话说:.rename()
没有达到预期的效果,<...>——Lukas评论道
“hacky” 的方式是这样的(就 pandas 1.0.5 而言)
def rename_columns(df, columns, inplace=False):
"""Rename dataframe columns.
Parameters
----------
df : pandas.DataFrame
Dataframe.
columns : dict-like
Alternative to specifying axis. If `df.columns` is
:obj: `pandas.MultiIndex`-object and has a few levels, pass equal-size tuples.
Returns
-------
pandas.DataFrame or None
Returns dataframe with modifed columns or ``None`` (depends on `inplace` parameter value).
Examples
--------
>>> columns = pd.Index([1, 2, 3])
>>> df = pd.DataFrame([[1, 2, 3], [10, 20, 30]], columns=columns)
... 1 2 3
... 0 1 2 3
... 1 10 20 30
>>> rename_columns(df, columns={1 : 10})
... 10 2 3
... 0 1 2 3
... 1 10 20 30
MultiIndex
>>> columns = pd.MultiIndex.from_tuples([("A0", "B0", "C0"), ("A1", "B1", "C1"), ("A2", "B2", "")])
>>> df = pd.DataFrame([[1, 2, 3], [10, 20, 30]], columns=columns)
>>> df
... A0 A1 A2
... B0 B1 B2
... C0 C1
... 0 1 2 3
... 1 10 20 30
>>> rename_columns(df, columns={("A2", "B2", "") : ("A3", "B3", "")})
... A0 A1 A3
... B0 B1 B3
... C0 C1
... 0 1 2 3
... 1 10 20 30
"""
columns_new = []
for col in df.columns.values:
if col in columns:
columns_new.append(columns[col])
else:
columns_new.append(col)
columns_new = pd.Index(columns_new, tupleize_cols=True)
if inplace:
df.columns = columns_new
else:
df_new = df.copy()
df_new.columns = columns_new
return df_new
所以只是
>>> df = pd.DataFrame([[1,2,3], [10,20,30], [100,200,300]])
>>> df.columns = pd.MultiIndex.from_tuples((("a", "b"), ("a", "c"), ("d", "f")))
>>> rename_columns(df, columns={('d', 'f'): ('e', 'g')})
... a e
... b c g
... 0 1 2 3
... 1 10 20 30
... 2 100 200 300
pandas 团队对此有何看法?为什么这种行为不是默认行为?
解决方案 6:
另一种方法是使用pandas.Series.map
lambda 函数,如下所示
df.columns = df.columns.map(lambda x: (x[0], "e") if x[1] == "f" else x)
[Out]:
a d
b c e
0 1 2 3
1 10 20 30
2 100 200 300
解决方案 7:
使用字典重命名元组
由于多索引将值存储为元组,并且 python dicts 接受元组作为键和值,因此我们可以使用 dict 替换它们。
mapping_dict = {("d","f"):("d","e")}
# Dictionary allows using tuples as keys and values
def rename_tuple(tuple_, dict_):
"""Replaces tuple if present in tuple dict"""
if tuple_ in dict_.keys():
return dict_[tuple_]
return tuple_
# Rename chosen elements from list of tuples from df.columns
altered_index_list = [rename_tuple(tuple_,mapping_dict) for tuple_ in df.columns.to_list()]
# Update columns with new renamed columns
df.columns = pd.Index(altered_index_list)
返回预期的 df
a d
b c e
0 1 2 3
1 10 20 30
2 100 200 300
在函数中进行聚合
然后可以将其聚合到一个函数中以简化事情
def rename_multi_index(index,mapper):
"""Renames pandas multi_index"""
return pd.Index([rename_tuple(tuple_,mapper) for tuple_ in index])
# And now simply do
df.columns = rename_multi_index(df.columns,mapping_dict)
相关推荐
热门文章
项目管理软件有哪些?
热门标签
曾咪二维码
扫码咨询,免费领取项目管理大礼包!
云禅道AD