Pandas DataFrame 如何高效按双条件筛选id+qual组合数据
高效实现方案(替代原双层循环)
原实现效率低的核心原因是:双层循环最多会触发10000个ID × 2个qual = 20000次全表查询,每次查询都会对全量千万级销售记录做扫描,总数据遍历量达到万亿级,自然运行缓慢。
优化思路是全程用pandas向量化分组聚合替代逐组合循环,整个流程仅需2-3次全表扫描,千万级数据下可秒级完成校验。
步骤拆解
1. 基础配置与预处理
required_sales_years = [2020, 2021] required_sales_days = 4 required_year_cnt = len(required_sales_years) # 提前从date字段提取销售年份,避免反复访问dt属性拖慢速度 df["sale_year"] = df["date"].dt.year # 提前筛出amount>0的有效销售子集,两个校验维度的计算都只基于这个子集 valid_sales = df[df["amount"] > 0]
2. 一次性计算所有id+qual组合的校验指标
两个核心校验指标(有效天数、覆盖的要求年份数)全部通过分组聚合一次性算出,无循环、无逐行判断:
# 指标1:计算每个id+qual组合的有效销售天数 days_metric = valid_sales.groupby(["id", "qual"]).size().reset_index(name="valid_days") # 指标2:计算每个id+qual组合覆盖的要求销售年份数(避免重复统计同一年份) # 先对id+qual+sale_year去重,拿到不重复的年份记录 unique_year = valid_sales[["id", "qual", "sale_year"]].drop_duplicates() # 标记每个年份是否属于要求覆盖的年份 unique_year["is_required_year"] = unique_year["sale_year"].isin(required_sales_years) # 分组统计每个组合匹配到的要求年份数量 year_metric = unique_year.groupby(["id", "qual"])["is_required_year"].sum().reset_index() # 合并两个指标 group_metrics = days_metric.merge(year_metric, on=["id", "qual"], how="outer").fillna(0)
3. 筛选出满足双校验条件的合格组合
passed_combos = group_metrics[ # 条件1:覆盖所有要求的销售年份(匹配数等于要求的年份总数) (group_metrics["is_required_year"] == required_year_cnt) & # 条件2:有效销售天数达到阈值 (group_metrics["valid_days"] >= required_sales_days) ][["id", "qual"]]
4. 从原始表中提取合格组合的全部记录
注意:最终保留的是合格组合的所有销售记录(包括amount<=0的记录),不能只保留有效销售子集:
final_df = df.merge(passed_combos, on=["id", "qual"], how="inner")
常见踩坑提醒
- 校验年份覆盖时,不能直接统计有效记录中要求年份的出现次数,必须先对年份去重,避免出现“某组合仅覆盖单一年份、但该年份重复出现多次”的误判。
- 原循环存在无意义计算:对不存在的id+qual组合(比如某id只有qual=A、却被循环遍历到qual=B),也会执行空查询,优化后的分组逻辑只会计算真实存在的组合,完全跳过无效计算。
- 年份集合判断时,用计数替代
set.issubset()的向量化写法,比逐行调用apply判断快30%以上,尤其是组合数大的场景下差距更明显。
内容的提问来源于stack exchange,提问作者Vega
相关产品推荐
相关产品推荐

