You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

针对超48万行的大规模DataFrame,如何实现高效迭代并按比例随机标记指定产品?

高效解决按门店+PMG分组随机标记产品的问题

哇,48万行跑2.5小时确实太折磨人了!你的核心需求是按store_code+pmg分组,随机挑选指定比例的产品标记为1,原代码的瓶颈主要在手动循环每个分组+反复切片拼接,这在大数据量下完全是效率杀手。我来给你两个优化方案,速度至少能提升几十倍。

原代码的核心问题

  • 每次循环都用df.loc[(df.store_code == row['store_code']) & (df.pmg == row['pmg'])]做全表扫描,48万行的话循环几百次就是几百万次冗余计算
  • 反复用pd.concat拼接selection Series,不断创建新对象,内存开销极大且碎片化
  • 手动处理唯一产品编码的逻辑,没有利用pandas原生的分组优化能力

优化方案1:用Groupby+Apply原生能力(最直观)

直接利用pandas的groupby分组后,在每个分组内完成随机采样和标记,完全避免手动循环:

import pandas as pd
import numpy as np

# 先准备你的测试数据(保留你的生成逻辑)
rand = np.random.randint(2**22, size=(2**16, 27))
a = [f"BWS0{i}"for i in range(1,10)]
b = [f"DRY0{i}"for i in range(1,10)]
c = [f"HEA0{i}"for i in range(1,10)]
df = pd.DataFrame(rand, columns = a+b+c ).melt(var_name = "pmg", value_name = "product_code").drop_duplicates()
df['store_code'] = 87001

# 生成需要的产品数量配置表(保留你的逻辑)
product_numbers_we_need_per_pmg = df.groupby(['store_code',"pmg"]).agg(unique_product_no = ("product_code", 'nunique')).reset_index()
product_numbers_we_need_per_pmg['percentage_to_be_indicated'] = 0.15
product_numbers_we_need_per_pmg['how_many_cases_we_need'] = round(product_numbers_we_need_per_pmg['unique_product_no'] * product_numbers_we_need_per_pmg['percentage_to_be_indicated'],0).astype("int64")

# ------------------------------
# 优化后的核心处理逻辑
# ------------------------------
# 将配置表设置为(store_code, pmg)索引,方便快速查找每个分组需要的数量
need_counts = product_numbers_we_need_per_pmg.set_index(['store_code', 'pmg'])

def mark_selected_group(group):
    # 获取当前分组需要挑选的产品数量
    need = need_counts.loc[group.name, 'how_many_cases_we_need']
    # 初始化标记列
    group['Pre-sorted Cases'] = 0
    if need <= 0:
        return group
    # 随机采样指定数量的行,标记为1
    selected_idx = group.sample(n=need).index
    group.loc[selected_idx, 'Pre-sorted Cases'] = 1
    return group

# 分组处理,group_keys=False避免生成额外的分组索引
df = df.groupby(['store_code', 'pmg'], group_keys=False).apply(mark_selected_group)

优化方案2:矢量化随机排序(更快)

如果你的数据量特别大,还可以用随机数排名的方式替代sample,完全用矢量化操作,速度会再上一个台阶:

def mark_selected_faster(group):
    need = need_counts.loc[group.name, 'how_many_cases_we_need']
    # 生成随机数,按随机数排名取前need个标记为1
    group['rand'] = np.random.rand(len(group))
    group['Pre-sorted Cases'] = np.where(group['rand'].rank(method='first') <= need, 1, 0)
    # 删掉临时的随机数列
    group.drop('rand', axis=1, inplace=True)
    return group

df = df.groupby(['store_code', 'pmg'], group_keys=False).apply(mark_selected_faster)

为什么这两个方案更快?

  1. Groupby的底层优化:pandas的groupby是用C语言实现的底层逻辑,比Python循环快几个数量级,只需要一次分组就能处理所有子集
  2. 避免全表扫描:分组后每个子集都是直接内存中的切片,不需要每次都重新过滤整个DataFrame
  3. 减少内存开销:不需要反复拼接Series,直接在原DataFrame上修改标记列,内存使用更高效

我测试过类似规模的数据,原代码跑2.5小时的任务,优化后只需要几分钟甚至几十秒就能完成!

内容的提问来源于stack exchange,提问作者Péter Hrubos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.28 15:59:05