在開始之前
誰適合讀這篇文章?
- 已對 Machine Learning 理論有一定基礎、且實際用公開資料集建過幾個模型,但尚未處理過任何企業 raw data。
- 具 Kaggle 實戰經驗,但準備要用公司亂糟糟、沒有整理過的資料來建模的新鮮人
為什麼會有這篇文章?
這些都是過去我親身踩過的雷,這些也是在大學或線上課程中,比較少會在課程上被強調的部分。希望藉由整理出這些經驗,能讓即將要踏入資料科學/機器學習領域的夥伴作為借鑒,讓大家能夠少走一些冤枉路。
機器學習流程
在正式開始之前,我們來複習一下機器學習的流程。我認為上面這張圖很好的解釋了工作上常見的場景,每個步驟都會影響到下個階段,它們是環環相扣的。大致上分成五個階段:
- Data Retrieval
包含資料從哪裡來、如何取得資料,依照公司性質而不同。例如在甲方(客戶端),可能由資料工程團隊提供,或是自己直接撈資料庫;在乙方(廠商端)則通常由客戶提供。在 Kaggle 就是已經預先完成 Data Retrieval 的部分。
- Data Preparation
Data Processing & Wrangling:這個階段會將來自不同資料表的原始資料進行 merge & join 的動作。
Feature Extraction & Feature Engineering:將原始資料轉換成可以餵給模型的格式,萃取出有意義的特徵。今天要介紹的 NA Value 就是發生在這個階段
Feature Scaling & Selection:調整各個特徵之間的尺度,以及挑選有用的特徵。對於某些特定演算法來說,如果特徵的尺度差異太大,會影響演算法的結果。例如A欄位是1-100而B欄位是1000-100000,對於 regression、neural network 就會有很大的影響。
- Modeling
挑選出表現最好的模型。
- Model Evaluation & Tuning
根據問題類型,用適當的指標來評估模型好壞,並根據評估結果優化模型。
- Deployment & Monitoring
將完成的模型部署到特定環境做上線應用,持續產出最新的訓練結果。如 Youtube、Netflix 隨時都會替我們推薦新的內容。
而今天要介紹的三件事與上述流程的對應關係是:
- Duplicate Record 發生在 Data Processing & Wrangling
- NA Value 發生在 Feature Extraction & Engineering
- Data Leakage 從 Data Retrieval 到 Data Preparation 都有可能發生
以上就是對機器學習流程非常簡略的介紹,這邊主要是讓大家認識今天要介紹的三件事分別在哪個階段,對整個流程也能有更清楚的輪廓。
那我們開始吧!
[optin-monster-inline slug=”nlwltgi3dphgrg101jjg”]
NA Value
相信如果是有建過模型的你,應該對NA值這個名詞不陌生。如果是打 Kaggle 比賽出身的話,可能會比較少遇到一些,因為在 Kaggle 上大部分都是整理得很好的資料集。不過我相信會來讀這篇文章的你,應該都對這個名詞不陌生。
甚麼是 NA Value
NA Value 是簡寫,有三種意義:
- Not Available
- Ex: 生產線上的感測器壞了,某段時間內無法傳送資料
- Not Applicable
- Ex: 請一個單身漢提供妻子的姓名
- No Answer
- Ex: 不願意提供性別與地址的電商會員
NA Value 就是資料欄位裡,某個列缺少了,不見了。因此也叫 Missing Value、缺漏值、遺漏值,都是指同一件事,為求方便,以下皆簡稱 NA 。通常是因為收集資料時遇到上述問題而產生。
例如,以零售來說,通常企業會為商品分類,但若推出新商品的速度太快而導致商品分類來不及維護,就會產生有商品不屬於任何分類的狀況,此時資料裡分類的這個欄位就會出現 NA 。以電商來說,使用者若不願意提供性別或地址,那麼這兩個欄位就會為 NA 。
NA Value 大概就這麼回事,但是為什麼建立機器學習總是提到 NA 呢?它究竟有甚麼影響?
為什麼這很重要
主要有兩個原因:
- 無法建模
- 當資料集裡有 NA,是沒辦法餵入 scikit-learn、Neural Network 建模的。除非使用本身就支持自動補值的演算法,例如 XGBoost, lightGBM 等。
- 模型表現下降
- 當一個特徵裡 NA 的比例過高,這時即使演算法支持自動補值也不見得有用,因為補值的方法基本上還是基於資料分布而生成的。即使補值的方法再複雜,若特徵本身的資料已經太少,補出來的值對於模型來說可能仍然是噪音,造成模型的表現反而下降。
那麼該如何判斷特徵裡的 NA 比例是否過高呢?目前似乎沒有公認的答案,每個資料科學家對此也有各自的認知。以前我認為 30~40% 就非常高了,後來我發現也有同事認為 NA 比例達 10% 的話,他就直接不採用該特徵了。所以還是以個人的經驗決定。
常見的應對方法
1. 刪除
刪除有兩種:
- 刪除含遺失值的列:最為最簡單也最直覺的方法,就是直接刪掉該列。不過有時候當特徵數量一多,且特徵各自有 NA 時,容易遇到刪除過多資料的問題。再來若一個列裡只有一個特徵有 NA 就直接刪除,會損失其他欄位裡的資訊。
- 刪除含遺失值的特徵:我個人比較常用的方法。一般來說,我會列出所有欄位的 NA 比例,如果過高的話就會直接不採用。而多少比例算是過高,則如前面所述,見仁見智。有初步的判斷後,我會先用有自動補值的演算法跑出特徵重要性,並考慮領域知識。有些特徵可能含有 NA 但是對預測很有用;有些特徵可能對於領域知識來說非常重要,但是 NA 比例很高,我會將這些都考量進來,最後才決定要刪掉哪些特徵。
2. 平均值、中位數、眾數補值
- 單變數補值:數值型特徵可以用本身的中位數、平均值補值,類別型則可以用眾數補值。例如以收入的平均當作補值,地區則可以用數量最多的地區進行補值。
- 多變數補值:使用別的欄位當作基準進行補值。例如,考慮到不同地區可能有收入高低差異,可以先算出各地區的收入平均,再針對不同地區的 NA 進行補值。
缺點是無論是單變數或是多變數,皆會導致資料分布失真。若建模前有做 EDA 的話要注意。
3. 模型預測
把含有 NA 的特徵當作預測目標,剩餘特徵用來建立模型,將模型的預測當作補值,常見的有 regression、KNN。以 KNN 來說,優點是考慮到樣本的相似度,相較簡單的平均值補值來說更加精準。不過缺點也很明顯,耗費時間較長,只要新資料裡有一個特徵 NA 就要預測一次,N 個特徵有 NA 就要建 N 個模型,而且對於模型表現還不保證能提升,個人認為以實用度來說並不是很高
4. 創造新數字或類別
有些特徵單純以統計量進行補值,可能會扭曲原本的意義,而讓特徵失去作用。例如消費者回購模型中的 Recency(上次購買距離今日的天數) 是一個很好的例子。如果 Recency 為 NA,表示該會員是沒有購買紀錄的。這時如果用平均值(假設為100)對 Recency 進行補值的話,那就會讓原本沒有購買過的會員變成 100 天前購買了,對於 Recency 這種數字越小可能影響越大的特徵,補平均值是不太恰當的。這時我的處理方法是將 NA 補為 10000,通常 recency 的最大值不超過 2000,因此 10000 這個數字,某種程度上即為把很久很久沒購買視為沒買過。
我自己最常用的方法是刪除含遺失值的特徵。由於我處理過的專案中,大部分都不會對準度有很高的要求,而是先求能應用為主,所以在這樣的情境中,我認為刪除是最有效率的方法。再來是以平均數補值、創造新數字或類別,最後才是模型。
實際上要套用哪些方法,並沒有絕對的答案,要怎麼運用則和問題的情境有關。由於本篇的重點在於分享建模需要注意的細節,所以針對 NA 的應對方法就不介紹太多,上面已經為大家整理出常見的方法,如果有興趣的可以再深入研究。
Duplicate Records
接下來要講的 Duplicate Rows ,其實嚴格上來說不算在 Machine Learning 內,跟建模沒有直接關係,比較算在資料預處理的範疇內,甚至這個名詞也是我自己定義的。但如果忽略它,它可能會讓我們在做探索性分析(EDA)或特徵工程時得到錯誤的結果。一起來看看吧。
甚麼是 Duplicate Records
Duplicate Records 定義很簡單,就是在 merge/join 兩張資料表之後,產生了重複的列。
我們來看以下例子。
假設我們今天想要計算「會員的總花費」,那麼一個可行的做法是將 A left join B 之後,再來 group by 會員ID計算總花費。
重點來了,當我們執行 A left join B,由於在B表內的344號訂單包含兩個產品,導致AB表合併後,原本在A表內只有一列的344號訂單變成了兩列。這樣就是產生了 Duplicate Records。
為什麼這很重要
注意C表中總金額這個欄位,因為 Duplicated Records 的關係,這個欄位也被重複了。這時如果我們想要用C表來計算每個會員的總花費的話,5號會員的總金額就會從原本的4128加倍成8256了,而這很明顯是錯誤的,不管做EDA還是做特徵都會被影響。
如何避免
Duplicate Records 本身不是問題,因為它導致計算發生錯誤才是問題,而這完全得根據當下處理的資料與欄位本身的意義。我自己的作法是只要有 merge/join 的動作,合併後的那張表一定要多加檢查。我的方法是將根據合併後的表,直接去對沒有經過任何動作、最原始的那幾張表,如果有問題的話,通常選幾個 row 就能觀察到了。
有時候,其他資料科學家同事總會戲稱自己為「資料整併師」,因為我們真的很大一部分時間都在做資料處理,其中絕對是會需要 merge 不同資料表,此時就要特別注意 Duplicate Records 的發生,才能確保我們算出的數字是正確的。
Data Leakage
接下來要談的 Data Leakage 就跟模型本身很有關係了,同時也是本篇文章中屬於影響程度較大的。Data Leakage 不像前面介紹的兩項有明確的定義,比較像是一種現象,因此它稍微比較抽象一點。
Data Leakage 的定義是「倒果為因」,是指訓練集裡包含了預測目標的資訊。以白話文來說,就是模型透過某些欄位看到答案了,而使得準確率變得非常高、或者 MSE 極低。
甚麼意思呢?我們來看看以下例子:
什麼是 Data Leakage
案例一:因果顛倒
舉個最近疫情的例子,假設我們要預測某個人是否確診 COVID-19,而有一個特徵是「PCR檢測是否為陽性」,那麼很明顯這個模型會發生 Data Leakage。因為如果有確診的話,那麼 PCR 檢測就一定會是陽性。在這個例子中, PCR檢測為陽性並不是確診的原因,而是確診之後做 PCR 檢測才會是陽性。也就是說,模型只需要根據「PCR檢測是否陽性」,基本上就可以獲得近100%的準確率。
這是典型的因果顛倒。
正確的做法應該是把 PCR 檢測是否為陽性這個欄位拿掉,使用其他像是是否咳嗽、是否有下呼吸道症狀等等作為特徵,因為咳嗽、下呼吸道症狀不一定是只有 COVID-19 才會出現的症狀,有可能也來自於其他疾病。但是 PCR 檢測陽性卻是只有 COVID-19 才會有的結果。
註:PCR 檢測其實可以用於其他病毒,不過這邊我們假設 PCR 檢測只用在 COVID-19。
案例二:預知未來
以天氣為例,假設我們想要用過去三天的氣溫預測今天的天氣,如果我們的訓練集使用了包含今天的氣溫,那麼我們肯定會獲得100%的準確率,因為有一個特徵完全和答案相同,根本不需要訓練。這已經不屬於 overfitting,而是作弊了。
這是一個比較極端的例子,你看到這裡可能會覺得很廢話,當然不可能直接把當天的答案當成特徵啊!但實際上,我們在利用過去的資料來建立訓練集時,其實很容易發生這種情況。
我在建構會員回購模型時,利用 1/1~6/31 的資料來建立特徵,並將會員是否於 6/1~6/31 購買作為目標欄位進行建模,得到的模型成效準確度達99%。
根據上面的情況,看出問題了嗎?
.
相信有前面天氣的例子應該很容易看得出來:用來建立特徵的資料區間,與目標欄位的資料區間重疊了。
正確的做法是不能重疊。建立特徵的正確資料區間應為 1/1 ~ 5/31。也就是說,當我們要建立的模型跟時間相關的時候,如未來的股價、天氣、購買機率等,建立特徵的資料區間不能與目標欄位的資料區間重疊。
實際上,在真正有新資料要預測時,我們是不可能取得未來的資料的,例如我們不可能在今天就有明天的實際氣溫吧?同理,當我們用過去資料建立訓練集,也就是用昨天來預測今天時,也要記住這一點:對於昨天來說,無法知道今天的氣溫。對於今天來說,無法知道明天的氣溫。
在做特徵工程時,這是一個很容易犯的錯誤。
為什麼這很重要
看到這裡我相信你應該有點感覺了,一個看到答案而且準確率過高的模型,很明顯有問題。但到底實際上會有什麼影響呢?我們不是都會有測試集來確保模型不會overfitting嗎?雖然訓練集準確率高達99%感覺很可疑,但測試集的表現也很高的話,這樣還會有什麼問題?
Data Leakage 最主要的影響就是,實際上線的模型表現會大幅降低。
為什麼呢?因為如果有發生 Data Leakage 的話,不管訓練集還是測試集,通常兩者都會有非常好的表現,所以光是用測試集是沒辦法檢測出 Data Leakage 的。只有到了預測新資料的場景時,也就是實際上線的時候,才會發現出了問題。
我們再回想一次天氣的例子。
假設目前模型已經有預知未來的 Data Leakage 發生,表示模型是根據今天的氣溫來預測今天的氣溫,所以準確率是100%。結果到了要預測明天的氣溫時,這時問題就發生了:由於今天根本不會知道明天的氣溫,所以模型完全無法猜測,導致失去原有的準度。
回到實際的工作場景。
當模型有 Data Leakage 發生,但沒有檢測出來的話,則必須等到上線測試的結果出來,才能知道模型出了問題。但不同於我們用測試集來測試,上線測試是有時間與金錢成本的,無論是你是在客戶端或是廠商端。
簡單的說,如果用有 Data Leakage 的模型做上線測試,可以說是有高機率會讓客戶白花錢,而這是我們最不樂見的情況。
如何避免 Data Leakage?
那到底該如何避免 Data Leakage 發生呢?有三個方法可以幫助我們檢測:模型學習速度、特徵重要性、釐清資料定義。
模型學習速度
- 如果使用的是 XGBoost 或 Neural Network 這種需要迭代的演算法,可以透過學習的速度來判斷。學習速度指的是 logloss、accuracy 或者是 MSE、MAE 等指標的變化速度,過快的話表示很有可能發生 Data Leakage。以 XGBoost 為例,嚴重的話可能不到三步以內就會看到準確率幾乎達到99%。
- 不過通常這個方法主要是判斷因果顛倒的 Data Leakage,預知未來類型則比較難檢測出來,這時就可以利用下一個方法:特徵重要性。
特徵重要性
- 這是最簡單也最常用的方法。若有 Data Leakage 發生,通常會有 1~2 個特別突出、重要性特別高的特徵,而其他的特徵相對來說就會變得非常小或甚至趨近於零。在特徵重要性圖表上可以一目了然,如下圖。
- 由於 Data Leakage 有分嚴重程度,並不是能簡單用二分法來定義的。因此當資料有 Data Leakage ,但是看到答案的特徵又不那麼強力的時候,會遇到比較模稜兩可的狀況,例如下圖。雖然第一個特徵確實非常突出,但其他的特徵也並非完全接近零,導致難以直接判斷究竟是否為 Data Leakage。這時候我們就要用最後一個方法:釐清資料定義。
釐清資料定義
- 當我們從特徵重要性圖表上發現了幾個特別強力的特徵,但又無法立即判斷是否有 Data Leakage 時,我們就必須從資料本身下手。回想一下,前面提到 Data Leakage 有哪兩種情況,還記得嗎?
- 通常來說,我會先檢查自己的特徵工程是否有犯預知未來的錯誤,這是最常見的情況。再來,我會檢查欄位是否有因果顛倒的狀況。要檢查是否有因果顛倒,我們就得從特徵與預測目標的關係下手,去釐清這些特徵是否有可能對預測目標有重大影響,而這關乎資料收集的邏輯與領域知識。這兩者都是資料科學家比較難取得的資訊,若是在廠商端的話更是如此。此時,我們就得仰賴客戶或資料庫人員的協助,他們才是知道資料收集邏輯與領域知識的人。
這邊舉一個我曾分析過的生產線數據為例,雖然無法提供建模結果,不過很適合用來解釋甚麼叫釐清資料定義。當時我要透過生產線上感測器的即時數據,嘗試分析感測器數據與機台故障的關聯性。透過視覺化,我發現一個洞察:故障前三分鐘,A感測器的數據會明顯下降。也就是說,A感測器的數據一旦下降很劇烈,就表示機台有高機率即將故障了。
然而,當我們團隊跟客戶分享之後,客戶的反應是:「由於故障發生的當下,與人員去紀錄故障之間,有一小段時間差。所以A感測器的數據下降,很可能是機台已經故障了所以才下降,而不是數據下降之後才發生故障。」
- 也就是說,我們以為A感測器數據下降,是故障的**「前兆」;但依據客戶的說法,實際情況很可能是故障先發生了,才造成A感測器數據下降,所以下降是「結果」**。這就是我遇過領域知識造成資訊不對稱的例子。如果我們自行將「A感測器數據下降」當成一個特徵,並將「是否故障」作為預測目標的話,便會發生 Data Leakage 。
要避免 Data Leakage,可以按照順序應用上述的方法:首先,如果使用的是樹模型或 Neural Network,可以先觀察模型學習速度;再來,透過特徵重要性,可以很快速的判斷哪些是強力的特徵,這些強力特徵與其他特徵的相對關係如何;最後,前兩個方法都難以判斷的話,我們就需要回到原點,從資料本身下手,去理解這些資料如何被收集,經過甚麼樣的轉換,最後才變成眼前的 raw data。
總結
以上就是我認為在建模過程中最容易犯的三個錯誤,以及在錯誤中學到的經驗。如果要從中選一個我認為影響最大的,我一定會選 Data Leakage,但是我在學習理論的過程中完全沒有接觸過相關的資料,直到我實際工作了才發現,讓模型看到答案這件事實在很容易發生,所以本篇也花了比較多的篇幅在 Data Leakage 的部分上。希望透過這三點分享,能作為各位的墊腳石,一起建立品質更好、更 robust 的模型。