首頁/模組/模組五
05 在地剪刀 · Local Landing

台灣電力
你家冷氣跳掉的那個瞬間

壓軸模組——把議題拉回到每個學生每天的生活經驗:夏天家裡跳電、新聞上的供電警戒、電費帳單愈繳愈多。 讓他們用自己親手跑出來的圖,理解「京都櫻花提前」與「我家冷氣跳電」是同一個故事。

課程時長
90–100 分鐘
敘事重點
在地化著陸點 · 政策與資料政治性
資料源
台電 / data.gov.tw(每日更新)
配套程式
module5_taiwan_power.py

真實資料:四十年的台灣電力剪刀

台電開放資料 #8307 · data.gov.tw · 即時下載計算
台灣 1982-2025 年尖峰負載與備用容量率的剪刀效應圖
圖五|台灣電力剪刀
紅線:歷年夏季尖峰負載(左軸,MW);綠線:年度備用容量率(右軸,%)。 紅線一路上升、綠線一路下降——與模組一的「京都櫻花剪刀效應」結構相同,但發生在你家的電費單上。
+489%
過去 43 年,台灣夏季尖峰負載從 1982 年的 6,918 MW 成長至 2025 年的 40,752 MW, 幾乎每四年就再翻一個 1982 年。同期備用容量率從 26.8% 一路掉到 14.2%。
資料範圍
1982–2025
44 年完整年度紀錄
尖峰負載
40,752MW
2025 年;1982 年為 6,918 MW
備用容量率
14.2%
2025 年;較 1982 年下降 12.6 個百分點
尖峰成長
+489%
1982 → 2025 年成長率

一、本模組的教學定位

這是整個課程的在地化著陸點(local landing point)。前四個模組帶學生環遊世界——京都的櫻花、勃艮第的葡萄、北極的海冰——目的是建立氣候變遷的全球認識論。但若課程就此結束,學生容易產生「那些都是別人的事」的心理距離。

模組五把議題拉回到每個學生每天的生活經驗:夏天家裡跳電新聞上的供電警戒電費帳單愈繳愈多。讓他們用自己親手跑出來的圖,理解「京都櫻花提前」與「我家冷氣跳電」是同一個故事。

面向本模組的獨特性
資料來源政府開放資料(台電 / data.gov.tw)——免費、公開、每天更新
技術挑戰Big5 vs UTF-8 編碼、民國年轉西元年、台電 CSV 格式偶爾變動
敘事重點「全球議題」如何顯化為「在地感受」;剪刀效應的在地翻譯
情意定位從「科學家的抽象曲線」走回「你家的電費單」

二、課堂前置準備

2.1 環境

與其他模組相同。Colab 首次執行:

!apt-get install -y fonts-noto-cjk -q

2.2 資料來源(真實 URL,每次執行自動更新)

資料集編號下載 URL
歷年尖峰負載及備用容量率(1982–) #8307 service.taipower.com.tw/.../d003002/001.csv
近三年每日尖峰備轉容量率 #24945 service.taipower.com.tw/.../d006004/001.csv
過去電力供需資訊(含機組) #19995 service.taipower.com.tw/.../d006005/001.csv

程式碼會自動處理:(a)Big5/UTF-8 編碼偵測、(b)民國年轉西元年、(c)欄位名稱模糊匹配(以防台電改欄名)。

2.3 關鍵名詞釐清(此教學重點不能省略)

許多學生甚至許多新聞記者都混淆這兩個名詞。教師務必在課堂一開始花 5 分鐘畫清楚:

備用容量率 Reserve Margin備轉容量率 Operating Reserve Margin
單位日(甚至分鐘)
用途長期電源規劃當日運轉調度
分母年度尖峰負載當日瞬時尖峰負載
分子全部裝置容量 − 尖峰負載運轉中淨尖峰能力 − 尖峰負載
關注者經濟部、政策制定者台電調度中心、民眾
口語意義「我家有幾成的發電機是備胎」「今天我有幾成電力可以應付突發狀況」
教學小撇步:把備用容量比喻為「整間餐廳有幾張桌子」(年度總量), 把備轉容量比喻為「今晚預訂客滿後還剩幾張空桌」(當日運轉)。兩者都是「緩衝」,但量級與時間尺度完全不同。

2.4 2022 年資料定義變動(必講的教學時刻)

台電自民國 111 年(2022)起,「備用容量率」改以「夜間備用容量率」呈現。原因是:白天太陽光電大量併網後,白天的供電壓力已大幅降低,真正緊張的是夜間(傍晚 5–8 點太陽下山、但民生用電還很高的時段)。

這意味著 2022 前後的數字不能直接比較。這是資料批判素養的絕佳教材:

「每一個指標都是某個時代對問題的理解方式。當問題本身變了(再生能源大量進入),指標也必須跟著變。但這也讓歷史比較變得困難——你會在論文中如何處理?」

三、課堂節奏建議(90 分鐘版)

