
本文介绍在 PySpark(尤其 Azure Databricks 环境)中,如何基于另一列(如 n_relevant)的值,对固定长度数组执行条件化子采样——支持截断、模运算下采样及统一模3采样,确保输出数组长度 ≤100。
本文介绍在 pyspark(尤其 azure databricks 环境)中,如何基于另一列(如 `n_relevant`)的值,对固定长度数组执行条件化子采样——支持截断、模运算下采样及统一模3采样,确保输出数组长度 ≤100。
在数据工程实践中,常需对长数组做合规性裁剪(例如目标系统限制数组长度 ≤100)。当原始数组恒为 300 元素,而有效元素数量由辅助列 n_relevant 动态指定时,简单切片或静态过滤无法满足需求:需按三档逻辑差异化处理:
-
≤100:直接取前
n_relevant个元素; - 100 :在前
n_relevant个元素中,按index % 2 == 0保留偶数索引项(即每 2 个取 1 个,最终约 100 个); -
>200:统一在前
n_relevant个元素中按index % 3 == 0采样(即每 3 个取 1 个,严格 ≤100)。
注意:原问题中“100–300 区间按 ceil(n_relevant/100) 取模”的逻辑,在 Spark SQL 函数限制下难以动态生成模数(filter 的 lambda 不支持运行时参数),因此采用分段近似策略——将 100–200 映射为模 2,>200 统一模 3。该方案兼顾可实现性与结果合理性(200→101≈100,300→101≈100,800→267→截断后仍需再处理?但实际 slice 已限定范围,filter 在切片后执行,故最终长度可控)。
以下是完整可运行代码(适配 Spark 3.4+):
from pyspark.sql import functions as F
from pyspark.sql.types import StructType, StructField, ArrayType, IntegerType
# 构造示例数据
df = spark.createDataFrame(
[
(list(range(1, 301)), 4), # n=4 → [1,2,3,4]
(list(range(1, 301)), 200), # n=200 → 偶数索引: 1,3,5,...,199 (共100个)
(list(range(1, 301)), 300), # n=300 → 模3索引: 1,4,7,...,298 (共100个)
(list(range(1, 301)), 800) # n=800 → 实际只 slice 前300,再模3 → 同上
],
schema=StructType([
StructField("array", ArrayType(IntegerType())),
StructField("n_relevant", IntegerType())
])
)
# 执行条件化子采样
df_result = df.withColumn(
"result",
F.when(
F.col("n_relevant") <= 100,
F.slice("array", 1, F.col("n_relevant")) # 1-based index, take first N
).when(
(F.col("n_relevant") > 100) & (F.col("n_relevant") <= 200),
F.filter(
F.slice("array", 1, F.col("n_relevant")),
lambda _, idx: idx % 2 == 0 # keep index 0,2,4,... (0-based)
)
).otherwise(
F.filter(
F.slice("array", 1, F.col("n_relevant")),
lambda _, idx: idx % 3 == 0 # keep index 0,3,6,...
)
)
)
display(df_result.select("array", "n_relevant", "result"))✅ 关键要点说明:
-
F.slice(col, start, length)使用 1-based 起始位置,务必传入1作为起始索引; -
F.filter(array_col, lambda elem, idx: ...)中idx是 0-based 索引,与 Python 列表习惯一致; - 所有
when/otherwise分支均先slice再filter,避免对全量 300 元素做无效计算; - 若业务要求严格匹配原 Python 函数的
ceil(n_relevant/100)动态模数,需改用pandas_udf(牺牲性能)或预计算模数列 +transform+filter组合,但复杂度显著上升,通常分段策略已满足生产需求。
该方案高效、声明式、完全基于内置函数,适用于大规模分布式场景,是 Azure Databricks 等环境中处理数组合规裁剪的推荐实践。

















