Spaces:
Running
Running
Download classroom_data/templates/week21/main.py from Telearn/Project_Demo: direct link, hf CLI and curl.
- Browser
- Download file 4.23 kB
-
https://huggingface.co/spaces/Telearn/Project_Demo/resolve/main/classroom_data/templates/week21/main.py
- Command line
-
hf download hf://spaces/Telearn/Project_Demo/classroom_data/templates/week21/main.py
-
curl -L -o main.py https://huggingface.co/spaces/Telearn/Project_Demo/resolve/main/classroom_data/templates/week21/main.py
4.23 kB
| """Lesson 21:用同一份公開資料練習排名、文字圖與跨年比較。""" | |
| import csv | |
| from pathlib import Path | |
| DATA_FILE = Path("data/students_by_county.csv") | |
| # 先執行一次,再依自己的問題修改這幾個條件。 | |
| COUNTY = "新北市" | |
| BEFORE_YEAR = "104" | |
| AFTER_YEAR = "114" | |
| FIELD = "國小[人]" | |
| TOP_N = 5 | |
| # 以下工具已備好,可以先使用,再查詢函式裡的寫法。 | |
| def load_rows(path=DATA_FILE): | |
| """將 CSV 每列讀成 dict;兼容有 BOM 的 UTF-8 檔案。""" | |
| with open(path, encoding="utf-8-sig", newline="") as file: | |
| return list(csv.DictReader(file)) | |
| def parse_count(value): | |
| """數字文字轉成整數;空白、破折號與無效值回傳 None。""" | |
| cleaned = (value or "").strip().replace(",", "") | |
| if not cleaned or cleaned == "-": | |
| return None | |
| try: | |
| return int(cleaned) | |
| except ValueError: | |
| return None | |
| def get_count(rows, school_year, county, field): | |
| """查詢指定學年度、縣市與教育階段的人數;找不到回傳 None。""" | |
| for row in rows: | |
| if row.get("學年度", "").strip() != str(school_year): | |
| continue | |
| if row.get("縣市別", "").strip() == county: | |
| return parse_count(row.get(field)) | |
| return None | |
| def count_by_county(rows, school_year, field): | |
| """同一學年度的人數排名;未知值不當成 0。""" | |
| totals = {} | |
| for row in rows: | |
| if row.get("學年度", "").strip() != str(school_year): | |
| continue | |
| county = row.get("縣市別", "").strip() | |
| count = parse_count(row.get(field)) | |
| if county and count is not None: | |
| totals[county] = count | |
| return sorted(totals.items(), key=lambda item: item[1], reverse=True) | |
| def print_text_chart(results, limit=5): | |
| """使用相同尺度畫文字長條,並保留可核對的人數。""" | |
| visible = results[:max(0, limit)] | |
| if not visible: | |
| print("沒有符合條件的資料,請檢查學年度、欄位名稱與顯示筆數。") | |
| return | |
| largest = max(value for _, value in visible) | |
| print("縣市 人數(人) | 比例長條") | |
| for county, value in visible: | |
| bar_length = round(value / largest * 24) if largest else 0 | |
| print(f"{county:<6} {value:>8,} | {'█' * bar_length}") | |
| print("長條從 0 開始,最長為 24 格;仍以旁邊的實際數字核對。") | |
| def main(): | |
| rows = load_rows() | |
| print("=== Lesson 21:比較與圖表 ===") | |
| print(f"讀入 {len(rows)} 列資料") | |
| if not rows: | |
| print("CSV 沒有資料,請檢查檔案。") | |
| return | |
| print(f"欄位:{', '.join(rows[0])}") | |
| # 第一部分:先觀察現成的排名圖,再換成自己的條件。 | |
| results = count_by_county(rows, AFTER_YEAR, FIELD) | |
| print(f"\n{AFTER_YEAR} 學年度各縣市 {FIELD}(前 {TOP_N} 名)") | |
| print_text_chart(results, TOP_N) | |
| print("來源:教育部統計處|各級學校縣市別學生人數(課堂 CSV)") | |
| # 第二部分:兩個原始數字都查到以後,才做相減。 | |
| before = get_count(rows, BEFORE_YEAR, COUNTY, FIELD) | |
| after = get_count(rows, AFTER_YEAR, COUNTY, FIELD) | |
| print(f"\n{COUNTY} {FIELD}:{BEFORE_YEAR} → {AFTER_YEAR} 學年度") | |
| if before is None or after is None: | |
| print("找不到完整的兩筆人數,請核對年份、縣市與欄位;未知值不能當成 0。") | |
| return | |
| print(f"{BEFORE_YEAR} 學年度:{before:,} 人") | |
| print(f"{AFTER_YEAR} 學年度:{after:,} 人") | |
| # TODO:以「後來的人數」減去「原來的人數」,取代下面的 None。 | |
| change = None | |
| if change is None: | |
| print("請完成 change 的相減算式,再執行一次。") | |
| return | |
| print(f"增減人數:{change:+,} 人") | |
| if change > 0: | |
| print(f"在這兩個學年度之間增加 {change:,} 人。") | |
| elif change < 0: | |
| print(f"在這兩個學年度之間減少 {abs(change):,} 人。") | |
| else: | |
| print("這兩個學年度的人數相同。") | |
| print("只比較兩個端點,還不能說中間每一年都增加或減少,也不能單靠此表判斷原因。") | |
| if __name__ == "__main__": | |
| main() | |