時段內容教學重點對應程式
0–10 分破冰問學生:「去年夏天家裡跳過電嗎?家人抱怨過電費嗎?」——從個人經驗切入
10–20 分名詞釐清花 10 分鐘畫圖解釋「備用」vs「備轉」的差別。這 10 分鐘是整堂課的地基
20–35 分動手跑資料讓學生執行 main(),觀察終端機的下載進度。「這些數字,都是今天從台電網站下載的。」第 1、2、3 節
35–55 分解讀長期剪刀圖fig5a:紅線(負載)一路向上,綠線(容量率)一路向下。連結回模組一的櫻花剪刀效應第 6 節
55–70 分熱地圖的衝擊fig5b:大片紅橘色塊。問:「你記得 2022 年 3 月大停電嗎?2023 年夏天的限電警報?」讓圖與新聞記憶連結第 7 節
70–85 分分組討論選討論題(推薦題一「跨模組整合」或題五「行動與政策」)第 10 節
85–90 分收束全課「氣候變遷不是別人的事。它是你家冷氣跳掉的那個瞬間。」——情意收尾

四、關鍵統計與技術概念之淺白解釋

4.1 為什麼尖峰負載一直上升?不只是因為天氣熱

台灣尖峰負載攀升的驅動因素至少有四個:

  1. 氣候變遷:夏季高溫日數增加,冷氣用電上升
  2. 工業轉型:半導體、電動車、AI 資料中心的用電量級越來越大
  3. 人口與都市化:都市熱島效應 + 冷氣普及率上升
  4. 行為變遷:在家工作增加、電動車普及、家電功率上升

這意味著「只靠節電」無法解決供電緊張,必須同時考慮供給面(再生能源、儲能、輸配電)與需求面(需量反應、碳定價、產業分流)。

4.2 為什麼夏天特別緊張?

  • 需求面:冷氣是夏季尖峰負載的最大單一成分(約佔三分之一)
  • 供給面:(a)火力電廠冷卻水效率在高溫下下降;(b)太陽光電雖在日間出力高,但傍晚下山後民生用電仍高,形成「鴨子曲線」(duck curve)缺口
  • 調度面:機組年度大修通常安排在春、秋,夏季「所有機組都必須上場」,一旦有機組非計畫性停機,緩衝就立刻消失

4.3 燈號制度的統計意義

台電的「綠黃橘紅黑」五燈號不是連續指標,而是離散警戒級別。這在統計上類似「天氣預報的體感溫度」——把連續的溫度值對映到「舒適、悶熱、危險」的敘事類別。好處是易懂、好傳達;壞處是切點(10%、6%、3%)本身是政治協商的結果,不是物理定律。

教學提問:若把黃燈門檻從 10% 改為 8%,每年的「黃燈日數」會減少多少? 這是統計操作,不是物理現象。操作指標的人,能操作輿論感受。

五、常見學生提問與建議回應

老師,程式跑的時候跳了「HTTP 403 Forbidden」怎麼辦?
這是因為台電伺服器有時會擋掉未標示 User-Agent 的請求。本模組的 download_taipower_csv() 函式已處理此問題(自動加上瀏覽器標頭)。若仍失敗,有兩種可能:(a)台電伺服器暫時維護——等一小時再試;(b)URL 改版——上 data.gov.tw 搜尋「備轉容量率」找新 URL 替換。
為什麼近年備用容量率看起來反而有「上升」的訊號(2020 以後)?這和氣候變遷的敘事矛盾嗎?
非常敏銳的觀察。這是 2022 年資料定義變動造成的偽訊號——改為「夜間備用容量率」後,因為太陽光電在夜間不計入,數字看起來比「全日備用」低。所以 2022 後看起來「更緊張」是對的方向,但來自定義改變,不是物理惡化。嚴謹研究需另做時間序列銜接(time series splicing)。
政府說要「2025 非核家園」,這樣夏季會不會更缺電?
這是當前最具爭議的政策問題之一。作為教師,我建議不要替學生做政治判斷,但可以提供分析框架:
  • 支持方論點:再生能源 + 儲能 + 節電可彌補核電缺口
  • 反對方論點:再生能源間歇性 + 儲能成本 = 短期內不足以填補
  • 第三方觀點:比「非核家園」更關鍵的是電網結構轉型(集中式→分散式)
本模組的資料本身不能回答這個問題,但可以幫助學生辨識「哪些是資料能說的、哪些是價值判斷」。
台灣電費為什麼這麼便宜?
台灣電費長期偏低(工業電價尤其)的三個原因:(a)政策補貼(台電虧損由國庫承擔);(b)產業競爭力考量(尤其是半導體);(c)政治敏感性(電價上漲直接衝擊選情)。但「便宜電價」也是需求攀升的結構性因素——當電價不反映真實成本,節電誘因不足。
我可以拿這個程式做自己的研究嗎?
當然。政府資料開放授權條款第 1 版允許「商業使用、衍生改作、散布」,只要註明出處即可。本模組的完整資料流可作為政策分析、學生報告、新聞調查的起點。你甚至可以拿這份程式改裝成「每日跳電風險預報」的 LINE Bot——這就是資料民主化的最小單位。

