🗺️ AI 學習與考證地圖
大數據處理 · Pandas

Pandas 概念總覽:DataFrame 怎麼想、怎麼用

Pandas 的語法有幾百個方法,背不完;但它的「心智模型」只有一張表、一條工作流。把 DataFrame 想成一張有名字的 Excel 表,每個方法都只是在這張表上「挑、改、算、拼、翻」。

Series/DataFrame/Indexloc/ilocgroupbymerge/concatmelt/pivot向量化chunksize

💡一句話定義

Pandas=Python 裡處理表格資料(tabular data)的工具箱。核心物件是 DataFrame(資料框):一張有欄名、有列標籤(Index)的二維表;每一欄是一條 Series(序列)。所有操作都可以歸納成一條工作流:讀 → 看 → 挑 → 清 → 轉 → 算 → 拼 → 存。

為什麼要有它?因為原生 Python 的 list/dict 處理十萬列資料又慢又難讀;NumPy 很快但只有數字、沒有欄名。Pandas 把 NumPy 的速度包上「欄名+標籤」,讓你用「金額 > 1000」這種人話來操作資料,而不是記第幾欄。

🧱三個零件:Series、DataFrame、Index

先把關係弄對,之後看任何程式碼都不會迷路:DataFrame = 好幾條 Series 並排,共用同一個 Index。

Index 0123 客戶 小明小華小美阿強 城市 台北台中高雄台北 金額 12008001500300 DataFrame(整張表) df["金額"] 是一條 Series df.shape → (4, 3) df.columns → 客戶, 城市, 金額 df.index → 0, 1, 2, 3 df["金額"] → Series df[["金額"]] → DataFrame 單中括號取欄=Series 雙中括號取欄=DataFrame
📏Series(序列)
一維、有標籤的陣列。底層是 NumPy 陣列+一個 Index。df["金額"] 就是一條。
📋DataFrame(資料框)
二維表。可以想成「一個 dict,key 是欄名、value 是 Series」,所有 Series 共用同一個 Index。
🏷️Index(索引/列標籤)
每一列的「名牌」。預設是 0,1,2…,但篩選後不會自動重排,這是很多題目的陷阱。
為什麼 Index 這麼重要?Pandas 做加減、合併時是「對齊標籤」而不是「對齊位置」。兩條 Series 相加,Index 相同的才會加在一起,對不到的變 NaN。這就是為什麼 loc(用標籤)和 iloc(用位置)要分開。

🔄八步工作流:讀→看→挑→清→轉→算→拼→存

任何 Pandas 程式幾乎都在這條線上,考題給一段程式問輸出時,先問自己「這段在做哪一步」。

  1. 讀檔(load):pd.read_csv("orders.csv")、read_excel、read_sql。超大檔加 chunksize= 一塊一塊讀(見下方記憶體那節)。
  2. 檢視(inspect):df.head() 看前 5 列、df.info() 看每欄型別與非空數量、df.describe() 看數值欄的統計摘要、df.shape 看幾列幾欄。info 看型別與缺值,describe 看分布——考題常拿這兩個互換來考。
  3. 篩選(select/filter):布林遮罩 df[df["金額"] > 1000];df.loc[列標籤, 欄名] 用名字;df.iloc[列位置, 欄位置] 用數字位置;df.query("金額 > 1000 and 城市 == '台北'") 用字串寫條件。
  4. 清理(clean):缺失值 isna().sum() 數、dropna() 丟、fillna(中位數) 補;型別 astype("int64")、pd.to_datetime();重複 drop_duplicates()。補值與整數型別的坑看 fillna 中位數補值與 Int64 逐行解剖。
  5. 轉換(transform):Series.map(字典或函式) 逐值對應、Series.apply(函式) 逐值套用、df.apply(函式, axis=1) 逐列套用、df.assign(新欄=...)。能用向量化(直接 df["金額"] * 1.05)就不要 apply。
  6. 彙總(aggregate):df.groupby("城市")["金額"].sum()=「分組 → 套用 → 合併」(split-apply-combine);agg(["sum","mean"]) 一次多個;pivot_table 是「groupby 後再攤成寬表」。範例題看 groupby 加總+nlargest 前三名。
  7. 合併(combine):pd.merge(左, 右, on="鍵", how="inner") 像 SQL JOIN,橫向按鍵對;pd.concat([a, b]) 像疊積木,縱向(或橫向)直接接。範例題看 query 篩選+inner merge 留下誰。
  8. 輸出(export):df.to_csv("out.csv", index=False)、to_excel、to_parquet(欄式格式,大資料更省空間)。index=False 不然 Index 會變成多一欄。

🎮互動:DataFrame 操作模擬器

