如何对Pandas DataFrame按邮箱和角色分组并编码组织列?
问题描述
现有如下Pandas DataFrame:
import pandas as pd df = pd.DataFrame({ 'Name': ['John', 'Mary', 'Mark', 'Sarah', 'John', 'Sarah', 'John'], 'Email': ['john@example.com', 'mary@example.com', 'mark@example.com', 'sarah@example.com', 'john@example.com', 'sarah@example.com', 'john@example.com'], 'Role_Name': ['Admin', 'User', 'Admin', 'User', 'Admin', 'Admin', 'User'], 'Last_Login': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-01', '2022-01-05', '2022-01-06'], 'Organization_Name': ['Org1', 'Org2', 'Org1', 'Org2', 'Org2', 'Org2', 'Org3'], 'Created_By_Name': ['SuperUser', 'SuperUser', 'SuperUser2', 'SuperUser2', 'SuperUser', 'SuperUser', 'Eve'], 'Modified_By_Name': ['SuperUser', 'SuperUser', 'SuperUser2', 'SuperUser2', 'SuperUser', 'SuperUser2', 'SuperUser2'] })
需求说明:
- 每一行对应Email和Role_Name的唯一组合(例如John会有两行,分别对应Admin和User角色)
- 将
Organization_Name列转换为多列(每个组织对应一列),用户拥有该组织权限则值为1,否则为0 - 注意:此需求不同于
pd.get_dummies,同一用户-角色组合可对应多个组织,不能拆分成多行
最终期望的DataFrame如下:
df_result = pd.DataFrame({ 'Name': ['John', 'Mary', 'Mark', 'Sarah', 'Sarah', 'John'], 'Email': ['john@example.com', 'mary@example.com', 'mark@example.com', 'sarah@example.com', 'sarah@example.com', 'john@example.com'], 'Role_Name': ['Admin', 'User', 'Admin', 'User', 'Admin', 'User'], 'Last_Login': ['2022-01-01', '2022-01-02', '2022-01-03', '2022-01-04', '2022-01-05', '2022-01-06'], 'Created_By_Name': ['SuperUser', 'SuperUser', 'SuperUser2', 'SuperUser2', 'SuperUser', 'SuperUser2'], 'Modified_By_Name': ['SuperUser', 'SuperUser', 'SuperUser2', 'SuperUser2', 'SuperUser2', 'SuperUser2'], 'Org1': [1, 0, 1, 0, 0, 0], 'Org2': [1, 1, 0, 1, 1, 0], 'Org3': [0, 0, 0, 0, 0, 1] })
解决方案
方法一:分组聚合+独热编码
通过分组保留唯一的Email-Role组合,再对组织列进行编码:
import pandas as pd # 原始DataFrame(略,同问题描述) # 1. 分组聚合,获取基础信息和每个分组的组织列表 grouped = df.groupby(['Email', 'Role_Name'], as_index=False).agg( Name=('Name', 'first'), Last_Login=('Last_Login', 'first'), Created_By_Name=('Created_By_Name', 'first'), Modified_By_Name=('Modified_By_Name', 'first'), Organizations=('Organization_Name', lambda x: list(x.unique())) ) # 2. 将组织列表转换为独热编码列 org_dummies = grouped['Organizations'].str.join('|').str.get_dummies() # 3. 合并基础信息和编码列,删除临时字段 result = pd.concat([grouped.drop('Organizations', axis=1), org_dummies], axis=1) # 调整列顺序匹配目标结果(可选) result = result[['Name', 'Email', 'Role_Name', 'Last_Login', 'Created_By_Name', 'Modified_By_Name', 'Org1', 'Org2', 'Org3']] print(result)
代码说明:
- 以
Email+Role_Name分组,确保每行是唯一组合 - 聚合函数
first用于提取同一分组下的唯一字段值(根据目标结果,这些字段在分组内一致) lambda x: list(x.unique())收集分组内所有不重复的组织str.join('|').str.get_dummies()自动生成组织列,存在则为1,否则为0
方法二:使用pivot_table实现
通过设置正确的索引和聚合逻辑,直接生成目标结构:
import pandas as pd # 原始DataFrame(略,同问题描述) # 生成透视表 pivot_result = df.pivot_table( index=['Email', 'Role_Name', 'Name', 'Last_Login', 'Created_By_Name', 'Modified_By_Name'], columns='Organization_Name', aggfunc=lambda x: 1 if len(x) > 0 else 0, fill_value=0 ).reset_index() # 调整列名和顺序 pivot_result.columns = pivot_result.columns.droplevel(0) pivot_result = pivot_result.rename(columns={'': 'Email', '': 'Role_Name', '': 'Name', '': 'Last_Login', '': 'Created_By_Name', '': 'Modified_By_Name'}) pivot_result = pivot_result[['Name', 'Email', 'Role_Name', 'Last_Login', 'Created_By_Name', 'Modified_By_Name', 'Org1', 'Org2', 'Org3']] print(pivot_result)
代码说明:
- 将非组织字段设为索引,保证唯一组合
- 以
Organization_Name为列,每个组织单独成列 - 聚合函数判断分组是否包含该组织,存在则标记为1
fill_value=0填充未拥有的组织值
内容的提问来源于stack exchange,提问作者Cyber
相关产品推荐
相关产品推荐

