📘 機器學習自學 EP.2 |資料清理:我的模型那麼乖,一定是資料教壞我家模型的

更新 發佈閱讀 12 分鐘
資料是未曾整理過的夢。 
它記得一切,也遺漏一切。
模型從中覓路,卻往往迷失在我們未曾察覺的錯誤裡。

📝 前言

我第一次接觸機器學習,是在碩士班的一門課程上。老師發給我們一份範例 code,讓我們試著跑跑看模型會怎麼預測。課程中有兩次實作考試,一次是經典的入門題目:Titanic - Machine Learning from Disaster,另一次則是使用 0056 這支股票資料,進行價格預測的練習。

因為整堂課只有短短一學期,老師為了讓我們順利上手,兩次都提供了可以直接執行的標準程式碼。我們只需要稍微補一下缺值、處理基本前處理,接著重點就放在「去調整模型」、「優化分數」上。

我照著要求去調參、改變訓練集比例、甚至測試不同模型組合,卻怎麼都無法明顯提升分數。那時我開始懷疑:是不是模型不夠好?還是我根本不會機器學習?

直到後來,我才逐漸發現:不是模型學不好,是資料一開始就給錯了東西讓它學。

❓所以為甚麼要進行資料清理?

我們都知道,機器學習的本質,是餵給模型大量的因果對應,讓它從中學出潛藏的規律。你給它什麼因,它就會學出什麼果。

這也是為什麼在這個領域裡,有句老話:"Garbage in, garbage out."

模型本身不懂夜的黑,它沒有像人類那樣的物件性直覺、語意聯想、或情境推理。
即使再強大的模型,也只能從你提供的資料裡學習世界的輪廓。你給它的,是雜訊,它學到的,就是失真。

資料清理,說穿了不是在幫模型打掃,而是在幫它學會看見。
那麼,資料會出現哪些狀況,需要我們幫它重新整理、還原語意呢?
資料清理的部分就有太多能聊了,一時半刻真的講不完,因此,
下面我會從幾個我實際碰過的幾個情境出發,簡單介紹一下。

🔧 缺失值(Missing Values):不是填上空白就沒事

一開始我處理缺失值的方法很單純:有缺就補,最簡單的那種。
平均數、中位數、乾脆全刪掉──老師這樣教,網路上也是這樣寫,我自然也就這樣做了。有時候還會出現一種幻覺:欄位看起來填滿了,心裡也就踏實了。

但預測出來的結果卻狠狠地打了我一拳,分數悽慘無比,在鐵達尼號這個已經被大家玩到透徹的比賽裡,我連前50%都到不了。

後來又遇到 Santander 的匿名特徵,有些欄位乾脆缺了一半,我開始困惑:
這種幾乎都空的資料,真的該留下來嗎?還是乾脆刪掉?

缺值到底代表什麼?它真的是「遺失」了某種資訊,還是其實在「暗示」什麼?

🧹 常見的處理方法有哪些?

針對缺失值,大部分人會採取以下幾種做法:

  1. 用統計值補上去
    像是平均數(mean)、中位數(median)、最多出現的值(mode)等等。這是最常見、也最容易上手的方法,尤其當你只是想先跑出 baseline 結果時。
  2. 分組後補值(Group Imputation)
    如果覺得整體補一個平均數太粗暴,也可以根據其他欄位分群(像是在鐵達尼號中,依照性別、船艙等級、上船地點等),對每一群分別補值,這樣的邏輯會更貼近資料本身的結構。
  3. 直接丟掉(Drop)
    當缺值筆數太多,或某欄幾乎全缺,可以選擇直接刪除那些資料或欄位。不過這種做法一定要小心──刪完可能會破壞整體分布,甚至不小心誤刪掉有意義的訊號。
  4. 轉換成「是否缺值」的訊號
    有些時候,缺值本身就是一種信號(例如:沒填地址可能代表不願透露、不是常駐用戶等)。這時候可以新增一個欄位來標示「是否缺值」,讓模型學習「缺」和「不缺」本身的意義差異。

