排序資料的範例說明
以下整理 Pandas 中「排序資料」以及「取得最前面或最後面資料」的常見用法,並附上實用技巧與完整範例。
---
# 1. 建立範例資料
```python
import pandas as pd
import numpy as np
df = pd.DataFrame({
"姓名": ["小明", "小華", "小美", "小強", "小安"],
"年齡": [25, 30, 22, 28, 35],
"部門": ["業務", "技術", "業務", "技術", "管理"],
"薪資": [42000, 65000, 38000, 58000, 72000],
"到職日": pd.to_datetime([
"2022-03-01",
"2020-07-15",
"2023-01-10",
"2021-05-20",
"2019-11-01"
])
})
print(df)
```
輸出:
```text
姓名 年齡 部門 薪資 到職日
0 小明 25 業務 42000 2022-03-01
1 小華 30 技術 65000 2020-07-15
2 小美 22 業務 38000 2023-01-10
3 小強 28 技術 58000 2021-05-20
4 小安 35 管理 72000 2019-11-01
```
---
# 2. 依單一欄位排序:`sort_values()`
## 2.1 由小到大排序
```python
result = df.sort_values(by="薪資")
print(result)
```
結果會按照薪資由低到高排列:
```text
姓名 年齡 部門 薪資 到職日
2 小美 22 業務 38000 2023-01-10
0 小明 25 業務 42000 2022-03-01
3 小強 28 技術 58000 2021-05-20
1 小華 30 技術 65000 2020-07-15
4 小安 35 管理 72000 2019-11-01
```
`sort_values()` 預設為升冪排序,也就是由小到大。
---
## 2.2 由大到小排序
```python
result = df.sort_values(
by="薪資",
ascending=False
)
print(result)
```
`ascending=False` 表示降冪排序,也就是由大到小。
---
## 2.3 依文字欄位排序
```python
result = df.sort_values(by="姓名")
print(result)
```
文字通常會按照字典順序或 Unicode 順序排列。
---
# 3. 依多個欄位排序
可以將欄位名稱放進串列中:
```python
result = df.sort_values(
by=["部門", "薪資"]
)
print(result)
```
這表示:
1. 先依照「部門」排序
2. 同一個部門內,再依照「薪資」排序
---
## 3.1 不同欄位使用不同排序方向
例如:
- 部門由小到大
- 薪資由大到小
```python
result = df.sort_values(
by=["部門", "薪資"],
ascending=[True, False]
)
print(result)
```
`ascending` 的順序必須和 `by` 對應:
```python
by=["部門", "薪資"]
ascending=[True, False]
```
代表:
```text
部門:升冪
薪資:降冪
```
---
# 4. 排序後重新設定索引
排序後,原本的索引通常會保留:
```python
result = df.sort_values(by="薪資")
print(result.index)
```
可能得到:
```text
Index([2, 0, 3, 1, 4], dtype='int64')
```
如果希望索引重新變成 `0, 1, 2, ...`,可以使用 `reset_index()`。
```python
result = (
df.sort_values(by="薪資")
.reset_index(drop=True)
)
print(result)
```
`drop=True` 表示不要把原索引保留成新的欄位。
---
## 4.1 保留原始索引
如果不使用 `drop=True`:
```python
result = df.sort_values(by="薪資").reset_index()
print(result)
```
原本的索引會變成一個名為 `index` 的新欄位。
這在需要追蹤原始資料位置時很有用。
---
# 5. `head()`:取得最前面的資料
## 5.1 取得前 5 筆
```python
top5 = df.head()
print(top5)
```
`head()` 預設取得前 5 筆資料。
---
## 5.2 取得前 N 筆
```python
top3 = df.head(3)
print(top3)
```
也可以使用變數:
```python
n = 2
result = df.head(n)
```
---
## 5.3 先排序,再取得前幾名
例如:取得薪資最高的 3 人。
```python
top3_salary = (
df.sort_values(by="薪資", ascending=False)
.head(3)
)
print(top3_salary)
```
這是非常常見的寫法:
```python
df.sort_values("欄位名稱", ascending=False).head(N)
```
---
# 6. `tail()`:取得最後面的資料
## 6.1 取得最後 5 筆
```python
last5 = df.tail()
print(last5)
```
---
## 6.2 取得最後 N 筆
```python
last2 = df.tail(2)
print(last2)
```
---
## 6.3 依日期排序後取得最新資料
假設要取得最近到職的 2 人:
```python
latest = (
df.sort_values(by="到職日", ascending=False)
.head(2)
)
print(latest)
```
也可以先由舊到新排序,再用 `tail()`:
```python
latest = (
df.sort_values(by="到職日")
.tail(2)
)
print(latest)
```
兩種方式都可以,但通常「降冪排序後搭配 `head()`」語意比較清楚。
---
# 7. `nlargest()` 與 `nsmallest()`
當目標是取得某個數值欄位的前幾名,可以使用:
- `nlargest()`:最大值前 N 筆
- `nsmallest()`:最小值前 N 筆
## 7.1 取得薪資最高的 3 筆
```python
result = df.nlargest(3, "薪資")
print(result)
```
等同於:
```python
result = (
df.sort_values(by="薪資", ascending=False)
.head(3)
)
```
---
## 7.2 取得薪資最低的 2 筆
```python
result = df.nsmallest(2, "薪資")
print(result)
```
等同於:
```python
result = (
df.sort_values(by="薪資", ascending=True)
.head(2)
)
```
---
## 7.3 同時依多個欄位判斷
```python
result = df.nlargest(
3,
columns=["薪資", "年齡"]
)
print(result)
```
這表示先依薪資挑選,若薪資相同,再參考年齡。
---
# 8. 處理缺失值排序
建立含有缺失值的資料:
```python
df_missing = pd.DataFrame({
"姓名": ["小明", "小華", "小美", "小強"],
"分數": [85, np.nan, 92, 70]
})
```
## 8.1 缺失值預設排在最後
```python
result = df_missing.sort_values(by="分數")
print(result)
```
通常 `NaN` 會被放在最後。
---
## 8.2 將缺失值放在最前面
```python
result = df_missing.sort_values(
by="分數",
na_position="first"
)
print(result)
```
`na_position` 可以是:
```python
na_position="first" # 缺失值放最前面
na_position="last" # 缺失值放最後面,預設值
```
---
# 9. 排序索引:`sort_index()`
除了依欄位排序,也可以依索引排序。
```python
df_index = df.sort_values(by="薪資")
print(df_index)
```
此時資料的索引順序可能是:
```text
2, 0, 3, 1, 4
```
若要依索引重新排序:
```python
result = df_index.sort_index()
print(result)
```
---
## 9.1 索引降冪排序
```python
result = df.sort_index(ascending=False)
print(result)
```
---
## 9.2 Series 的索引排序
```python
s = pd.Series(
[30, 10, 20],
index=["C", "A", "B"]
)
print(s.sort_index())
```
輸出:
```text
A 10
B 20
C 30
dtype: int64
```
---
# 10. 不修改原始 DataFrame 與 `inplace`
## 10.1 預設不會修改原始資料
```python
sorted_df = df.sort_values(by="薪資")
# df 本身通常仍維持原本順序
```
這是 Pandas 比較建議的使用方式,因為可以保留原始資料。
---
## 10.2 使用 `inplace=True`
```python
df.sort_values(
by="薪資",
ascending=False,
inplace=True
)
```
這會直接修改 `df`。
不過在實務上,通常更建議:
```python
df = df.sort_values(
by="薪資",
ascending=False
)
```
原因是:
- 程式碼較容易追蹤
- 不容易意外修改原始資料
- 適合連續使用方法串接
- `inplace=True` 並不一定能帶來實質效能優勢
---
# 11. 使用 `key` 進行自訂排序
有時候不想直接按照原始值排序,而是希望先轉換後再排序。
## 11.1 不分大小寫排序
```python
df_name = pd.DataFrame({
"name": ["bob", "Alice", "charlie", "alice"]
})
result = df_name.sort_values(
by="name",
key=lambda col: col.str.lower()
)
print(result)
```
這樣會先將文字轉成小寫,再進行排序。
---
## 11.2 依文字長度排序
```python
result = df_name.sort_values(
by="name",
key=lambda col: col.str.len()
)
print(result)
```
---
## 11.3 依中文字自訂順序
假設部門有特定順序:
```python
department_order = ["管理", "技術", "業務"]
df_order = df.copy()
df_order["部門"] = pd.Categorical(
df_order["部門"],
categories=department_order,
ordered=True
)
result = df_order.sort_values(by="部門")
print(result)
```
這樣排序順序會依照:
```text
管理 → 技術 → 業務
```
而不是按照文字排序。
---
# 12. 群組內取得前幾名
例如:每個部門取得薪資最高的人。
```python
result = (
df.sort_values(
by=["部門", "薪資"],
ascending=[True, False]
)
.groupby("部門")
.head(1)
)
print(result)
```
說明:
1. 先依部門排序
2. 每個部門內薪資由高到低
3. `groupby("部門").head(1)` 取每組第一筆
---
## 12.1 每個部門取薪資最高的 2 人
```python
result = (
df.sort_values(
by=["部門", "薪資"],
ascending=[True, False]
)
.groupby("部門")
.head(2)
)
print(result)
```
這個技巧常用於:
- 每個分類取前 N 名
- 每個客戶取最新幾筆交易
- 每個地區取銷售額最高的產品
- 每個群組取評分最高的資料
---
# 13. 使用 `groupby().nlargest()`
也可以使用 `groupby()` 搭配 `nlargest()`:
```python
result = (
df.groupby("部門")["薪資"]
.nlargest(2)
)
print(result)
```
輸出會是帶有多層索引的 Series。
如果希望取得完整資料,可以使用:
```python
result = (
df.loc[
df.groupby("部門")["薪資"]
.nlargest(2)
.reset_index()["level_1"]
]
)
print(result)
```
不過對初學者而言,這種情況使用:
```python
df.sort_values(...).groupby(...).head(...)
```
通常比較直觀。
---
# 14. 取得排序後的第一筆或最後一筆
## 14.1 取得排序後的第一筆
```python
result = (
df.sort_values(by="薪資", ascending=False)
.iloc[0]
)
print(result)
```
`iloc[0]` 會回傳一個 Series。
如果希望結果仍然是 DataFrame,可以使用:
```python
result = (
df.sort_values(by="薪資", ascending=False)
.head(1)
)
```
---
## 14.2 取得排序後的最後一筆
```python
result = (
df.sort_values(by="薪資")
.iloc[-1]
)
print(result)
```
或:
```python
result = (
df.sort_values(by="薪資")
.tail(1)
)
```
差異如下:
```python
.iloc[0] # 回傳 Series
.head(1) # 回傳 DataFrame
```
---
# 15. `idxmax()` 與 `idxmin()`
如果只想找到最大值或最小值所在的索引,可以使用:
```python
max_index = df["薪資"].idxmax()
min_index = df["薪資"].idxmin()
print(max_index)
print(min_index)
```
再使用 `.loc[]` 取得完整資料:
```python
highest_salary = df.loc[df["薪資"].idxmax()]
lowest_salary = df.loc[df["薪資"].idxmin()]
print(highest_salary)
print(lowest_salary)
```
這種方法適合只需要單一最大值或最小值的情況。
---
## 15.1 最大值有重複時
`idxmax()` 只會回傳第一筆最大值。
如果想取得所有並列最高薪資的人:
```python
max_salary = df["薪資"].max()
result = df[df["薪資"] == max_salary]
print(result)
```
或使用:
```python
result = df[
df["薪資"].eq(df["薪資"].max())
]
```
---
# 16. 常見技巧整理
## 16.1 依欄位升冪排序
```python
df.sort_values("薪資")
```
## 16.2 依欄位降冪排序
```python
df.sort_values("薪資", ascending=False)
```
## 16.3 多欄位排序
```python
df.sort_values(
by=["部門", "薪資"],
ascending=[True, False]
)
```
## 16.4 取得前 N 筆
```python
df.head(3)
```
## 16.5 取得最後 N 筆
```python
df.tail(3)
```
## 16.6 取得數值最高的 N 筆
```python
df.nlargest(3, "薪資")
```
## 16.7 取得數值最低的 N 筆
```python
df.nsmallest(3, "薪資")
```
## 16.8 排序後重新建立索引
```python
df.sort_values("薪資").reset_index(drop=True)
```
## 16.9 依索引排序
```python
df.sort_index()
```
## 16.10 每個群組取前 N 筆
```python
(
df.sort_values(
["部門", "薪資"],
ascending=[True, False]
)
.groupby("部門")
.head(2)
)
```
---
# 17. 一個完整實例
取得「每個部門薪資最高的 1 位員工」,並將結果重新排序及整理索引:
```python
result = (
df.sort_values(
by=["部門", "薪資"],
ascending=[True, False]
)
.groupby("部門", as_index=False)
.head(1)
.sort_values(by="薪資", ascending=False)
.reset_index(drop=True)
)
print(result)
```
執行流程:
1. 依部門分組
2. 每個部門內薪資由高到低排序
3. 每個部門取第一筆
4. 將結果依薪資由高到低排序
5. 重新建立索引
---
# 18. 注意事項
## 欄位名稱不存在
```python
df.sort_values(by="不存在的欄位")
```
會產生 `KeyError`,因此要確認欄位名稱:
```python
print(df.columns)
```
---
## 欄位型別要正確
日期欄位最好先轉換成日期格式:
```python
df["到職日"] = pd.to_datetime(df["到職日"])
```
如果日期被當作文字,排序可能只按照字串順序處理。
---
## 數字欄位不要誤存成文字
例如:
```python
"100", "20", "3"
```
文字排序可能會得到:
```text
100, 20, 3
```
正確的數字排序應先轉型:
```python
df["分數"] = pd.to_numeric(df["分數"], errors="coerce")
```
---
## 排序不一定會修改原始資料
```python
sorted_df = df.sort_values("薪資")
```
這只會產生新的 DataFrame。若要保存結果,必須指定給變數,或使用 `inplace=True`。
---
簡單來說:
```python
# 排序
df.sort_values("薪資")
# 由大到小排序
df.sort_values("薪資", ascending=False)
# 前 N 筆
df.head(N)
# 後 N 筆
df.tail(N)
# 最大的 N 筆
df.nlargest(N, "薪資")
# 最小的 N 筆
df.nsmallest(N, "薪資")
```
這幾個方法已經可以涵蓋大部分 Pandas 的排序與取資料需求。
相關學習地圖、教學課程
Python 資料工程