如何根据列中包含的子字符串过滤pandas groupby结果

0 投票
2 回答
45 浏览
提问于 2025-04-14 17:39

我有一个员工培训的表格,里面记录了员工完成了哪些培训课程。我需要找出哪些员工完成了入职培训。这个表格有两列:

员工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

撰写回答