下面內建一張 10 列的訂單表(客戶、城市、金額、日期)和一張 5 列的「城市→區域」對照表。點操作按鈕,右邊立刻顯示結果表與對應的 Pandas 程式碼。注意看每次操作後的形狀與Index 怎麼變。

📜 程式碼

📋 結果

🔀寬表 vs 長表:melt 與 pivot

同一份資料可以有兩種長相。寬表(wide):一列一個主體、每個月各一欄,人看最舒服;長表(long/tidy):一列一筆觀測(城市、月份、金額三欄),程式與繪圖最好處理——seaborn、groupby 都喜歡長表。

寬表 wide(3 列 × 3 欄) 城市1月2月 台北1200300 台中800950 高雄1500400 melt:欄名「融」進一欄 pivot:把一欄「攤」成多欄 長表 long(6 列 × 3 欄) 城市月份金額 台北1月1200 台中1月800 高雄1月1500 台北2月300 台中2月950 高雄2月400 melt 後列數 = 原列數 × 被融的欄數(3 × 2 = 6);資料沒變,只是「長相」變了
# 寬 → 長:id_vars 留著當身分,其餘欄名跑進 var_name、值跑進 value_name
long = wide.melt(id_vars="城市", var_name="月份", value_name="金額")

# 長 → 寬:index 當列、columns 當欄、values 填格子;重複鍵要用 pivot_table 指定 aggfunc
wide = long.pivot_table(index="城市", columns="月份", values="金額", aggfunc="sum")

完整題目走一遍:melt 加 barplot 畫出什麼?六根條=groupby 一字不差。

⚡向量化 vs for 迴圈;記憶體與 chunksize

向量化(vectorization):一次對整欄動手

# ❌ 慢:Python 迴圈一格一格算
total = []
for i in range(len(df)):
    total.append(df.loc[i, "金額"] * 1.05)
df["含稅"] = total
# ✅ 快:整欄一起算(底層是 C 的 NumPy)
df["含稅"] = df["金額"] * 1.05

# 條件也向量化
df["大單"] = df["金額"] > 1000
df["等級"] = np.where(df["金額"] > 1000, "A", "B")

迴圈每一格都要經過 Python 直譯器;向量化把整欄丟給底層 C 程式一口氣算完,十萬列的差距常是數十到數百倍。apply 本質上還是逐格呼叫 Python 函式,比迴圈好讀、但不會比向量化快。優先順序:原生運算子/內建方法 > np.where/map > apply > for 迴圈。

記憶體:DataFrame 是整張載進 RAM 的

一個 10 GB 的 CSV 讀進來不會只佔 10 GB——字串欄用 object 型別時每格都是一個 Python 物件,常膨脹 2–5 倍。三招:

chunksize 的經典陷阱:「每塊各算平均、再把平均平均起來」是錯的(每塊列數不同)。正確做法是每塊累加 sum 與 count,最後才相除——只有能拆成「可累加的部分和」的統計量才能串流。逐行解剖:chunksize 與 TextFileReader、chunksize 串流平均的陷阱。

時間序列的 rolling/shift 也屬於轉換這一步,且很容易「偷看未來」造成資料洩漏:rolling 移動平均與 shift 落後特徵。

🤔最容易混淆的六組配對

配對前者後者一句記法
loc vs ilocloc 用標籤(列名、欄名),切片含尾端iloc 用整數位置,切片不含尾端(像 Python list)l=label,i=integer
merge vs concatmerge 按鍵橫向對齊,像 SQL JOIN,有 inner/left/right/outerconcat 直接疊,預設縱向(axis=0),不看鍵merge 要有共同鍵,concat 只要形狀合
map vs applySeries.map 逐值對應,可吃 dict/Series/函式apply 可用在 Series(逐值)或 DataFrame(逐列/逐欄,用 axis 控制)查表用 map,複雜邏輯用 apply
groupby vs pivot_tablegroupby 結果是「長」的(分組鍵當 Index)pivot_table 是 groupby 後再攤成「寬」的二維交叉表pivot_table = groupby + unstack
melt vs pivotmelt 寬→長,欄名融進一欄pivot/pivot_table 長→寬,一欄攤成多欄互為反操作;有重複鍵用 pivot_table
info vs describeinfo() 看型別、非空數、記憶體describe() 看count/mean/std/min/四分位/maxinfo 管結構,describe 管分布
merge 的 how 怎麼記?inner=兩邊都有才留;left=左邊全留、右邊對不到補 NaN;right 相反;outer=兩邊全留。另外,鍵有重複會「爆列」:左邊某鍵 3 列、右邊同鍵 2 列,合併後會變 3×2=6 列。

⚠️常見誤區與陷阱

