攝影或3C

Python pandas iterrows:為什麼你改 row 沒有效果?正確更新 DataFrame 的方法

摘要

  • iterrows 產生的是每列的 Series 拷貝;你修改 row 不會回寫到原 DataFrame。
  • 正確做法:在迴圈中用 .loc/.at 回寫,或更推薦用向量化一次性更新。
  • 大量資料時,盡量避免逐列回寫,改成批次或向量化以提升效能。

一、為什麼改 row 不會改到原 DataFrame?

  • iterrows 迭代時,row 是一個 Series(通常是值的複本)。你在 row[“A”] 上的賦值,只是改了這個臨時 Series。
  • pandas 並不保證 iterrows 提供的是 view;實務上把它視為 copy,修改不會影響 df。
  • 這跟 Python 的 for x in list: x = … 也不會改到原清單的概念相似:你改的是迭代到的變數,不是容器裡的元素。

範例:修改 row 失敗的常見陷阱

# %%
import pandas as pd

df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})

for idx, row in df.iterrows():
    row["A"] = "999"  # 這只改了拷貝
print(df)
#    A  B
# 0  1  3
# 1  2  4  ←  df 沒變

輸出:

row[“A”] = 999 #int 可以成功,
但不要依賴這種不可靠的方式:

二、正確更新 DataFrame 的方式

  1. 在迴圈內用 .loc 或 .at 回寫
  • .loc 用於標籤定位;.at 是單一標量更新的高效版本。
  1. 先收集到列表或 Series,最後一次性指派(推薦)
  • 避免在迴圈中反覆觸發寫入,效能更佳
    (除非迴圈數太多,每一次迴圈都做存檔動作,
    以免意外中斷,前功盡棄
    非效能考量的話,可使用方法1)。
  1. 使用向量化/批量運算(最佳)
  • 能不用迴圈就不用迴圈,pandas 的設計哲學就是這樣更快。

三、MultiIndex 欄位或奇怪欄名時的注意事項

  • 迭代時,row 的欄位鍵可以是 tuple(例如 (‘A’,’x’))。用 .loc 回寫時也用相同鍵。
col_key = ('A','x')
for idx, row in df.iterrows():
    df.loc[idx, col_key] = 123
  • 欄名若包含空白、符號、或非合法標識符,
    請不要用屬性存取(row.A),改用 row[“A B”] 或 row[(“A”,”B”)]。

四、效能與可靠性建議

  • 少量更新:迴圈 + .at/.loc 沒問題。
  • 大量更新(上千上萬列):先計算成列表/Series 再一次性賦值,或直接向量化。
  • 需要逐步保存(長任務/外部 API):每 N 筆 checkpoint 存檔,支援續跑。
  • 避免 SettingWithCopy 警告:回寫請用 .loc/.at,而不是 df[df[“cond”]][“col”] = …

五、常見問答

  • Q: 那 iterrows 有什麼用?
    • A: 便於逐列讀值、生成字串、呼叫外部 API 等「讀多寫少」的情境。
  • Q: 想就地修改,能用 itertuples 嗎?
    • A: 也不行,itertuples 回傳 namedtuple,屬性是唯讀;修改依然需要 df.loc 回寫。
  • Q: 有沒有更快的逐列方法?
    • A: apply 比 iterrows 常更簡潔,但本質仍迭代;速度差距視情況而定。真正的加速還是向量化或用 NumPy。

六、總結

  • 記住一句話:iterrows 是讀,不是寫。要寫就用 .loc/.at,或更好的是向量化/一次性指派。

推薦hahow線上學習python: https://igrape.net/30afN

儲蓄保險王

儲蓄險是板主最喜愛的儲蓄工具,最喜愛的投資理財工具則是ETF,最喜愛的省錢工具則是信用卡