如何在Pandas多级列中基于查找字典为Group列赋值?
解决Pandas多级列DataFrame中根据字典映射赋值Group列的问题
首先,我们来拆解你遇到的问题核心:你的字典dict_map是组名对应成员列表的结构,但你需要的是反过来——根据成员值查找所属组名,同时还要适配Pandas的多级列结构。
问题分析
- 你最初的代码报错
TypeError: unhashable type: 'Series',是因为apply(lambda x: dict_map.get(x))里的x是Series对象,而字典的键必须是可哈希类型(比如字符串),Series无法作为键使用。 - 后来尝试的
df['Group']=df['my_ch'].apply(lambda x: dict_map.get(x))返回全None,是因为dict_map的键是group_one/group_two,而你传入的x是A/B这类成员值,自然找不到匹配项。
正确解决方案
步骤1:反转映射字典
先把dict_map从组→成员列表的结构,转换成成员→组名的结构,这样就能直接通过成员值查找组名:
reverse_map = {val: group for group, chars in dict_map.items() for val in chars}
这个字典推导式会遍历每个组的成员,生成类似{'B': 'group_one', 'A': 'group_two'}的映射。
步骤2:适配多级列结构添加Group列
你的DataFrame是多级列结构,所以添加Group列时要和现有列的层级对齐,同时调整列顺序让Group排在前面:
import pandas as pd import numpy as np # 原始定义 dict_map = dict(group_one=['B','D','GG','G'], group_two=['A','C','E','F']) arrays = [["bar", "bar", "baz", "baz", "foo", "foo", "qux", "qux"], ["one", "two", "one", "two", "one", "two", "one", "two"]] tuples = list(zip(*arrays)) index = pd.MultiIndex.from_tuples(tuples, names=["first", "second"]) df = pd.DataFrame(np.random.randn(5, 8), index=["A", "B", "C","D",'G'], columns=index) df = df.rename_axis(index=['my_ch']).reset_index() # 反转映射字典 reverse_map = {val: group for group, chars in dict_map.items() for val in chars} # 添加Group列(和多级列结构对齐) df[('Group', '')] = df[('my_ch', '')].map(reverse_map) # 调整列顺序,把Group和my_ch放在最前面 cols = [('Group', ''), ('my_ch', '')] + [col for col in df.columns if col not in [('Group', ''), ('my_ch', '')]] df = df[cols]
最终效果
运行后你会得到和期望一致的DataFrame:
first Group my_ch bar baz foo qux second one two one two one two 0 group_two A 0.037718 0.089609 ... 0.202885 0.706059 -2.280754 1 group_one B 0.578452 0.039445 ... -0.153135 0.178715 -0.040345 2 group_two C 2.139270 1.104547 ... 0.989953 -0.280724 -0.739488 3 group_one D 0.733355 0.227912 ... -1.359441 0.761619 -1.119464 4 group_one G -1.565185 -1.070280 ... 0.458847 1.072471 1.724417
额外说明
如果你希望Group列的second层级和其他列保持一致(比如显示one/two但值相同),可以用以下代码替换添加Group列的步骤:
# 让Group列填充所有second层级 df[('Group', slice(None))] = df[('my_ch', '')].map(reverse_map).values[:, np.newaxis]
不过这种方式会让Group列的one和two子列值完全相同,从业务逻辑来看,用('Group', '')的单层级结构更合理。
内容的提问来源于stack exchange,提问作者rpb
相关产品推荐
相关产品推荐

