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

关于使用PySpark sampleBy实现比例分层抽样是否等同于随机抽样的技术问询

关于PySpark sampleBy实现比例分层抽样的疑问解答

你的理解完全正确——当你用sampleBy给所有分组设置相同的抽样比例时,根本无法实现精确的比例分层抽样,它的效果和简单随机抽样完全一致。

先明确核心概念的差异

咱们拿你举的例子来说:

  • 总体规模N=1000,4个分组占比分别是A组25%、B组50%、C组13%、D组12%。
  • 精确比例分层抽样的要求是:抽100个样本时,必须精准从A组拿25个、B组拿50个、C组拿13个、D组拿12个。
  • 而简单随机抽样的结果是:各组的预期样本量是上述数值,但实际抽取时会有随机波动,比如A组可能抽23个,B组可能抽52个,完全是概率性的。

为什么sampleBy在这里和随机抽样没区别?

sampleBy的底层逻辑是伯努利试验(类似抛硬币,每个元素独立判断是否被选中)。当你给所有分组设置相同的fractions参数(比如{'A': .1, 'B': .1, 'C': .1, 'D': .1}),意味着每个元素被选中的概率都是10%——不管它属于哪个分组。

这种情况下,按分组做伯努利抽样,和直接对整个数据集做简单随机抽样的统计效果完全一致:最终各组的样本量依然是随机波动的,完全达不到精确比例分层抽样“固定每组样本量”的要求。

那怎么实现精确的比例分层抽样?

  • Spark确实有sampleByKeyExact方法可以实现精确抽样,但遗憾的是Python API不支持这个方法,而且它的性能和扩展性在大数据场景下表现不佳,不太推荐。
  • 更实用的替代方案是用窗口函数:给每个分组内的元素添加一个随机排序的列,然后按分组取指定数量的样本。举个简单的代码示例:
from pyspark.sql import Window
import pyspark.sql.functions as F

# 定义窗口:按分组列分区,随机排序
window_spec = Window.partitionBy("group_col").orderBy(F.rand())

# 给每行添加组内排名,然后取前N个(N是每组需要的样本量)
exact_stratified_sample = df.withColumn("rank", F.row_number().over(window_spec)) \
    .filter(F.col("rank") <= F.when(F.col("group_col") == "A", 25)
                               .when(F.col("group_col") == "B", 50)
                               .when(F.col("group_col") == "C", 13)
                               .when(F.col("group_col") == "D", 12)) \
    .drop("rank")

这种方式可以精准控制每个分组的样本量,实现真正的比例分层抽样,而且性能更适合大规模数据集。

内容的提问来源于stack exchange,提问作者Vishaal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 18:03:15