National Central University
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try an AI Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

3

Local AI

--

Uedu Code

--

中央大學 AQI 78 24°C PM2.5 18
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 06

排序與新增欄位

sort_values、新增與計算欄位、apply 與向量化
Interaction實作 30 minute(s)

Learning Objectives

  • 用 sort_values 依一欄或多欄排序,設定由大到小,並說出排序後的索引怎麼變
  • 用整欄運算新增計算欄位(例如加權總分、是否及格)
  • 分辨會改到原表的 df["新欄"] = … 與回傳新表的 assign、sort_values
  • 用 apply 對每個值套用自己寫的函數,並說出何時改用 np.where、pd.cut 這類向量化寫法

排名與換算

選出需要的資料之後,常見的下一步是排序(誰的期末最高、哪門課缺席最多)和新增計算欄位 (期中占 40%、期末占 60% 的總分,是否及格,等第)。這一課學三件事:

想做的事 寫法
依某欄排序 df.sort_values("final", ascending=False)
新增一欄,用其他欄算出來 df["total"] = df["midterm"] * 0.4 + df["final"] * 0.6
對每個值套用自己寫的規則 df["final"].apply(letter),或向量化的 np.where、pd.cut

資料一樣是 grades.csv(600 筆修課成績),這是程式產生的模擬資料,不是任何學校的真實資料。

逐步看:依期末排序

注意每次印出的最左欄(索引):排序時整列一起移動,索引跟著走。

新增欄位:整欄一起算

df["total"] = df["midterm"] * 0.4 + df["final"] * 0.6 不需要迴圈:右邊的運算對每一列各自做一次, 得到一整欄的結果,再放進新欄。這種「整欄一起算」的寫法稱為向量化(vectorization)。

  • 右邊可以是數字運算、比較(得到 True/False 的欄),也可以是一個值(每一列都放同一個值)。
  • 欄名已經存在時,會覆蓋那一欄。
  • df["新欄"] = … 會改到 df 本身;df.assign(新欄=…) 和 sort_values 一樣,回傳一個新的資料表,原本的表不變。 想保留結果,要指定回去:df = df.sort_values("total")。

逐步看:總分、進步分數與是否及格

看記憶體區的 df:每執行一行 df["…"] = …,表格右邊就多一欄。

互動練習:排序與新增欄

選「sort_values」設定排序鍵,或選「新增欄」寫出運算式,按「執行」看結果。 新增的欄會留在 df 裡(排序不會改到 df);想重來就按「還原 df」。依序完成下面的任務。

apply 與向量化

有些規則不是一條算式,例如等第:80 分以上 A、70 分以上 B、60 分以上 C、其他 F。最直覺的寫法是寫一個函數, 再用 apply 對每個值呼叫一次:df["final"].apply(letter)。

apply 很有彈性,但它其實是在幕後跑一個 Python 迴圈,資料有幾列就呼叫幾次函數。資料多的時候,改用向量化的寫法通常快很多, 也比較短:

規則 向量化寫法
兩種結果(及格/不及格) np.where(df["final"] >= 60, "及格", "不及格")
依區間分組(等第、年齡層) pd.cut(df["final"], bins=[0, 60, 70, 80, 101], right=False, labels=["F", "C", "B", "A"])
一般的算式 直接用運算子:df["a"] * 0.4 + df["b"] * 0.6

pd.cut 的 bins 是區間的邊界;right=False 表示每個區間包含左端、不含右端,例如 [60, 70) 是 60~69 分。 最後一個邊界寫 101,100 分才會落在 A。

逐步看:apply 逐一呼叫,np.where 與 pd.cut 一次算完

只對前 4 列用 apply,好看清楚 letter 被呼叫了 4 次;整份 600 列改用向量化的寫法。

實作:總分前五名

讀入 grades.csv,新增 total 欄:期中(midterm)× 0.4 + 期末(final)× 0.6,四捨五入到小數 1 位。 再依 total 由高到低排序存進 top,最後一行會印出前 5 名的學號、課程與總分。

你的輸出
預期輸出

小測驗:排序與新增欄位

1.

下面程式會印出什麼?

import pandas as pd
s = pd.Series([30, 10, 20], index=["a", "b", "c"])
print(s.sort_values(ascending=False).index.tolist())
2.

下面程式會印出什麼?

import pandas as pd
df = pd.DataFrame({"x": [3, 1, 2]})
df.sort_values("x")
print(df["x"].tolist())
3.

下面程式會印出什麼?

import pandas as pd
df = pd.DataFrame({"a": [1, 2, 3], "b": [10, 20, 30]})
df["c"] = df["b"] - df["a"] * 2
print(df["c"].tolist())
4.

要把 60 萬筆期末成績換成「及格/不及格」,關於 apply 與 np.where,哪一個說法正確?

5.

下面程式會印出什麼?

import numpy as np
import pandas as pd
s = pd.Series([55, 60, 72])
print(np.where(s >= 60, "P", "F").tolist())
第 1 次作答

重點整理

  • sort_values("欄", ascending=False) 由大到小;多欄排序用串列,ascending 也用串列一欄對應一個。
  • 排序時整列一起移動,索引跟著走;reset_index(drop=True) 重新編號。同分的順序不保證,需要固定時加第二個排序鍵。
  • df["新欄"] = 整欄運算 會改到原表;assign、sort_values 回傳新表,要保留就指定回去。
  • apply 對每個值呼叫一次函數,彈性大但慢;兩種結果用 np.where,依區間分組用 pd.cut,一般算式直接用運算子。
  • 下一課處理缺值:期中缺考的 13 筆在算總分時變成 NaN,該刪掉、補值,還是保留?
這一課完成了!
Next lesson:缺值
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。