除此之外,還有許多其他補值策略,針對不同情況會有不同的處理方法,這邊很難一次說完。後續在介紹各題目的時候,我會再補充當時實際採用的方式與遇到的思考盲點。

🧨 異常值(Outliers):看來離譜,卻可能藏著訊號。

有時候我們打開資料,會發現一些「怎麼看都怪怪的」的值。

像是年齡寫成 999 歲、一個名字是 Mr. 的人性別卻標示為女性、或是商品售價普遍在 100 元左右,卻突然出現一筆 10,000 元的紀錄。 這些資料,不一定是錯,但一畫出分布圖,就會發現它們飛得比別人遠很多

這就是我們說的「異常值」: 在整體資料趨勢中,它們是少數派,是離群者,有時是錯誤,有時卻也是最關鍵的訊號來源。

🛠️ 怎麼發現與處理異常值?

異常值不是壞人,它們只是特別。

但如果你沒先注意它們,模型會因為這些特例而失去方向感,做出離譜的預測。以下是我常用的幾種處理方式:

  1. 畫圖先看(Boxplot / Scatterplot)
    畫出來,你就會知道有沒有問題。
    像是 boxplot 很適合看數值欄位的離群值,只要有「鬍鬚飛天」的,就值得進一步看看發生什麼事。散佈圖也能幫助你在多變數中發現不合群的點。
    Boxplot與散布圖都能明確的看到離群的狀況
  2. 統計判斷(IQR / Z-score)
    你可以用 IQR(四分位距)來篩選離群值,方法是找出超過 Q3 + 1.5×IQR 或低於 Q1 - 1.5×IQR 的點。
    或是使用 Z-score,當一個值的 Z-score 超過 ±3,就可以被視為異常。
  3. 壓尾(Winsorize)
    如果你不想刪掉資料,又怕極端值干擾模型學習,可以將太大的值「壓」到某個百分位內(例如把超過 95% 的值通通設為 95% 分位值)。這樣可以保留資料筆數,又減少極端影響。
  4. 新增欄位當作標記(Outlier Flag)
    有些異常值反而代表某種族群或行為(像是高價客戶、機器誤讀等),這時候你可以不要刪,而是加一欄「這筆是不是異常」,讓模型自己學學看這是不是個關鍵因子。

✅ 要不要刪?還是要留?或者要改?
最關鍵的不是「處理掉」異常值,而是「理解」它。
你得先搞懂這筆資料到底是錯的、特例、還是真相的一部分。
否則你可能把關鍵樣本當成錯誤資料刪掉,結果模型就再也學不到那個方向了。
哪種方法適用?該刪還是該留?沒有標準答案,這需要工程師根據具體問題來判斷策略。

🧾資料型別錯誤(Data Type Errors):你其實不是你自己

有些資料,看起來沒問題,實際上卻「偽裝成別的東西」。

舉例來說:

  • 數字卻是文字:
    像「001」、「50」這類欄位,看起來是數字,但實際上是 字串格式(object/string)。如果你直接拿去計算平均、建模,就會出錯或被模型忽略。
  • 類別卻變成數字:
    像「1」代表男性、「2」代表女性,這其實是類別資料(categorical),但很多時候它們會被系統當成數值來處理。模型可能會錯誤地以為「2 > 1」表示女性比男性多一倍,結果導致預測偏差。
  • 日期變成文字串:
    「2022-05-01」若是被讀成文字,那就不能做時間差計算、排序或擷取年月,許多時間序列模型會因此失效。

🛠️ 常見處理方式:

  1. 轉換成正確格式(astype / pd.to_datetime)
    • 把「看起來像數字的字串」用 .astype(int) 或 .astype(float) 轉成數值
    • 把「日期字串」轉為 datetime 格式
  2. 釐清欄位意義
    • 例如身份代碼、產品 ID 即使是數字,也應該視為類別,轉為 category 類型處理
    • 一旦搞錯類別/數值的身份,模型可能會用錯方式處理(例如對類別去平均)

🧭 這些錯誤從哪裡來?

