如何在PySpark DataFrame的population列中将0替换为中位数?
在PySpark中将DataFrame列的0值替换为中位数
方法一:先计算中位数再替换(简单直观)
先算出目标列的中位数,再用when/otherwise逻辑替换0值。PySpark里推荐用approxQuantile计算中位数,适合大数据场景,效率更高:
1. 计算中位数
- 包含0值的中位数:
from pyspark.sql import functions as F # 计算population列的近似中位数,相对误差设为0.01(可根据需求调整精度) median_val = df.approxQuantile("population", [0.5], 0.01)[0]
- 排除0值的中位数(如果需要基于非0数据计算):
median_val = df.filter(F.col("population") != 0).approxQuantile("population", [0.5], 0.01)[0]
2. 替换0值
# 将population列中的0替换为中位数 df_updated = df.withColumn( "population", F.when(F.col("population") == 0, median_val).otherwise(F.col("population")) )
方法二:聚合关联替换(减少数据扫描次数)
针对大数据集,可通过聚合计算中位数后关联原表,避免多次扫描数据:
# 计算中位数并生成临时DataFrame median_df = df.select(F.percentile_approx("population", 0.5, 0.01).alias("median_pop")) # 关联原表并替换0值 df_updated = df.crossJoin(median_df).withColumn( "population", F.when(F.col("population") == 0, F.col("median_pop")).otherwise(F.col("population")) ).drop("median_pop")
补充:计算精确中位数(小数据集适用)
如果需要精确中位数而非近似值,可使用窗口函数实现(数据量大时效率较低):
from pyspark.sql.window import Window # 基于非0数据计算精确中位数 window = Window.orderBy("population") df_with_stats = df.filter(F.col("population") != 0).withColumn( "rank", F.row_number().over(window) ).withColumn( "total_count", F.count("population").over(Window.partitionBy()) ) # 取中间位置的平均值(兼容偶数/奇数数据量) median_val = df_with_stats.filter( (F.col("rank") == (F.col("total_count") + 1)/2) | (F.col("rank") == (F.col("total_count")/2) + 1) ).select(F.avg("population")).first()[0] # 替换0值 df_updated = df.withColumn( "population", F.when(F.col("population") == 0, median_val).otherwise(F.col("population")) )
内容的提问来源于stack exchange,提问作者Viane Phill
相关产品推荐
相关产品推荐

