Learning Objectives
- 用 to_datetime 把文字轉成日期時間,指定格式避免把月、日讀反
- 用 dt 存取器取出月份、星期,並計算兩個時間的間隔
- 以日期為索引,用 resample 依週或月彙總,用 rolling 算移動平均,並說明它們各自的邊界問題
- 說明每日彙整的「一天」要依資料所在地的時區切,以及時區為什麼要存 IANA 名稱而不是固定的時差
時間不只是一串文字
宿舍每天的用電、每小時的氣溫、作業的繳交時間,都是時間資料。讀進來時它們通常只是文字("2026-09-01"),
轉成真正的日期時間之後才能做這些事:
- 取出月份、星期幾,比較平日和週末;
- 算兩個時間差幾天;
- 把每日資料彙總成每週、每月(
resample); - 算最近 7 天的移動平均,看出趨勢(
rolling)。
這一課用 dorm_power.csv(5 棟宿舍 × 122 天的用電)與 weather.csv(同期間每天的氣溫與雨量),
都是程式產生的模擬資料,不是任何學校的真實資料。
逐步看:文字變成日期
注意右邊 raw 和 d 的差別:同樣的內容,一個是文字(object),一個是日期時間(datetime64)。最後一段是同一串文字被讀成兩個不同的日期。
日期格式與時間索引
常用的格式代碼:
| 代碼 | 意思 | 例子 |
|---|---|---|
%Y |
四位數的年 | 2026 |
%m |
月(01~12) | 09 |
%d |
日(01~31) | 01 |
%H、%M |
時(00~23)、分 | 14、05 |
"2026-09-01" 這種「年-月-日」(ISO 8601 的寫法)不會讀錯,也能直接依文字排序,交換資料時優先用這種寫法。
讀 CSV 時可以直接用 pd.read_csv(..., parse_dates=["date"]) 把日期欄轉好。接著把日期設成索引(set_index("date")),
就能用 resample 依時間彙總、用 a.loc["2026-10"] 選出整個 10 月。
逐步看:每日用電彙總成每週、每月
只看 A 棟。resample 和第 9 課的 groupby 很像,只是分組依據是「落在哪一週、哪一個月」。
移動平均:看趨勢而不是每天的起伏
每日的數字起伏很大(週末、下雨、考試週)。移動平均(rolling mean)在每一天取「包含今天在內的最近 n 天」的平均,
把短期的起伏抹平,留下趨勢。a.rolling(7).mean() 就是 7 日移動平均。
兩件事要知道:
- 預設要湊滿 n 天才算,所以前 n − 1 天是 NaN;可以用 min_periods 放寬。
- 預設的視窗是「到今天為止」(向後看),所以移動平均的曲線會落後原本的資料幾天。加上 center=True 改成以今天為中心。
resample 和 rolling 的差別:resample("W") 把資料切成不重疊的段,一週只剩一個數字;rolling(7) 每一天都有一個數字,視窗一天一天往前滑。
逐步看:7 日移動平均與氣溫
算 A 棟用電的 7 日移動平均,再和每日最高溫比較。最後一步畫出兩條線。
「一天」從幾點算起?
資料庫通常用 UTC(世界協調時間)記錄時間,顯示時再換成使用者所在的時區。但「每日用電」「每日雨量」這種以日為單位的彙總, 一天的起點要用資料所屬地點的當地時間:台灣的宿舍用台灣的午夜切,波士頓的校區用美東的午夜切,而不是看分析的人在哪裡。
時區要存 IANA 時區名稱(例如 Asia/Taipei、America/New_York),不要存固定的時差(例如「UTC−4」):
美國有日光節約時間,一年中時差會在 −4 和 −5 小時之間切換,切換那一天只有 23 或 25 小時。
存固定時差的話,換季之後每天的分界都偏一小時,切換那天前後的兩天也會算錯。IANA 名稱背後有一份完整的換季紀錄,pandas 會自動查。
pandas 的作法:tz_localize("UTC") 標明「這些時間是 UTC」,tz_convert("America/New_York") 換成當地時間,再依當地日期分組。
逐步看:同一份紀錄,三種切法
72 筆每小時的用電紀錄,時間是 UTC。分別用紐約時間、固定 UTC−4、台北時間切成「一天」,看每天各有幾筆。
實作:每月的平均最高溫與總雨量
讀入 weather.csv(讀檔時把 date 轉成日期),把日期設成索引,用 resample("MS") 依月彙總:
temp_max 算平均、rain_mm 算總和,四捨五入到小數 1 位後印出。
小測驗:日期與彙總
下面程式會印出什麼?
import pandas as pd
d = pd.to_datetime("05/04/2026", format="%d/%m/%Y")
print(d.month, d.day)
下面程式會印出什麼?
import pandas as pd
s = pd.Series([1, 2, 3, 4, 5])
print(s.rolling(3).mean().tolist())
daily.resample("W").sum() 和 daily.rolling(7).sum() 最主要的差別是?
小測驗:時區與當地日
某大學在台北與波士頓各有一個校區,資料庫用 UTC 記錄每小時的用電。要算「每個校區每天的用電」,一天的分界應該怎麼定?
設定檔要記錄波士頓校區的時區,哪一種寫法最好?
重點整理
pd.to_datetime把文字轉成日期時間;格式不明確時用format=寫清楚(%d/%m/%Y和%m/%d/%Y會讀出不同的日期)。讀 CSV 時可用parse_dates。.dt.month、.dt.dayofweek(星期一是 0)、.dt.day_name()取出日期的各部分;日期相減得到Timedelta。- 日期設成索引後:
resample("W")、resample("MS")依週、月切成不重疊的段(注意頭尾不完整的段);rolling(7).mean()是 7 日移動平均,前 6 天是 NaN、曲線會落後。 - 每日彙總的「一天」依資料所在地的時區切:
tz_convert("America/New_York")之後再依日期分組。時區存 IANA 名稱,不存固定時差,日光節約換季那天是 23 或 25 小時。 - 下一課開始畫圖:同一份資料,比較、分布、關係、隨時間變化各適合哪一種圖。