本篇文章Why Most Data Scientists Are Wrong About PySpark EDA — And How to Do It Right適合希望高效處理大數據的從業者。文章的亮點在于強調了使用PySpark進行探索性數據分析(EDA)的重要性,避免了將Spark數據框轉換為Pandas的低效做法。幾點建議:
- 留在 Spark 中:不要強行將 Pandas 引入大數據工作流。
- 明智地使用采樣:Spark 完成繁重的工作,你繪制小樣本。
- 分布式思考:將過濾、連接和聚合推送到 Spark 中。
關聯Pyspark文章:
- 90% 的機器學習團隊仍停留在 2019 年的建模方式: Spark+XGBoost大規模訓練
- 在 PySpark ML 中LightGBM比XGBoost更好(二)
- 在 PySpark 中解鎖窗口函數的力量,實現高級數據轉換
- (早年帖子) PySpark︱DataFrame操作指南:增/刪/改/查/合并/統計與數據處理
- (早年帖子) pySpark | pySpark.Dataframe使用的坑 與 經歷
- (早年帖子) PySpark︱pyspark.ml 相關模型實踐
文章目錄
- 1 為什么在 PySpark 中進行 EDA 是不同的(并且更適合大數據)
- 2 步驟 1 — 從免費數據集開始
- 3 步驟 2 — 大規模數據分析
- 3.1 摘要統計
- 3.2 缺失值
- 3.3 唯一值(基數)
- 4 步驟 3 — 分布與可視化
- 4.1 示例:行程距離分布
- 4.2 示例 2:按乘客數量劃分的平均票價(條形圖)
- 4.3 分類分布
- 5 步驟 4 — 相關性與關系
- 5.1 相關矩陣
- 5.2 示例 3:相關性熱力圖(距離、票價、小費)
- 5.3 分組洞察
- 6 步驟 5 — 使用 Spark SQL 進行高級 EDA
- 7 常見錯誤(以及如何避免)
- 8 PySpark EDA 的未來
如果你是一名數據科學家、AI/ML 從業者或數據分析專業人士,你可能經歷過這樣的噩夢:你獲得了海量數據集,渴望對其進行探索,然后……你基于 Pandas 的筆記本就卡死了。
大多數人錯誤地認為:探索性數據分析 (EDA) 是一種Pandas + Seaborn 的儀式。這種信念如此普遍,以至于整個團隊浪費數小時將 Spark DataFrames 轉換為 Pandas——結果卻遇到了內存錯誤。
在這篇文章中,我將向你展示如何在 PySpark 中構建一個完整、端到端的 EDA 工作流。無需 Pandas 轉換。無需“對所有數據進行降采樣”的借口。只有干凈、可擴展的技術。
這基于我自己在領導數億行數據分析項目中的經驗,在這些項目中,Pandas 不僅效率低下——它根本不可能使用。
讀完本文,你將知道如何:
- 直接在 Spark 中分析海量數據集
- 使用 Spark SQL 和 PySpark 函數進行統計摘要
- 生成可視化而不會耗盡內存
- 為實際項目構建一個可重復、可擴展的 EDA 流水線
1 為什么在 PySpark 中進行 EDA 是不同的(并且更適合大數據)
當你在 Pandas 中打開數據集時,所有數據都會加載到內存中。如果你正在分析一個包含 50 萬行數據的 CSV 文件,這沒問題。但如果將其擴展到5 億行,你的筆記本電腦就會直接罷工。
我仍然記得我在金融領域的第一個大型項目:我們有數十億條交易記錄。我天真地以為我“只需使用 Pandas 進行采樣”。我的筆記本在不到一分鐘內就卡死了。更糟糕的是:即使我設法獲得了一個樣本,我意識到它不夠具代表性——分布具有誤導性。
這時 Spark 進入了視野。與 Pandas 不同,Spark 不會在你要求它處理數據之前進行處理。它是惰性的、分布式的,并且旨在處理數 TB 的數據而不會崩潰。
讓我們比較一下:
Pandas:
- 在單臺機器上運行
- 所有數據都在內存中
- 非常適合中小型數據集
PySpark:
- 分布在多個節點上
- 惰性求值——只在需要時處理
- 專為海量數據集構建
然而,許多教程仍然告訴你:“將你的 Spark DataFrame 轉換為 Pandas,然后用 Matplotlib 繪圖。”這不僅是糟糕的建議——它很危險。你正在丟棄 Spark 為之構建的可擴展性。
👉 要點:如果你的數據集已經存在于 Spark 中,你的 EDA 也應該留在 Spark 中。
2 步驟 1 — 從免費數據集開始
你不需要公司權限來練習 Spark EDA。有大量免費的真實世界數據集。我最喜歡的是:
- 紐約市出租車行程數據(數億次乘車):NYC Open Data
- Airbnb 房源數據:Inside Airbnb
- MovieLens(電影評分和元數據):MovieLens
對于本指南,讓我們使用 NYC 出租車行程數據集。它足夠大,符合實際,并且文檔完善。
from pyspark.sql import SparkSessionspark = SparkSession.builder.appName("EDA_PySpark").getOrCreate()df = spark.read.csv("yellow_tripdata_2023-01.csv", header=True, inferSchema=True)
df.printSchema()
df.show(5)
輸出:
root|-- VendorID: integer (nullable = true)|-- tpep_pickup_datetime: timestamp (nullable = true)|-- tpep_dropoff_datetime: timestamp (nullable = true)|-- passenger_count: integer (nullable = true)|-- trip_distance: double (nullable = true)|-- fare_amount: double (nullable = true)|-- tip_amount: double (nullable = true)
👉 專業提示:inferSchema=True
對于探索很方便。但在生產環境中,手動定義模式——當 Spark 預先知道列類型時,運行速度會快得多。
3 步驟 2 — 大規模數據分析
EDA 的第一步是分析:了解數據集的形狀、完整性和特性。
3.1 摘要統計
df.describe().show()
這會計算數值列的計數、均值、標準差、最小值和最大值——并在集群中分布式執行。
3.2 缺失值
Pandas 用戶通常會寫 df.isnull().sum()
。在 Spark 中,你可以這樣復制它:
from pyspark.sql.functions import col, sumdf.select([sum(col(c).isNull().cast("int")).alias(c) for c in df.columns]).show()
這會告訴你每列有多少個空值。
3.3 唯一值(基數)
for c in ["passenger_count", "VendorID"]:print(c, df.select(c).distinct().count())
高基數通常表示類似 ID 的字段(不利于建模)。低基數?是分組的好選擇。
👉 提示:.distinct()
可能會很昂貴。如果你只需要一個估計值,請使用 .approx_count_distinct()
。
4 步驟 3 — 分布與可視化
這就是有趣的地方。大多數人認為:“你不能直接在 Spark 中進行可視化。”這不正確。
訣竅在于智能采樣。Spark 擁有完整的數據集,但你只提取繪圖所需的數據。
4.1 示例:行程距離分布
import matplotlib.pyplot as pltsample = df.select("trip_distance").sample(fraction=0.01).toPandas()plt.hist(sample["trip_distance"], bins=50, range=(0,20))
plt.title("Trip Distance Distribution")
plt.xlabel("Distance (miles)")
plt.ylabel("Frequency")
plt.show()
行程距離直方圖
你不需要加載所有 1000 萬行,只需提取 1%。這足以生成一個具有代表性的直方圖。
👉 專業提示:在繪圖前始終過濾掉不切實際的異常值。在出租車數據中,200 英里的行程很可能是數據錄入錯誤。
4.2 示例 2:按乘客數量劃分的平均票價(條形圖)
我們可以使用 Spark 進行聚合,然后繪制結果。
import pandas as pdavg_fares = (df.groupBy("passenger_count").avg("fare_amount").orderBy("passenger_count").toPandas()
)
plt.figure(figsize=(8,6))
plt.bar(avg_fares["passenger_count"], avg_fares["avg(fare_amount)"], color="orange")
plt.title("Average Fare by Passenger Count")
plt.xlabel("Passenger Count")
plt.ylabel("Average Fare ($)")
plt.show()
按乘客數量劃分的平均票價(條形圖)
👉 這顯示了更大的團體是否傾向于支付更多費用。在紐約市出租車中,單人乘車占主導地位,但票價確實會隨著團體人數的增加而略有上漲。
4.3 分類分布
df.groupBy("passenger_count").count().orderBy("passenger_count").show()
這一行代碼就能告訴你有多少次行程有 1、2、3……位乘客。
5 步驟 4 — 相關性與關系
EDA 不僅僅是單變量分析——你還需要了解變量之間的關系。
5.1 相關矩陣
from pyspark.ml.stat import Correlation
from pyspark.ml.feature import VectorAssemblercols = ["trip_distance", "fare_amount", "tip_amount"]
vec = VectorAssembler(inputCols=cols, outputCol="features").transform(df)corr = Correlation.corr(vec, "features").head()[0]
print(corr.toArray())
輸出(截斷):
[[ 1.0, 0.78, 0.32],[0.78, 1.0, 0.55],[0.32, 0.55, 1.0]]
👉 解釋:票價和行程距離強相關(合情合理)。小費金額與兩者都有中等相關性。
5.2 示例 3:相關性熱力圖(距離、票價、小費)
import seaborn as sns
from pyspark.ml.stat import Correlation
from pyspark.ml.feature import VectorAssemblercols = ["trip_distance", "fare_amount", "tip_amount"]
vec = VectorAssembler(inputCols=cols, outputCol="features").transform(df)corr_matrix = Correlation.corr(vec, "features").head()[0].toArray()import pandas as pd
corr_df = pd.DataFrame(corr_matrix, index=cols, columns=cols)plt.figure(figsize=(8,6))
sns.heatmap(corr_df, annot=True, cmap="coolwarm", fmt=".2f")
plt.title("Correlation Heatmap")
plt.show()
相關性熱力圖
👉 現在你得到了一個漂亮的相關性熱力圖,顯示行程距離和票價強相關,而小費金額與它們的關系較弱但呈正相關。
5.3 分組洞察
df.groupBy("passenger_count").avg("fare_amount", "tip_amount").show()
這能快速顯示小費如何隨團體人數變化。
6 步驟 5 — 使用 Spark SQL 進行高級 EDA
有時,SQL 是最快的思考方式。Spark 允許你無縫切換。
df.createOrReplaceTempView("trips")spark.sql("""
SELECT passenger_count,AVG(fare_amount) AS avg_fare,AVG(tip_amount) AS avg_tip
FROM trips
WHERE trip_distance BETWEEN 1 AND 20
GROUP BY passenger_count
ORDER BY passenger_count
""").show()
該查詢:
- 過濾掉極端異常值
- 按乘客數量分組
- 給出平均票價和小費
結果:清晰、可解釋的 EDA 洞察。
7 常見錯誤(以及如何避免)
-
將整個 DataFrames 轉換為 Pandas
- 💥 內存立即崩潰。
- ? 解決方案:使用
.sample()
或.limit()
進行采樣。
-
忘記 Spark 是惰性的
- “為什么我的代碼沒有運行?”因為 Spark 等待一個_動作_。
- ? 解決方案:使用
.show()
、.count()
或.collect()
來觸發執行。
-
使用大型
.collect()
使本地機器過載- ? 在將結果帶到本地內存之前,始終在 Spark 中進行聚合。
-
不智能地進行緩存
- 如果你反復重用同一個子集,請對其進行
.cache()
以避免重復計算。
- 如果你反復重用同一個子集,請對其進行
👉 經驗法則:將 Spark 視為你的計算引擎,而不僅僅是數據容器。
8 PySpark EDA 的未來
我們正處于一個激動人心的轉折點。
- Spark 上的 Pandas API (Koalas):為 Spark DataFrames 帶來了類似 Pandas 的語法。
- 自動化 EDA 工具,如 ydata-profiling,正在適應 Spark。
- 可視化庫(Plotly、Altair)正在構建直接的 Spark 連接器。
- LLMs + Spark:想象一下,輸入“顯示一月份行程中的異常”,然后立即獲得 SQL 和圖表。這已經不遠了。
👉 EDA 的未來是可擴展、自動化和對話式的。