如何在Python中基于分组与列条件创建指定新列
问题描述
现有一个包含3个站点的员工数据DataFrame,记录了员工的manager标识、年龄、性别信息。需要新增三列:
manager_age:对应站点的经理年龄(经理为manager=1的员工,非经理行填0)minage_m:各站点男性员工的最小年龄(女性行填NaN)minage_f:各站点女性员工的最小年龄(男性行填NaN)
原尝试代码无法实现全行填充,比如站点A的所有行manager_age应对应经理的36岁,第2行(女性)的minage_m应为站点A男性的最小年龄22等,期望得到的目标表格如下:
| site | manager | age | gender | manager_age | minage_m | minage_f |
|---|---|---|---|---|---|---|
| A | 0 | 24 | m | 0 | 22.0 | NaN |
| A | 1 | 36 | f | 36 | NaN | 36.0 |
| A | 0 | 22 | m | 0 | 22.0 | NaN |
| A | 0 | 54 | m | 0 | 22.0 | NaN |
| B | 1 | 28 | m | 28 | 28.0 | NaN |
| B | 0 | 19 | f | 0 | NaN | 19.0 |
| B | 0 | 33 | f | 0 | NaN | 19.0 |
| C | 1 | 57 | m | 57 | 25.0 | NaN |
| C | 0 | 26 | m | 0 | 25.0 | NaN |
| C | 0 | 31 | f | 0 | NaN | 31.0 |
| C | 0 | 25 | m | 0 | 25.0 | NaN |
原尝试代码
创建DataFrame的代码:
import pandas as pd import numpy as np site = ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C'] manager = [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0] age = [24, 36, 22, 54, 28, 19, 33, 57, 26, 31, 25] gender = ['m', 'f', 'm', 'm', 'm', 'f', 'f', 'm', 'm', 'f', 'm'] df = pd.DataFrame({'site': site, 'manager': manager, 'age': age, 'gender': gender})
新增列的代码:
df['manager_age'] = np.select([df['manager'] == 1], [df['age']]) df['minage_m'] = df.groupby(df['site'][df['gender'] == 'm'])['age'].transform(np.min) df['minage_f'] = df.groupby(df['site'][df['gender'] == 'f'])['age'].transform(np.min)
解决方案
以下是实现需求的正确代码:
import pandas as pd import numpy as np site = ['A', 'A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C', 'C'] manager = [0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0] age = [24, 36, 22, 54, 28, 19, 33, 57, 26, 31, 25] gender = ['m', 'f', 'm', 'm', 'm', 'f', 'f', 'm', 'm', 'f', 'm'] df = pd.DataFrame({'site': site, 'manager': manager, 'age': age, 'gender': gender}) # 处理manager_age列:经理行填自身年龄,非经理行填0 df['manager_age'] = df.apply(lambda row: row['age'] if row['manager'] == 1 else 0, axis=1) # 处理minage_m列:按站点计算男性最小年龄,仅男性行保留值 male_min = df[df['gender'] == 'm'].groupby('site')['age'].min().rename('minage_m') df = df.merge(male_min, on='site', how='left') df['minage_m'] = df['minage_m'].where(df['gender'] == 'm', np.nan) # 处理minage_f列:按站点计算女性最小年龄,仅女性行保留值 female_min = df[df['gender'] == 'f'].groupby('site')['age'].min().rename('minage_f') df = df.merge(female_min, on='site', how='left') df['minage_f'] = df['minage_f'].where(df['gender'] == 'f', np.nan) print(df)
代码说明
manager_age列:
- 使用
apply逐行判断,若当前行是经理(manager=1)则取自身年龄,否则填0,确保所有行都有对应值。
- 使用
minage_m列:
- 先筛选男性员工,按站点分组计算最小年龄,通过
merge将结果关联到原表,再用where方法仅保留男性行的最小年龄,女性行设为NaN。
- 先筛选男性员工,按站点分组计算最小年龄,通过
minage_f列:
- 逻辑与
minage_m一致,针对女性员工计算最小年龄后,仅在女性行保留值。
- 逻辑与
运行代码后即可得到目标表格效果。
内容的提问来源于stack exchange,提问作者85sph
相关产品推荐
相关产品推荐

