iPAS AI 應用規劃師 中級 科目二 大數據處理分析與應用

Year 欄位含 NaN,怎麼安全轉換成整數?

原題 44

研究團隊接下來想要將 Year 欄位轉換為整數型態,以便後續進行年份趨勢分析。考慮到資料中可能包含缺失值(NaN),請選出最合適的轉換方式。

白話

vgsales.csv 的 Year 欄位目前是 float64,部分資料有缺失值(NaN)。研究團隊要把它轉成整數型態,方便做年份相關的趨勢分析。四個選項各提供了不同的轉換語法,有的在碰到 NaN 時會直接報錯,有的會用假值填補,有的能保留 NaN 同時轉成整數型別。

問你:在資料可能含有缺失值的情況下,哪一種轉換方式最合適?

點選你的答案。

01 總結

一句話總結

含缺失值的欄位要轉整數,最合適的方式是 astype('Int64')(大寫 I):這是 pandas 的可空整數型別,可以同時存放整數值和 NaN,不需要先填補缺失值。直接 astype(int) 會報錯,fillna(0) 或 fillna(1) 用假值污染資料。

02 情境

先感受問題:轉型前要先處理 NaN 嗎?

遊戲研究公司的分析師小凱確認了 Year 欄有幾筆 NaN(某些遊戲沒有記錄發售年份)。他要把 Year 轉成整數以便按年份計算趨勢,但馬上發現問題:

方案一:直接 astype(int)
→ 執行後立刻報錯:Cannot convert non-finite values (NA or inf) to integer

方案二:fillna(0).astype(int)
→ 不報錯,但缺失年份被填成 0,分析時會出現「0 年」的假資料,污染趨勢圖

方案三:fillna(1).astype(int)
→ 同樣污染,缺失年份變成「西元 1 年」,更荒謬

方案四:astype('Int64')(大寫 I)
→ 成功轉換,dtype 變成 Int64,NaN 保留為 <NA>,不污染資料

正確答案是方案四:用 pandas 的可空整數型別 Int64,讓缺失值保持缺失,不用假值填補。

03 對照

三個錯誤做法各有什麼問題

  1. astype(int) 直接轉型:numpy 的 int 型別不支援 NaN,遇到缺失值就拋出 ValueError,整個轉換中斷。只有在確認資料完全沒有缺失值的情況下才能安全使用。
  2. fillna(0).astype(int) 填零再轉:技術上不報錯,但把缺失年份填成 0,年份分析時「西元 0 年」的資料就成了假資料。做趨勢圖時 x 軸會多一個 0,嚴重干擾視覺呈現和統計結果。
  3. fillna(1).astype(int) 填 1 再轉:和 fillna(0) 同樣的問題,只是假值換成 1,遊戲發售年份出現「西元 1 年」更不合邏輯,是語義上更嚴重的錯誤。
  4. 不處理 NaN 就分析:如果不轉型就直接做年份趨勢分析,float64 的年份計算可能出現 2006.0 這樣的小數年份,且 NaN 會在 groupby 等操作時被自動跳過,行為有時不符合預期。
  5. drop NaN 後再轉型:dropna() 後再 astype(int) 是另一種做法,但這會永久刪除有 NaN 的整筆資料,損失其他欄位的有效資訊。Int64 保留 NaN 是更好的選擇。
04 解法

astype('Int64') 一行搞定:轉整數又保留缺失值

小凱最終採用:

data['Year'] = data['Year'].astype('Int64')

轉換後驗證:
data['Year'].dtype → Int64
data['Year'].isna().sum() → 同前(NaN 筆數不變)
data['Year'].head() → 2006, 1985, 2008, <NA>, 2010(有缺失的顯示 <NA>)

轉換後 dtype 顯示 Int64(大寫),缺失值以 pandas 的 <NA> 表示,不是 numpy 的 nan,且整欄都是整數值,可以直接做年份趨勢分析。這就是選項 D 講的:data['Year'] = data['Year'].astype('Int64')

技術版:Int64 vs int64 的差別與可空整數型別

中級考試大概率會考程式碼跟公式,所以這部分你還是要學。但如果現在學起來很痛苦,可以先跳過,等讀完其他題目回頭再來。

Step 1 純故事版

想像兩種信封:一種只能裝數字(numpy int64),另一種可以裝數字或一張「此信封空著」的說明卡(pandas Int64)。當你有幾封空信封時,只能用第二種信封盒子來收納它們。fillna(0) 是把空信封強制塞進「0」這個假內容,讓人以為裡面有東西。astype('Int64') 是換成能正確標記「空著」的信封盒,不需要造假。

Step 2 中文 ↔ 程式碼對照
情境程式碼與結果
直接轉,有 NaN 時報錯astype(int) → ValueError
填 0 後轉,NaN 變假資料fillna(0).astype(int) → dtype: int64,NaN→0
轉可空整數,NaN 保留astype('Int64') → dtype: Int64,NaN→<NA>
確認型別data['Year'].dtype → Int64
確認缺失值個數不變data['Year'].isna().sum()
Step 3 符號角色表
int64(小寫 i)
numpy 的 64 位元整數型別,不支援 NaN,遇到缺失值報錯。
Int64(大寫 I)
pandas 1.0+ 推出的可空整數型別(Nullable Integer Dtype),用 pandas.NA 表示缺失值,支援整數和 NaN 共存。
pandas.NA 和 numpy.nan
Int64 欄的缺失值顯示為 <NA>(pandas.NA),與 float64 欄的 nan(numpy.nan)不同,但 isna() 和 isnull() 都能偵測到兩者。
astype()
pandas Series 的型別轉換方法,傳入字串 'Int64' 時使用可空整數,傳入 int 時使用 numpy int(不可空)。
fillna()
用指定值填補缺失值的方法,使用時需確保填入的值在語意上合理,否則會污染資料。
Step 4 完整公式對應

