如何高效获取Spark DataFrame中所有分类变量的频率?支持单次表扫描
高效实现Spark DataFrame多分类变量频率统计(单次表扫描)
核心思路
借助Spark的stack函数将多列分类变量宽表转长表(unpivot),之后仅需一次分组聚合即可完成所有变量的频率统计,全程仅触发一次表扫描,彻底解决遍历列多次扫表的性能问题。
代码实现
假设源DataFrame名为df,具体代码如下:
import org.apache.spark.sql.functions._ // 定义需要统计的分类列列表 val catCols = List("FRUIT", "COLOR") // 构造stack函数参数:每个列对应(列名常量, 列值)的组合 val stackExpr = catCols.map(col => s"'${col}', ${col}").mkString("stack(", ",", ") as (COLUMN, LEVEL)") // 执行宽表转长表 + 分组聚合 val result = df.selectExpr(stackExpr) .groupBy("COLUMN", "LEVEL") .agg(count("*").alias("COUNT")) .orderBy("COLUMN", "LEVEL") result.show()
代码细节说明
stack(n, expr1, expr2, ...):其中n是分类列的数量,每个'列名', 列名组合会将原表的一行拆分为一行新数据,最终把多列分类变量合并为COLUMN(原列名)和LEVEL(分类值)两列。- 分组聚合阶段,按
COLUMN和LEVEL分组统计行数,直接得到对应分类的出现频率,全程仅扫描源表一次。
测试验证
用你提供的源数据测试:
源DataFrame内容:
FRUIT COLOR Apple Red Apple Red Apple Yellow Pear Yellow Pear Yellow
执行代码后输出结果:
+------+------+-----+ |COLUMN| LEVEL|COUNT| +------+------+-----+ | FRUIT| Apple| 3| | FRUIT| Pear| 2| | COLOR| Red| 2| | COLOR|Yellow| 3| +------+------+-----+
完全匹配期望输出。
扩展提示
如果需要处理空值,可在selectExpr后添加.filter(col("LEVEL").isNotNull)过滤空值行;即使分类列数量很多,该方法依然保持单次表扫描的高效性。
内容的提问来源于stack exchange,提问作者user7238835
相关产品推荐
相关产品推荐

