如何在PySpark中为多列绘制箱线图?解决大数据量转换报错
解决PySpark大数据集绘制箱线图的内存问题
当PySpark数据集过大时,直接转Pandas会触发内存限制报错,无法直接用PySpark原生绘制箱线图,但可以通过「先在PySpark中计算箱线图所需统计量,再用可视化工具基于统计量绘图」的方式解决,无需全量转换数据。
步骤1:在PySpark中计算箱线图核心统计量
箱线图只需要最小值、Q1(25分位数)、中位数、Q3(75分位数)、最大值,以及基于IQR计算的异常值边界。用PySpark的approxQuantile可以高效计算分位数(大数据集建议设置非0的相对误差提升速度):
from pyspark.sql import functions as F # 筛选浮点类型数值列 numeric_columns = [col for col, dtype in df.dtypes if dtype.startswith('float')] # 定义需要计算的分位数点位 quantiles = [0.0, 0.25, 0.5, 0.75, 1.0] # 逐个列计算箱线图统计量 boxplot_stats = {} for col in numeric_columns: # approxQuantile参数:列名、分位数列表、相对误差(0为精确计算,大数据建议0.01) q_vals = df.approxQuantile(col, quantiles, 0.01) min_val, q1, median, q3, max_val = q_vals iqr = q3 - q1 # 计算须线边界(异常值判定阈值) lower_whisker = max(min_val, q1 - 1.5 * iqr) upper_whisker = min(max_val, q3 + 1.5 * iqr) boxplot_stats[col] = { 'min': min_val, 'q1': q1, 'median': median, 'q3': q3, 'max': max_val, 'lower_whisker': lower_whisker, 'upper_whisker': upper_whisker } # 转为小体量的Pandas DataFrame,用于后续绘图 import pandas as pd stats_df = pd.DataFrame(boxplot_stats).T.reset_index().rename(columns={'index': 'column'})
步骤2:基于统计量用Plotly绘制箱线图
用Plotly的go.Box直接传入预计算的统计参数,无需全量数据:
import plotly.graph_objects as go fig = go.Figure() # 逐个列添加箱线图轨迹 for _, row in stats_df.iterrows(): fig.add_trace(go.Box( name=row['column'], q1=[row['q1']], median=[row['median']], q3=[row['q3']], lowerfence=[row['lower_whisker']], upperfence=[row['upper_whisker']], y=[row['min'], row['max']] # 显示数据极值 )) fig.update_layout( title='PySpark数值列箱线图(基于预计算统计量)', yaxis_title='数值', boxmode='group' # 分组显示多列箱线图 ) fig.show()
可选:添加异常值散点
如果需要查看异常值分布,不需要全量导出,可在PySpark中过滤异常值后抽样转Pandas:
outliers_df = pd.DataFrame() for col in numeric_columns: stats = boxplot_stats[col] # 筛选当前列的异常值 col_outliers = df.filter( (F.col(col) < stats['lower_whisker']) | (F.col(col) > stats['upper_whisker']) ) # 抽样(按比例或固定条数,避免数据量过大) sample_outliers = col_outliers.select(col).sample(False, 0.01, seed=42).toPandas() sample_outliers['column'] = col outliers_df = pd.concat([outliers_df, sample_outliers]) # 将异常值添加到箱线图中 for col in numeric_columns: col_outlier_vals = outliers_df[outliers_df['column'] == col][col].dropna().tolist() fig.add_trace(go.Scatter( x=[col] * len(col_outlier_vals), y=col_outlier_vals, mode='markers', marker=dict(color='red', size=4), showlegend=False )) fig.show()
这种方法只传递统计量和少量抽样数据,完全避开了全量转Pandas的内存限制,适合处理大规模PySpark数据集。
内容的提问来源于stack exchange,提问作者jessirocha
相关产品推荐
相关产品推荐