最常見的原因其實很單純:

  • Excel 自動把資料判成文字或數字
  • 來自不同系統合併的資料型別不一致
  • 開頭零被吃掉(像郵遞區號「00320」變成 320)
  • 多語系輸入、API 介接時未標準化

這類錯誤通常不會馬上報錯,但會讓你在建模時卡關、出現莫名其妙的 NaN、甚至整份預測結果偏掉。


這些型別錯誤,常常是資料清理最容易忽略的一環,卻對整體建模影響巨大。

不只會讓統計分析失準,還會讓 One-Hot Encoding歸一化(Normalization) 無法順利進行,甚至讓整個模型報錯崩潰。

📌 你以為它是誰,其實它不是誰——這樣的資料最可怕。

🧾 類別不一致(Inconsistent Categories)

資料格式對了,也不代表語意就正確。

很多時候,我們面對的不是「資料型別錯誤」,而是「資料表達方式不一致」。

像是:

  • "男", "Male", "M", "男生" —— 其實都在說男性
  • "台北", "Taipei", "臺北市" —— 本質上是同一個地點
  • "否", "No", "0" —— 都是在表達「沒有」

這種錯誤,表面上看不出問題,實際上會讓模型把這些值當成完全不同的類別,導致:

  • One-Hot Encoding 生成多個重複維度
  • 分布計算嚴重失真
  • 模型學不到一致性的規則

🛠️ 常見處理方式:

  1. 字串標準化(Lowercase / Strip / Replace)
    • 把所有字串轉為小寫、小寫轉數字、移除空白、統一簡繁字等等
    • 例如:" Male " → "male","臺北" → "台北"
  2. 映射轉換(Mapping / Dictionary Encoding)
    • 你可以手動或自動定義一個轉換表,將相同語意的類別標準化
    • 例如:{"M": "male", "男": "male", "male": "male"}
  3. 合併低頻類別(Group Rare Categories)
    • 有些類別數太多(像產品型號、使用者 ID 等),你可以把出現次數太低的類別歸為一類,避免維度爆炸

⚖️樣本不均衡(Imbalanced Data):少數派報到

有些資料,在標籤分布上就天生「不公平」。

例如:

  • 你要預測誰會中樂透,大部分人都不會中。
  • 你要偵測詐騙交易,真正詐騙只有千分之一。
  • 你做癌症預測,健康樣本遠遠多於患者。

這些狀況下,如果你直接拿這樣的資料去訓練模型,它很可能學會了:「我猜大家都正常,就能拿到很高準確率」。

但這種準確率毫無意義。因為模型根本沒學會怎麼分辨「異常」或「少數派」。

🛠️ 常見處理方式:

  1. 重新採樣(Resampling)
    • 過採樣(Over-sampling):把少數類別複製、或用 SMOTE 等方法合成更多類似樣本
    • 欠採樣(Under-sampling):從多數類別中隨機抽樣,讓它與少數類別數量接近
  2. 改用不敏感於不均衡的評估指標
    • 不要只看 accuracy,改用: F1-score(平衡 precision 與 recall) AUC(整體排序能力) precision / recall curve
  3. 使用支持 class weight 的模型
    • 很多模型(如 SVM、XGBoost、Logistic Regression)都可以調整 class_weight,讓模型在訓練時「多注意」少數類別

📌 少數派不是沒價值,而是更需要被注意。資料的公平,從清理時就該開始做起。

🔚 結語

資料清理的方式千變萬化,許多技巧其實早已和接下來要談的「特徵工程」密不可分。
這一章沒辦法一次說完所有狀況,也不敢說自己已經學會了全部。更真實的情況是:
我們補了資料、做了工程,分數卻降了;以為合理的處理,卻反而害模型看錯方向。
資料處理從來不是單選題,而是一場猜測與驗證交錯的旅程。
我們只能仰賴一遍遍的嘗試,一次次的視覺化與分析,慢慢去理解:
哪些資料,適合怎樣的處理;哪些模型,又能從中學到什麼。
這,就是資料清理之所以難,也之所以重要的地方。

留言
avatar-img
夕月之下
0會員
9內容數
在模型尚未收斂前,記下語言的提示與意圖。觀察者、語言與語言模型的交界。