🔢篩選後 Index 不會重排
df[df["金額"]>1000] 的 Index 還是 0, 2, 4…;之後 iloc[0] 與 loc[0] 可能指向不同列。要重排加 .reset_index(drop=True)。
🧮有 NaN 的整數欄會變 float
NaN 是浮點數,所以 [1, 2, NaN] 的 dtype 是 float64,印出來是 1.0、2.0。要保留整數用可空型別 "Int64"(大寫 I)。
📎SettingWithCopyWarning
df[df.a>1]["b"] = 0 是「鏈式索引」,改的可能是副本、原表沒變。正確寫法:df.loc[df.a>1, "b"] = 0。
↩️大多數方法回傳新物件
df.dropna() 不會改 df 本身,要 df = df.dropna() 或 inplace=True(官方不建議,難以串接)。
🔗groupby 後鍵跑到 Index
df.groupby("城市")["金額"].sum() 回傳 Series、城市是 Index;要當普通欄加 .reset_index() 或一開始 as_index=False。
🪤head(3) 不等於前三名
head 是「前 3 個位置」,沒排序就不是名次;要名次先 sort_values 或直接 nlargest(3, "金額")。

✅自我檢測

Q1. df.iloc[0:2] 會取出幾列?

Q2. 想得到「每個城市的總金額」,哪個方法最直接?

Q3. 左表 10 列、右表 5 列,用 how="inner" 以「城市」合併;左表有 1 列的城市右表沒有,右表有 1 個城市左表沒有。結果幾列?

Q4. 一張「城市 × 1月、2月、3月」的寬表要變成「城市、月份、金額」三欄的長表,用哪個?

Q5. 用 chunksize 分塊讀 CSV 要算整欄平均,正確做法是?

🎯重點整理

📝 iPAS 考點提醒

Pandas 是 iPAS 中級科目二「大數據處理分析與應用」的程式題主力。典型題型:給一段 4–8 行的 Pandas 程式,問「輸出幾列幾欄」「印出什麼」或「哪個方法能達成需求」。高頻考點:① groupby 加總後鍵跑到 Index、head 不是名次要先 sort 或用 nlargest;② merge 的 how(inner 掉列、left 補 NaN)與鍵重複爆列;③ melt/pivot_table 寬長互轉後的列數計算;④ 篩選後 loc vs iloc 行為差異、Index 不重排;⑤ fillna 後 NaN 讓整數欄變 float、Int64 可空型別;⑥ chunksize 串流只能累加 sum/count、不能平均再平均。易混點:info vs describe、map vs apply、concat vs merge。情境題長相:「某電商要算各區域月銷售前三名,資料分成訂單表與城市對照表,應依序使用哪些操作?」答案通常是 merge → groupby → sort_values/nlargest。

想練情境題與詳解 → AI 學習與考證地圖

❓ 常見問題

Series 和 DataFrame 差在哪?

Series 是一維、帶 Index 的一欄資料;DataFrame 是多條 Series 並排、共用同一個 Index 的二維表。df["欄"] 回傳 Series,df[["欄"]] 回傳 DataFrame。

loc 和 iloc 怎麼分?

loc 用標籤(列名、欄名)且切片含尾端;iloc 用整數位置且切片不含尾端。篩選後 Index 不會重排,所以 loc[0] 可能 KeyError、iloc[0] 永遠是第一列。

merge 和 concat 什麼時候用哪個?

兩張表有共同鍵、要像 SQL JOIN 橫向對齊補欄位時用 merge;只是把形狀相同的表上下(或左右)疊起來用 concat。merge 的 how 決定掉不掉列:inner 掉、left 補 NaN。

melt 和 pivot 是什麼關係?

互為反操作。melt 把寬表的多個欄名融成一欄(寬→長,列數=原列數×被融欄數);pivot/pivot_table 把一欄的值攤成多個欄(長→寬),有重複鍵時要用 pivot_table 指定 aggfunc。

groupby 的結果為什麼不能直接當欄用?

因為分組鍵跑到 Index 了。加 .reset_index() 或一開始用 as_index=False,鍵就會變回普通欄。

為什麼要用向量化而不是 for 迴圈?

向量化把整欄交給底層 C 的 NumPy 一次算完,迴圈每格都經過 Python 直譯器,十萬列常差數十到數百倍。apply 也是逐格呼叫 Python 函式,比迴圈好讀但不會比向量化快。

chunksize 可以算哪些統計量?

只能算「可拆成部分和再合併」的量:sum、count、min、max、平均(累加 sum 與 count 最後相除)。中位數、分位數不能直接串流,需要近似演算法或先排序。

🧭 相關主題

← 返回 AI 學習與考證地圖