如何根据列中包含的子字符串过滤pandas groupby结果
我有一个员工培训的表格,里面记录了员工完成了哪些培训课程。我需要找出哪些员工完成了入职培训。这个表格有两列:
员工ID | 完成的课程名称 |
---|---|
1 | 入职培训第一部分 |
1 | 入职培训第二部分 |
1 | 公司合规培训A |
2 | 公司合规培训B |
2 | 其他随机培训 |
要被认定为“完成了入职培训”,员工需要完成入职培训第一部分(第二部分不是必须的),并且至少完成一门公司合规培训。对我来说,最简单的理解方式是按员工ID分组,如果完成的课程名称中包含“入职培训第一部分”和“公司合规”,就返回True。但我在想,是否有更符合Python风格或者更“pandas风格”的方法来实现这个。
这是我的代码:
data = [
{"EmployeeID": 1, "CompletedCourseName ": "onboarding part 1"},
{"EmployeeID": 1, "CompletedCourseName ": "onboarding part 2"},
{"EmployeeID": 1, "CompletedCourseName ": "corporate compliance training A"},
{"EmployeeID": 2, "CompletedCourseName ": "corporate compliance training B"},
{"EmployeeID": 2, "CompletedCourseName ": "Random other Training"}
]
# Create a DataFrame from the list
df = pd.DataFrame(data)
# return True if True is anywhere in the returned series of Trues and Falses that was return after checking if the required substring exists.
df.groupby(['EmployeeID'])['CompletedCourseName '].apply(lambda column:
( True in list(column.str.lower().str.contains("onboarding part 1")) )
&
( True in list(column.str.lower().str.contains("corporate compliance")) ) )
2 个回答
1
与其把布尔系列转换成列表,然后再检查列表里是否有True,不如直接在布尔系列上应用逻辑条件。你可以试试这样做:
# Group by EmployeeID and check if both conditions are satisfied
onboarding_completion = df.groupby('EmployeeID')['CompletedCourseName'].apply(
lambda x: x.str.contains('onboarding part 1', case=False).any()
and
x.str.contains('corporate compliance', case=False).any()
)
print(onboarding_completion)
1
这里有一个通用且高效的方法,可以让你随意组合多个条件:
# set up condtions
c1 = df['CompletedCourseName '].str.contains('onboarding part 1', case=False)
c2 = df['CompletedCourseName '].str.contains('corporate compliance training', case=False)
# concat, groupby.any, all
out = (pd.concat([c1, c2], axis=1) # combine conditions
.groupby(df['EmployeeID']).any() # check if each is met once
.all(axis=1) # check if all are met
)
输出结果:
EmployeeID
1 True
2 False
dtype: bool
在最后一个 all(axis=1)
之前的中间结果(带有自定义名称):
c1 c2
EmployeeID
1 True True
2 False True