iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
自我挑戰組

用數據守護雙眼:生活型態對視力影響的探索性資料分析系列 第 6 篇

開啟視覺化篇章!單變數分佈探索(直方圖與 KDE 圖實作)

  • 分享至 

  • xImage
  •  

利用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()

https://ithelp.ithome.com.tw/upload/images/20260920/20178794sVXyx54Vjw.png

三、圖表解讀與生活型態洞察(真實視覺化產出剖析)
觀察輸出的三張直方圖與KDE擬合曲線:
圖一:受試者年齡分佈(多峰態分佈,涵蓋學業與職涯兩端)

  • 圖表特徵:在18~20歲出現了最顯著的高峰(超過70人),接著在31~32歲以及43~44歲 也各有明顯的突起。
  • 實質洞察:這直觀驗證了樣本的組成——剛進大學的大專院校學生(18~20歲)是一大主力,另一群則是進入職場多年、處於高強度工作期的資深專業人士(30~44歲)。年齡層的橫跨幅度夠廣,後續非常值得探討「年齡」是否會隨用眼時長加劇乾眼症狀。

圖二:每日螢幕使用時數分佈(重度暴露,峰值逼近 9~10 小時)

  • 圖表特徵:數值從2小時一路拉到14小時,且最高峰明顯落在9到10小時區間(該區間直逼60人)。
  • 實質洞察:整體KDE曲線呈現向高工時偏右傾斜的趨勢。這代表在現代生活型態下,不論是遠距上課、寫報告或辦公,多數受試者每天清醒時間有超過一半以上都在盯著螢幕,重度螢幕暴露(8小時以上)是整體常態。

圖三:每日睡眠時數分佈(高原型分佈,普遍處於睡眠臨界點)

  • 圖表特徵:數值均勻落在4到9小時之間,在5到5.5小時處達到最高峰(近60人),且有相當大比例的人群睡眠時間落在4~6小時的偏低水準。
  • 實質洞察:整體分佈並非嚴格的鐘形常態,而是較寬的平坦分佈。這群重度用眼族群同時伴隨著睡眠時間被壓縮的現象,這為後續交叉分析「睡眠時數是否會加重眼睛疲勞與頭痛頻率」提供了充分的變異性。

四、實作踩坑記錄:Colab重置導致字型遺失
在今天的開發過程中,也記錄下一個極具代表性的Colab實作地雷:
除錯日誌:為什麼Day2設定的中文字型今天又變豆腐塊?

  • 問題現象:執行Seaborn繪圖時跳出大量 WARNING:matplotlib.font_manager:findfont: Generic family 'sans-serif' not found...,圖表標題全部變成空心方塊(豆腐塊)。
  • 根本原因:Colab 虛擬機在閒置或重新連線後會被重置,存放在暫存目錄的思源黑體 .otf 檔案被清空;且若在 rcParams 中指定了虛擬機內未安裝的字型族群名稱,Matplotlib 便會回退失敗。
  • 最終解法:在繪圖腳本開頭加入 os.path.exists() 檢查與自動下載,並改用 fm.FontProperties(fname=font_path) 生成字型物件,直接透過 fontproperties=my_font 指派給標題與座標軸,徹底實現「不依賴系統字型庫、單檔自給自足」的跨平台中文字型方案!

上一篇
探索分類特徵!類別變數分佈檢視與受試者輪廓初探
下一篇
症狀量表深度透視!箱形圖與小提琴圖實作
系列文
用數據守護雙眼:生活型態對視力影響的探索性資料分析 共 16 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言