本題沒有數學公式,核心是 pandas 的型別系統設計:

  • numpy int64:不可為空,記憶體效率高,不支援 NaN。
  • pandas Int64:可為空(Nullable),底層用 numpy int64 + 一個 boolean 遮罩(mask)標記哪些位置是 NA,記憶體比 float64 更精確表達整數意圖。
  • float64:浮點數,用 IEEE 754 的 nan 表示缺失,轉整數後會有精度疑慮(2006.9999 可能因捨入誤差導致問題)。
Step 5 自我複述
  1. astype(int) 和 astype('Int64') 最關鍵的差別是什麼?
  2. fillna(0).astype(int) 技術上不報錯,為什麼在年份分析中是壞做法?
  3. Int64 的缺失值顯示為 <NA>,和 float64 的 nan 有什麼不同?isna() 都能偵測嗎?
  4. 如果已確定 Year 欄完全沒有缺失值,應該用 astype(int) 還是 astype('Int64')?
  5. 讀 CSV 時如果想直接把 Year 欄讀成 Int64,應該怎麼寫 read_csv 參數?
05 陷阱

為什麼其他選項是錯的

選項 A astype(int)

字面在說什麼:直接把 Year 欄轉成整數型態。

為什麼不對:numpy int(即 int64)不支援 NaN 值。Year 欄有缺失值,執行 astype(int) 時會拋出 ValueError:"Cannot convert non-finite values (NA or inf) to integer"。程式會在這行中斷,無法繼續執行。

誰會選錯:只知道「轉整數用 astype(int)」但不知道 int 無法存 NaN 的人,或者沒有仔細看題目說「考慮到可能包含缺失值」這個提示的人。

選項 B fillna(0).astype(int)

字面在說什麼:先把缺失值填成 0,再轉整數,兼顧了 NaN 問題和型別轉換。

為什麼不對:技術上不報錯,但語意上錯了。把缺失的年份填成 0(西元 0 年)是無意義的假資料。後續做年份趨勢分析時,x 軸出現「Year = 0」,嚴重影響視覺化和統計正確性。題目說「最合適」,語意上正確才算合適。

誰會選錯:只想解決「不能有 NaN」的問題,沒有考慮填入假值對後續分析的影響。看到「不報錯」就認為是正確答案的人。

選項 C fillna(1).astype(int)

字面在說什麼:先把缺失值填成 1,再轉整數,這樣 NaN 問題和型別轉換都解決了。

為什麼不對:和選項 B 同樣的問題,只是假值更荒謬。把遊戲缺失的發售年份填成 1(西元 1 年),比填 0 更明顯是錯誤的,任何人看到 Year = 1 都知道是假資料。fillna 填入的值必須要有語意合理性,1 對年份分析沒有任何意義。

誰會選錯:同選 B 的人,但選了更荒謬的填補值。

06 變形

同個考點下次怎麼變形

變形 1 邊界

直覺:轉成 Int64 之後,還能對 Year 欄做 groupby 或算術運算嗎?

答案:可以。Int64 欄支援 groupby、sum()、mean() 等操作,行為和 int64 類似。差別在於:涉及 <NA> 的計算預設會跳過缺失值(類似 skipna=True),不會因為 NaN 讓整個聚合結果變成 NaN。這讓後續的年份趨勢分析(例如每年遊戲銷售量 groupby Year)能正確運作。

變形 2 反例

直覺:如果確定 Year 欄完全沒有缺失值,用 astype(int) 還是 astype('Int64') 更好?

答案:沒有缺失值時,astype(int) 或 astype('int64') 稍微更好,因為 numpy int64 的記憶體效率比 pandas Int64 高(Int64 需要額外的 boolean 遮罩),且與 numpy 運算的相容性更高。但如果不確定資料後續會不會引入 NaN,保守起見用 Int64 也沒問題。

變形 3 升級版

直覺:除了 astype('Int64'),還有什麼方法可以把有 NaN 的 float64 欄轉成整數型態?

答案:兩種:(1) pd.array(data['Year'], dtype='Int64'),等效於 astype('Int64')。(2) 如果確定要刪掉有 NaN 的資料,先 dropna(subset=['Year']) 再 astype('int64'),但這會永久刪除整筆資料列。最安全的做法仍是 astype('Int64'),保留缺失值資訊,後續視分析需求決定如何處理。

變形 4 跨領域

直覺:什麼時候應該填補缺失值(fillna),什麼時候應該保留缺失值(Int64)?

答案:保留缺失值(Int64):缺失本身有意義(例如某遊戲真的沒有記錄年份),或後續分析工具能自動跳過 NaN。填補(fillna):缺失值必須被處理才能進行特定分析(例如機器學習模型不接受 NaN),且填入的值語意合理(例如年齡缺失填平均年齡)。以中位數、平均數、眾數填補是常見的合理策略;填 0 或 1 通常是語意錯誤的。

變形 5 評估指標

直覺:轉換後如何確認 Int64 轉換是否成功、NaN 是否正確保留?

答案:兩行驗證:data['Year'].dtype 應該顯示 Int64(注意大寫 I);data['Year'].isna().sum() 的結果應與轉換前相同(缺失值個數不變)。如果 dtype 是 int64(小寫)就表示轉換到了 numpy int,不是可空整數。isna().sum() 變成 0 表示缺失值被意外填補了,需要重新檢查轉換步驟。

07 延伸

想再往下看,這 5 個

出處

iPAS 經濟部產業人才能力鑑定 ・ 114 年第二梯次 iPAS AI 應用規劃師 中級 科目二 大數據處理分析與應用 第 44 題

查看官方原文 PDF