六、評量建議

6.1 形成性評量(課中)

在圖 5b 熱地圖上,請學生指出:(a)最危險的一週是什麼時候;(b)近年有哪些日子應該落在警戒區但沒有——並推測原因(提示:可能是颱風把需求壓低、或某場大雨剛好降溫)。

6.2 總結性評量(課後)

三擇一繳交 1,000–1,500 字短文:

  1. 跨模組整合題:把模組一(櫻花)、模組二(葡萄)、模組四(海冰)、模組五(台灣電力)四張圖並列,寫一篇給家人或朋友看的文章,說明「同一個氣候故事的四個面向」。重點:讓他們理解氣候變遷不是別人的事。
  2. 政策分析題:依據圖 5a 的數字,若政府要把備用容量率目標設回 15%(國際電力規劃基準),需要在未來 5 年內新增多少 MW 的裝置容量?這些容量若全部來自燃氣電廠 vs 太陽光電 vs 核能,各自的成本、碳排、土地占用如何比較?
  3. 資料批判題:本模組的兩份資料在 2022 年面臨「定義不連續」問題。假設你是政府統計資料的使用者,應該如何與政府溝通,讓他們在更新統計口徑時保留「比較基準」?寫一封正式的公民建議信。

七、進階挑戰(供有餘裕的學生)

  1. 疊加氣溫:從中央氣象署 HistoryDataQuery 服務下載台北測站的日最高溫資料,與備轉容量率做回歸分析。預期會看到「日最高溫越高→備轉容量率越低」的負相關。
  2. 機組分析:使用資料集 #19995(過去電力供需資訊)的機組發電量資料,分析「哪些機組在警戒日貢獻最大」。這會讓你看見台電的實際調度策略。
  3. 預測模型:以過去 3 年日資料訓練簡單 ARIMA 或 XGBoost 模型,預測未來一週的備轉容量率。比較你的預測與台電「未來一週電力供需預測」(資料集 #33462)的差距。

八、延伸閱讀

  • 台灣電力股份有限公司(各年度)。《台電統計年報》。台北:台灣電力股份有限公司。
  • 經濟部能源署(各年度)。《能源統計年報》。台北:經濟部能源署。
  • IEA (2024). Chinese Taipei: country profile. International Energy Agency. https://www.iea.org/countries/chinese-taipei
  • U.S. EIA (2024). Taiwan country analysis brief. U.S. Energy Information Administration.

九、重要提醒:資料取得失敗時的處理

如果課堂上多人執行時遇到 Taipower 伺服器短暫當機(可能發生),建議:

  1. 請一位學生在上課前一晚先跑過一次,把下載下來的 CSV 備份
  2. 修改 load_annual_reserve()load_daily_operating_reserve(),在 download_taipower_csv() 失敗時讀取本地備份檔
  3. 把「資料源失效」本身作為教學題材——這展現了開放資料的脆弱性
教學者自我提醒:這是整個課程的收尾。前四個模組是「讓學生看見氣候變遷」, 這個模組是「讓他們看見自己已經在氣候變遷裡」。 當學生離開教室走回宿舍、打開冷氣、看到新聞上又一次限電警報時, 如果他們能想起課堂上的這張熱地圖——那麼這整堂課的教學目標就達成了。

配套程式碼

CC BY 4.0 · Python 3.10+ · 政府資料開放授權第 1 版
關鍵片段:台電 CSV 下載器(多重編碼自動偵測) module5_taiwan_power.py · 第 81–115 行
def download_taipower_csv(url: str,
                          encodings: tuple = ("utf-8-sig", "utf-8",
                                              "big5", "cp950")) -> pd.DataFrame:
    """
    台電 CSV 下載器,依序嘗試多種編碼。

    台電檔案的編碼曾在 Big5 與 UTF-8 之間變動過,為使程式長期可用,
    本函式以「依序嘗試,成功即返回」的方式處理編碼不確定性。
    若遇 403 Forbidden,會加上 User-Agent 重試。
    """
    req = urllib.request.Request(
        url, headers={"User-Agent":
                      "Mozilla/5.0 (educational research; Python/pandas)"})
    try:
        with urllib.request.urlopen(req, timeout=30) as resp:
            raw = resp.read()
    except urllib.error.HTTPError as e:
        raise RuntimeError(f"無法下載:HTTP {e.code} {e.reason}({url})")
    except urllib.error.URLError as e:
        raise RuntimeError(f"無法連線:{e.reason}({url})")

    last_err = None
    for enc in encodings:
        try:
            text = raw.decode(enc)
            df = pd.read_csv(io.StringIO(text))
            return df
        except UnicodeDecodeError as e:
            last_err = e
            continue
        except pd.errors.ParserError as e:
            last_err = e
            continue
    raise RuntimeError(f"所有編碼皆解碼失敗(嘗試:{encodings});"
                       f"最後錯誤:{last_err}")