如何用Pandas实现按Site分组统计Person与Service_Date唯一配对数
问题回顾
你已经构造了这样的DataFrame:
import pandas as pd people = ['shayna','shayna','shayna','shayna','john'] dates = ['01-01-18','01-01-18','01-01-18','01-02-18','01-02-18'] places = ['hospital', 'hospital', 'inpatient', 'hospital', 'hospital'] df = pd.DataFrame({'Person':people,'Service_Date':dates, 'Site_Where_Served':places})
你的需求是按Site_Where_Served分组,统计Person和Service_Date的唯一配对数量,预期得到:
| Site_Where_Served | Site_Visit_Count |
|---|---|
| hospital | 3 |
| inpatient | 1 |
但你之前的代码会分别统计两个字段的唯一值,而不是配对数,这显然不符合预期。
正确解决方案
这里提供几种简单高效的实现方式,选你觉得最顺手的就行:
方法1:先去重配对再分组计数(最直观)
思路是先保留Person+Service_Date+Site_Where_Served的唯一组合,再按站点分组统计数量:
# 第一步:去除重复的Person-ServiceDate-Site配对 unique_visits = df.drop_duplicates(subset=['Person', 'Service_Date', 'Site_Where_Served']) # 第二步:按站点分组,统计每个站点的唯一配对数 result = unique_visits.groupby('Site_Where_Served').size().reset_index(name='Site_Visit_Count')
运行后就能得到你想要的结果,这种方法逻辑清晰,性能也不错,因为提前去重减少了分组时的数据量。
方法2:用groupby+lambda统计去重后的行数
如果你不想提前生成中间表,可以直接在分组时用lambda函数统计每组内去重后的配对数:
result = df.groupby('Site_Where_Served').apply( lambda group: group[['Person', 'Service_Date']].drop_duplicates().shape[0] ).reset_index(name='Site_Visit_Count')
这里的lambda函数会对每个分组,先去除Person和Service_Date的重复配对,再用shape[0]获取去重后的行数,也就是我们要的配对数。
方法3:将两列组合成元组后统计唯一值
还可以把Person和Service_Date组合成元组,再统计每个分组内元组的唯一数量:
result = df.groupby('Site_Where_Served').agg( Site_Visit_Count=lambda x: x.apply(tuple, axis=1).nunique() ).reset_index()
x.apply(tuple, axis=1)会把每行的Person和Service_Date转成一个元组,nunique()就会统计这个元组的唯一数量,也就是配对数。
为什么你的原代码不行?
你之前的代码df[['Person', 'Service_Date']].groupby(df['Site_Where_Served']).nunique()是分别对Person和Service_Date两个字段单独统计唯一值,而不是统计它们的组合配对数。比如hospital分组里,Person有2个唯一值(shayna、john),Service_Date有2个唯一值(01-01-18、01-02-18),但实际的有效配对是3个:(shayna,01-01-18)、(shayna,01-02-18)、(john,01-02-18),这才是我们需要统计的对象。
内容的提问来源于stack exchange,提问作者Shayna

