![]()
探索性數據分析(EDA)的本質不是畫圖和算統計量,而是不被自己的數據欺騙。
分類列是最容易出問題的地方。city、category、product、department、role、customer_type——這些列看起來很簡單,跑個 value_counts()畫個柱狀圖搞定了。
其實分類變量往往藏著隱藏的層次結構。這些關系存在于類別內部,不主動挖掘根本看不出來。一旦忽略那么就會得到錯誤的結論、垃圾特征、誤導性的報表。
這篇文章講的是如何在 EDA 階段把這些隱藏結構找出來,用實際的步驟、真實的案例,外加可以直接復用的 Python 代碼。
什么是"隱藏層次結構"?
一個分類變量表面看起來是扁平的,實際上卻是分層的:這就是隱藏層次結構。
舉幾個常見例子:City 背后藏著收入水平、門店類型、客戶行為;Product Category 背后是價格層級和利潤模式;Customer Type 對應著忠誠度階段或消費能力;Department 則可能隱含資歷或責任級別。
把所有類別一視同仁EDA 就廢了,因為它們從來都不平等。
示例數據集
繼續使用同一份銷售數據,保持系列的連貫性。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style("whitegrid")
df = pd.read_csv("sales_data.csv")
df['order_date'] = pd.to_datetime(df['order_date'])
df.head()
扁平類別的假象
初學者通常這么干:
df['city'].value_counts()
輸出:Delhi: 3,Mumbai: 1,Bangalore: 1。
結論:"Delhi 銷售最多。"
技術上沒錯,分析上毫無價值。
EDA 應該問更好的問題:Delhi 的客戶是買得更頻繁,還是買得更貴?Delhi 的數據是不是被某一個客戶撐起來的?不同城市的品類結構有沒有差異?
扁平的計數把真正的結構埋了起來。
頻率不等于重要性
比較一下頻率和價值:
df.groupby('city')['amount'].sum().sort_values(ascending=False)
再看均值:
df.groupby('city')['amount'].mean().sort_values(ascending=False)
你很可能發現:某個城市訂單少但客單價高,另一個城市量大但貢獻的收入反而一般。
這就是第一個隱藏層次結構:數量主導 vs 價值主導。
出現頻率高的類別,并不自動意味著更重要。
嵌套類別
類別很少孤立存在。看看 city → category 的關系:
pd.crosstab(df['city'], df['category'], normalize='index')
可視化一下:
pd.crosstab(df['city'], df['category'], normalize='index')\
.plot(kind='bar', stacked=True, figsize=(8,5))
plt.title("Category Distribution Within Each City")
plt.show()
模式開始出現了:有的城市電子產品占大頭,有的城市家具更突出,還有的城市品類分布比較均勻。
這里的隱藏層次結構是:城市不是一個類別,而是一個容器。
忽略這一點,細分就做不好,報表也只是走過場。
主導類別背后的子群組
看看 category:
df['category'].value_counts(normalize=True)
電子產品占主導。但繼續拆解:
df.groupby(['category', 'product'])['amount'].sum()
很可能發現某一個產品貢獻了絕大部分收入,其他產品只是湊數的。
一個大類別可能完全由一個小子群組撐著。這對特征工程、庫存規劃、模型偏差都有直接影響。
客戶層級
客戶 ID 本質上也是分類變量,而且層次很深。
df.groupby('customer_id')['amount'].sum().sort_values(ascending=False)
你可能會看到某個客戶貢獻了大部分收入,或者同一個人反復購買。
再疊加城市維度:
df.groupby(['customer_id', 'city'])['amount'].sum()
真相可能是:某個城市的"領先地位"其實就靠一個客戶撐著。由此得出的地理結論完全站不住腳。
永遠要檢查:一個類別是由眾多貢獻者驅動的,還是被某個異常個體拉高的。
時間帶來的層次
時間天然會產生層次結構。
df['month'] = df['order_date'].dt.month
df.groupby(['city', 'month'])['amount'].sum().unstack()
畫出來:
sns.lineplot(data=df, x='month', y='amount', hue='city', marker='o')
plt.show()
你可能會發現不同城市在不同月份達到峰值,季節性主導權在品類之間輪換。
靜態的柱狀圖永遠看不到這些。
類別與數值的交互
處理分類數據時,交互分析是最關鍵的一環。
先看單一維度:
sns.boxplot(x='category', y='amount', data=df)
plt.show()
加上城市:
sns.boxplot(x='city', y='amount', hue='category', data=df)
plt.xticks(rotation=45)
plt.show()
同一個品類在不同城市的表現可能天差地別,消費分布不一樣,隱藏的高端細分市場也藏在里面。
特征創意往往就是這么來的。
隱藏層次結構如何破壞模型
不做 EDA 就直接 one-hot 編碼會出大問題,因為高價值和低價值的子群組被混在一起,客戶集中度信息泄露,噪聲被放大。
EDA 階段可以這樣修補:
df['high_value_customer'] = (
df.groupby('customer_id')['amount']
.transform('sum') > df['amount'].median()
).astype(int)
這個特征的存在,完全依賴于對層次結構的挖掘。
分類數據的 EDA 清單
每個分類列都應該過一遍:頻率檢查、基于價值的聚合、跨類別交互、時間維度拆分、異常值主導檢查。
跳過這些,EDA 就只是做做樣子。
面試時怎么說
不要說"我檢查了分類分布"。
要說:"我通過結合頻率、價值貢獻以及與時間和數值變量的交互,分析了分類變量的隱藏層次結構,識別出主導子群組,避免了建模時的誤導性結論。"
面試官一聽就知道你是明白人。
總結
分類數據從來都不是扁平的。EDA 存在的意義,就是證明這個假設是錯的。
隱藏的層次結構能解釋很多事:為什么報表會騙人,為什么模型會過擬合,為什么業務決策讓人一頭霧水。
一旦開始有意識地尋找這些結構,就再也回不去了。分析的段位會直接拉升一個檔次。
EDA 的目的不是更快地出圖,而是在相信圖表之前,先想清楚。
https://avoid.overfit.cn/post/829701eeb5dc40d094b0f69df05c3b15
by Gitanjali
特別聲明:以上內容(如有圖片或視頻亦包括在內)為自媒體平臺“網易號”用戶上傳并發布,本平臺僅提供信息存儲服務。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.