Pandas新增列计算结果重复问题求助
问题描述
现有两个Pandas DataFrame:
- 安全角色定义表(roleDefDF):约3000个角色,结构如下:
| ROLE_NAME | DEPARTMENT_CODES |
|---|---|
| Role 1 | DPT_60001716,DPT_60009998 |
| Role 2 | DPT_62068951 |
- 员工详情表(factTabDF):约20万名员工数据,结构如下:
| INDEX | EMPLOYEE_ID | DEPARTMENT_CODE |
|---|---|---|
| 0 | EMP_001 | DPT_60001716 |
| 1 | EMP_002 | DPT_62068951 |
| 2 | EMP_003 | DPT_62068951 |
| 3 | EMP_004 | DPT_60001716 |
| 4 | EMP_005 | DPT_60009998 |
| 5 | EMP_006 | DPT_60009999 |
需要匹配每个员工对应的可见角色,预期结果如下:
| INDEX | EMPLOYEE_ID | ROLE_NAME |
|---|---|---|
| 0 | EMP_001 | Role 1 |
| 1 | EMP_002 | Role 2 |
| 2 | EMP_003 | Role 2 |
| 3 | EMP_004 | Role 1 |
| 4 | EMP_005 | Role 1 |
| 5 | EMP_006 |
最初通过遍历roleDefDF实现了需求,但性能极差。尝试新增列INDEX_OF_VISIBLE_EMPLOYEES存储角色可见的员工索引列表,代码如下:
roleDefDF['INDEX_OF_VISIBLE_EMPLOYEES'] = ','.join(str(x) for x in factTabDF.loc[factTabDF['DEPARTMENT_CODE'].apply(lambda x: any([x in roleDefDF['DEPARTMENT_CODES'].str.split(",",expand=False).values[0]]))].index.tolist())
预期生成的roleDefDF应该是:
| ROLE_NAME | DEPARTMENT_CODES | INDEX_OF_VISIBLE_EMPLOYEES |
|---|---|---|
| Role 1 | DPT_60001716,DPT_60009998 | 0,3,4 |
| Role 2 | DPT_62068951 | 1,2 |
但实际运行后,所有行的INDEX_OF_VISIBLE_EMPLOYEES都重复第一行的值:
| ROLE_NAME | DEPARTMENT_CODES | INDEX_OF_VISIBLE_EMPLOYEES |
|---|---|---|
| Role 1 | DPT_60001716,DPT_60009998 | 0,3,4 |
| Role 2 | DPT_62068951 | 0,3,4 |
请问该问题的原因是什么?如何解决?
原因分析
你的代码存在两个核心问题:
- 固定取第一行的部门列表:
roleDefDF['DEPARTMENT_CODES'].str.split(",",expand=False).values[0]直接取了values数组的第一个元素(即Role 1的部门列表),整个过滤逻辑都基于Role 1的规则计算,自然只会得到Role 1对应的员工索引。 - 标量广播赋值:你计算出的是一个单一字符串(比如"0,3,4"),当把这个标量赋值给DataFrame列时,Pandas会自动将其广播到所有行,导致所有行结果完全相同。
解决方案
方案1:修正原思路,逐行处理角色表
用apply遍历roleDefDF的每一行,针对每个角色的部门列表计算对应的员工索引:
# 预处理factTabDF,建立部门到索引的映射,提升查询效率 dept_to_indices = factTabDF.groupby('DEPARTMENT_CODE')['INDEX'].apply(list).to_dict() def get_visible_indices(row): depts = row['DEPARTMENT_CODES'].split(',') indices = [] for dept in depts: indices.extend(dept_to_indices.get(dept, [])) # 去重并排序(按需选择) indices = sorted(list(set(indices))) return ','.join(map(str, indices)) roleDefDF['INDEX_OF_VISIBLE_EMPLOYEES'] = roleDefDF.apply(get_visible_indices, axis=1)
方案2:高效关联方案(推荐,适配大数据量)
针对20万员工+3000角色的大数据量,更高效的方式是先拆分角色表的部门,再与员工表关联后聚合:
# 1. 拆分角色表的部门列,将一个角色的多个部门拆成多行 role_dept_expanded = roleDefDF.assign(DEPARTMENT_CODE=roleDefDF['DEPARTMENT_CODES'].str.split(',')).explode('DEPARTMENT_CODE') # 2. 和员工表关联,得到每个角色对应的员工记录 role_employee_match = role_dept_expanded.merge(factTabDF, on='DEPARTMENT_CODE', how='left') # 3. 按角色聚合,收集员工索引 role_visible_indices = role_employee_match.groupby('ROLE_NAME')['INDEX'].agg(lambda x: ','.join(map(str, sorted(x.dropna().unique())))).reset_index() # 4. 合并回原角色表 roleDefDF = roleDefDF.merge(role_visible_indices, on='ROLE_NAME', how='left') roleDefDF.rename(columns={'INDEX': 'INDEX_OF_VISIBLE_EMPLOYEES'}, inplace=True) # 处理无匹配员工的角色 roleDefDF['INDEX_OF_VISIBLE_EMPLOYEES'] = roleDefDF['INDEX_OF_VISIBLE_EMPLOYEES'].fillna('')
如果最终目标是生成员工-角色匹配表,直接整理关联后的结果即可:
employee_role_match = role_employee_match[['INDEX', 'EMPLOYEE_ID', 'ROLE_NAME']].drop_duplicates() # 合并原员工表,补充无匹配角色的员工 final_result = factTabDF[['INDEX', 'EMPLOYEE_ID']].merge(employee_role_match, on=['INDEX', 'EMPLOYEE_ID'], how='left').fillna('')
内容的提问来源于stack exchange,提问作者Armando Ochoa
相关产品推荐
相关产品推荐

