利用Matplotlib與Seaborn針對核心數值變數(年齡、每日螢幕時數、每日睡眠時數)繪製直方圖與核密度估計曲線(KDE),探究其真實數據分佈型態。
一、 實作前情境:告別乾癟數字,讓分佈說話
在 Day4 我們用 df.describe() 算出了數值摘要(如每日螢幕時數平均 8.11 小時、睡眠平均 6.42 小時)。 但統計學上有一個經典概念:「平均值會騙人」。
平均 8 小時可能是大家都在 7~9 小時徘徊(單峰常態分佈),也可能是極端分化成「輕度使用2小時」與「重度熬夜 14 小時」兩群人(雙峰分佈)。
為了看清這500位受試者的真實日常型態,今天正式進入單變數探索性資料分析(Univariate EDA),透過圖表直觀呈現分佈形狀。
二、撰寫單變數視覺化腳本(Seaborn + Subplots)
在Notebook中新增程式碼儲存格,使用plt.subplots一口氣將三項生活核心指標視覺化:
# ==========================================
# Day 6:單變數分佈視覺化(直方圖 + KDE)
# ==========================================
import matplotlib.pyplot as plt
import seaborn as sns
# 1. 設定整體風格與畫布大小 (1 列 3 行子圖)
sns.set_theme(style="whitegrid")
plt.rcParams['font.sans-serif'] = ['Noto Sans CJK JP', 'Noto Sans TC', 'sans-serif'] # 確保中文字型支援
plt.rcParams['axes.unicode_minus'] = False # 正常顯示負號
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# 2. 圖表一:受試者年齡分佈 (Age)
sns.histplot(df['Age'], kde=True, ax=axes[0], color='#2b5c8f', bins=12)
axes[0].set_title('受試者年齡分佈 (Age)', fontsize=14, fontweight='bold')
axes[0].set_xlabel('年齡(歲)', fontsize=12)
axes[0].set_ylabel('人數計數', fontsize=12)
# 3. 圖表二:每日螢幕使用時數分佈 (Daily_Screen_Hours)
sns.histplot(df['Daily_Screen_Hours'], kde=True, ax=axes[1], color='#e06666', bins=12)
axes[1].set_title('每日螢幕使用時數分佈', fontsize=14, fontweight='bold')
axes[1].set_xlabel('螢幕使用時數(小時/天)', fontsize=12)
axes[1].set_ylabel('人數計數', fontsize=12)
# 4. 圖表三:每日睡眠時數分佈 (Sleep_Hours)
sns.histplot(df['Sleep_Hours'], kde=True, ax=axes[2], color='#6aa84f', bins=10)
axes[2].set_title('每日睡眠時數分佈', fontsize=14, fontweight='bold')
axes[2].set_xlabel('睡眠時數(小時/天)', fontsize=12)
axes[2].set_ylabel('人數計數', fontsize=12)
plt.tight_layout()
plt.show()# ==========================================
# Day 6:單變數分佈視覺化(修正中文字型版)
# ==========================================
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib.font_manager as fm
import os
# 1.自動檢查並下載思源黑體(若不存在才下載)
font_path = 'NotoSansTC-Regular.otf'
if not os.path.exists(font_path):
!wget -O NotoSansTC-Regular.otf https://github.com/googlefonts/noto-cjk/raw/main/Sans/OTF/TraditionalChinese/NotoSansCJKtc-Regular.otf
# 2.註冊字型並建立字型屬性物件
fm.fontManager.addfont(font_path)
my_font = fm.FontProperties(fname=font_path)
plt.rcParams['axes.unicode_minus'] = False # 正常顯示負號
# 3.設定畫布 (1 列 3 行)
sns.set_theme(style="whitegrid")
fig, axes = plt.subplots(1, 3, figsize=(18, 5))
# --- 子圖一:受試者年齡分佈 ---
sns.histplot(df['Age'], kde=True, ax=axes[0], color='#2b5c8f', bins=12)
axes[0].set_title('受試者年齡分佈 (Age)', fontproperties=my_font, fontsize=14, fontweight='bold')
axes[0].set_xlabel('年齡(歲)', fontproperties=my_font, fontsize=12)
axes[0].set_ylabel('人數計數', fontproperties=my_font, fontsize=12)
# --- 子圖二:每日螢幕使用時數分佈 ---
sns.histplot(df['Daily_Screen_Hours'], kde=True, ax=axes[1], color='#e06666', bins=12)
axes[1].set_title('每日螢幕使用時數分佈', fontproperties=my_font, fontsize=14, fontweight='bold')
axes[1].set_xlabel('螢幕使用時數(小時/天)', fontproperties=my_font, fontsize=12)
axes[1].set_ylabel('人數計數', fontproperties=my_font, fontsize=12)
# --- 子圖三:每日睡眠時數分佈 ---
sns.histplot(df['Sleep_Hours'], kde=True, ax=axes[2], color='#6aa84f', bins=10)
axes[2].set_title('每日睡眠時數分佈', fontproperties=my_font, fontsize=14, fontweight='bold')
axes[2].set_xlabel('睡眠時數(小時/天)', fontproperties=my_font, fontsize=12)
axes[2].set_ylabel('人數計數', fontproperties=my_font, fontsize=12)
plt.tight_layout()
plt.show()

三、圖表解讀與生活型態洞察(真實視覺化產出剖析)
觀察輸出的三張直方圖與KDE擬合曲線:
圖一:受試者年齡分佈(多峰態分佈,涵蓋學業與職涯兩端)
圖二:每日螢幕使用時數分佈(重度暴露,峰值逼近 9~10 小時)
圖三:每日睡眠時數分佈(高原型分佈,普遍處於睡眠臨界點)
四、實作踩坑記錄:Colab重置導致字型遺失
在今天的開發過程中,也記錄下一個極具代表性的Colab實作地雷:
除錯日誌:為什麼Day2設定的中文字型今天又變豆腐塊?