Stata与Python分组观测结果不一致问题排查
两段代码的核心差异分析
1. 日期比较逻辑的本质区别
Stata 端
Stata 的 mdy(5,4,2020) 生成的是日期型数值(以1960年1月1日为基准的天数),date_eval < mdy(5,4,2020) 是基于实际日期值的比较,逻辑完全准确,不会受字符串格式的干扰。
Python SQL 端
你使用 strftime(date_eval) < strftime("%m/%d/%Y", '5/4/2020') 做的是字符串字典序比较,这会引发两个关键问题:
- 如果
date_eval的字符串格式不统一(比如有的是5/3/2020,有的是05/03/2020),字典序比较会出错。例如05/05/2020会被错误判定为小于5/4/2020(因为字符0的ASCII码小于5),但实际日期5/5/2020是晚于5/4/2020的。 strftime("%m/%d/%Y", '5/4/2020')的写法本身有误:strftime的第二个参数需要是日期对象,直接传入字符串会导致解析错误,生成的结果大概率不是你预期的05/04/2020,直接干扰了筛选范围。
2. ID分组后的统计逻辑差异
Stata 端
你的代码逻辑是:
- 给每条观测标记是否属于period_1(1=符合,0=不符合,缺失值对应无有效日期的观测)
collapse period_1=period_1:未指定统计函数时,Stata默认对period_1取均值。之后count if period_1统计的是至少有一条观测符合period_1的ID数量(只要该ID有≥1条符合条件的记录,均值就大于0,会被计入统计)。- 注:如果你的需求明确是统计“有至少一条记录在period_1的ID数”,更严谨的写法是用
max函数collapse:gen period_1 = date_eval < mdy(5,4,2020) preserve collapse (max) period_1 count if period_1 == 1
- 注:如果你的需求明确是统计“有至少一条记录在period_1的ID数”,更严谨的写法是用
Python SQL 端
你的SQL查询 SELECT id, COUNT(date_eval) FROM df WHERE ... GROUP BY id:
- 理论上会返回所有在period_1范围内有至少一条记录的ID,以及每个ID对应的符合条件的记录数。如果统计这个结果的行数,应该和Stata的
count if period_1结果一致,但因为日期比较的错误,导致筛选出的ID范围偏差,最终数值不同。 - 另外,
COUNT(date_eval)会忽略date_eval为NULL的记录,Stata中date_eval为缺失值的观测会被标记为缺失,collapse时会被忽略,这部分逻辑是一致的,不是数值差异的核心原因。
3. 修正建议
修正Python SQL的日期比较
直接基于日期类型比较,避免字符串字典序的坑:
# 若date_eval是datetime类型 evals_period_1 = ps.sqldf(""" SELECT id, COUNT(date_eval) FROM df WHERE date_eval < '2020-05-04' GROUP BY id """) # 若date_eval是字符串类型,先转成日期类型再比较 evals_period_1 = ps.sqldf(""" SELECT id, COUNT(date_eval) FROM df WHERE DATE(date_eval) < '2020-05-04' GROUP BY id """)
内容的提问来源于stack exchange,提问作者user15663873
相关产品推荐
相关产品推荐

