Learning Objectives
- 建立 Series,說出值(values)與索引(index)的關係
- 分辨用標籤取值(s["S02"]、loc)與用位置取值(iloc)
- 說明兩個 Series 相加時依索引對齊,對不到的位置變成 NaN
- 用 mean、median、describe 描述數值欄,用 value_counts 描述類別欄
每個值都有名字
上一課的 NumPy 陣列只知道位置:arr[2] 是第 3 個數,但不知道它是誰的讀書時數。
pandas 的 Series 在一維陣列旁邊加上索引(index):每個值都有一個標籤,例如學號或系所。
| NumPy 陣列 | Series | |
|---|---|---|
| 取值 | 只能用位置 arr[1] |
用標籤 s["S02"],也可以用位置 s.iloc[1] |
| 兩個一起運算 | 依位置一對一 | 依索引對齊,標籤相同的才放在一起 |
| 常用統計 | mean、max |
同樣有,另外有 describe、value_counts |
下一課的資料表(DataFrame)就是好幾個共用同一個索引的 Series 並排在一起:從資料表取出一欄,得到的就是 Series。
逐步看:建立 Series,用標籤取值
右邊記憶體區把 Series 畫成兩欄:左邊是索引,右邊是值。
標籤與位置:loc 和 iloc
Series 有兩種取值方式,最好分清楚:
| 寫法 | 依據 | 例子(hours 的索引是 S01~S04) |
|---|---|---|
s.loc["S02"] 或 s["S02"] |
標籤 | 12.0 |
s.iloc[1] |
位置(從 0 數起) | 12.0 |
s.loc["S02":"S03"] |
標籤範圍,包含結尾 | S02、S03 兩筆 |
s.iloc[1:3] |
位置範圍,不包含結尾(同串列切片) | S02、S03 兩筆 |
索引本身是整數時(例如自動編號的 0、1、2),s[0] 到底是標籤還是位置容易混淆;這時明確寫 loc 或 iloc。
篩選、排序之後,索引會跟著值走,不會重新編號,所以「第 0 個」不一定是「標籤 0」。第 5 課在資料表上會再用到 loc 與 iloc。
運算時依索引對齊
兩個 Series 相加,pandas 不是依位置一對一,而是先依索引對齊:標籤相同的值才相加。 只出現在其中一邊的標籤,結果是 NaN(Not a Number,表示缺值,第 7 課詳細介紹);因為 NaN 是小數,整欄也會變成 float64。
這個設計讓不同來源、順序不同的資料可以安全地相加,但也要小心:標籤寫法不一致(「資工」和「資工系」)時,pandas 會當成兩個不同的標籤,不會報錯,只會多出 NaN。
如果對不到的位置應該當成 0,用 add(另一個, fill_value=0)。
逐步看:兩週的借書次數相加
兩個 Series 的系所順序不同,也各有一個對方沒有的系。猜猜看相加後會有幾個系、哪幾個是 NaN。
描述一欄:統計量與 value_counts
從資料表取出的一欄就是 Series,描述它的方法依資料型態(第 1 課)而定:
| 資料型態 | 常用方法 | 得到 |
|---|---|---|
| 數值 | mean()、median()、min()、max()、std() |
平均、中位數、最小、最大、標準差 |
| 數值 | describe() |
筆數、平均、標準差、最小、四分位數、最大,一次列出 |
| 類別、順序 | value_counts() |
每個值出現幾次,由多到少 |
| 類別、順序 | value_counts(normalize=True) |
每個值的比例,加起來是 1 |
| 順序 | value_counts().sort_index() |
依值的順序排,而不是依次數排 |
這些統計方法預設略過缺值。describe 的 25%、50%、75% 是四分位數,50% 就是中位數;
平均比中位數大很多時,通常代表有少數特別大的值把平均往上拉(第 15 課會仔細談)。
逐步看:讀書時數與系所
讀入 students.csv(程式產生的模擬資料,不是真實學生),取出一個數值欄與一個類別欄來描述。
實作:年級人數與住宿比例
讀入 students.csv,依序印出:
- 各年級(
year)的人數,依年級 1、2、3、4 的順序排列 - 是否住宿(
dorm,Y 或 N)的比例,四捨五入到小數 3 位
小測驗:索引、對齊與描述
下面程式會印出什麼?
import pandas as pd
s = pd.Series([10, 20, 30], index=["a", "b", "c"])
print(s["b"], s.iloc[0])
下面程式會印出什麼?
import pandas as pd
a = pd.Series({"x": 1, "y": 2})
b = pd.Series({"y": 10, "z": 20})
print((a + b).to_dict())
students["dept"].value_counts(normalize=True) 的所有值加起來是多少?
每週讀書時數的平均是 9.93,中位數是 9.1。最可能的原因是什麼?
重點整理
- Series=值+索引;
values是底下的 NumPy 陣列,index是標籤。從資料表取出一欄就是 Series。 - 用標籤取值:
s["S02"]、s.loc["S02"];用位置取值:s.iloc[1]。索引是整數時明確寫loc或iloc。 - 兩個 Series 運算時依索引對齊,只有一邊有的標籤得到 NaN;要當成 0 用
add(..., fill_value=0)。 - 數值欄用
mean、median、describe;類別欄用value_counts(),比例加normalize=True,順序資料接sort_index()。 - 下一課的 DataFrame 是很多個 Series 並排而成的資料表:讀 CSV、看
shape、head、info與每一欄的dtype。