---
# System prepended metadata

title: ML-Report
tags: [homework]

---

###### tags: `homework`
# ML-Report

[toc]

## Data Survey

### Overview

* 總共有 5634 筆 training records，其中有 1408筆 Churn Category 是 NA
* training set 和 testing set 每種 feature 的 NA % 都介於 23% ~ 26% 之間 (1200 ~ 1300 個)

### Training Target

* Churn Category 是極端 imbalance
    * No Churn 2374
    * Attitude 164
    * Competitor 381
    * Dissatisfaction 134
    * Other 87
    * Price 87

### Categorical Features

* Country / State / Quarter: 只有兩種可能(XX 和 NA)
* 多數 feature imbalanced，但是在可接受範圍內
* 以 chi2 計算 categorical features 和 Churn Category 之間的 correlation，由高分至低分:
    * 'Zip Code', 'City', 'Contract', 'Offer', 'Dependents', 'Internet Service', 'Unlimited Data','Paperless Billing', 'Referred a Friend', 'Married', 'Online Security', 'Under 30', 'Premium Tech Support','Streaming TV', 'Payment Method', 'Online Backup', 'Streaming Music', 'State', 'Streaming Movies', 'MultipleLines', 'Senior Citizen', 'Quarter', 'Internet Type', 'Device Protection Plan', 'Phone Service', 'Country', 'Gender'

### Numerical Features

* 以 ANOVA 計算 categorical features 和 Churn Category 之間的 correlation，由高分至低分
* 'Satisfaction Score', 'Tenure in Months', 'Number of Referrals', 'Total Revenue', 'Total Long Distance Charges', 'Number of Dependents', 'Total Charges', 'Monthly Charge', 'Age', 'Latitude', 'Avg Monthly GB Download', 'Avg Monthly Long Distance Charges', 'Longitude', 'Population', 'Total Refunds', 'Total Extra Data Charges'
* 經過 normalize 後，numerical features 的 KDE plot
![](https://i.imgur.com/bIWadhj.png)


## Pre-proccessing

### Data Augmentation

我們嘗試使用兩種 augmentation 方法

* k-Means smote
* SVM smote

    SMOTE執行三個步驟來生成合成樣本。首先，它選擇一個隨機的少數觀測值a。在其k個最近的少數類鄰居中，選擇實例b。最後，通過對兩個樣本進行隨機插值來創建一個新的樣本。然而，smote 有重大缺陷: 可能會進一步放大數據中的 noise。當線性插值一個有噪聲的少數樣本時，可能會發生該樣本位於多數類及其最近的少數鄰居之間。
    K-means SMOTE 則嘗試改善上述缺點。由三個步驟組成:clustering / filtering / over sampling。在 clustering 中，使用K-means將輸入空間聚類成k個組。filtering步驟選擇用於過採樣的聚類，保留少數類樣本比例高的聚類。然後，它分配要生成的合成樣本的數量，將更多的樣本分配給少數樣本稀疏分佈的集群。最後，在over sampling時，在每個選定的聚類中應用SMOTE，以實現少數和多數實例的目標比率。
    SVM smote 則是使用一個SVM分類器尋找support vector，然後在 support vector 的基礎上合成新的樣本。SVM smote 會根據 KNN 的屬性決定樣本的類型（safe、danger、noice），然後使用danger的樣本訓練SVM。


Train_ID裡面有的，在其他.csv裡面不一定有

Training dataset中沒有status的部分，在訓練時drop掉。

### Missing Value

#### 1. Mean/Median 插補
計算每列資料中非缺失值的平均數或中位數，然後用平均數或中位數補齊每列中的缺失值。這種方法只適用於數值型資料。
pros:容易實現
cons：在encoded categorical variable上效果很差。沒有考慮到特徵間的相關性。沒有考慮到插補值的不確定性。
#### 2.眾數插補
使用眾數補齊每個feature中的缺失值。
pros：適用於分類變數。
cons：沒有考慮到特徵間的相關性。
#### 3.KNN插補
基於特徵相似性來預測新資料點的值，這就意味著新資料點是基於和其他點的相似程度來被賦值。這對於缺失值的預測非常有用：找到距離缺失值距離最近的K個數據點，然後基於這些點的值來插補缺失值。
pros:比較精準
cons：計算量大。KNN對outliers非常敏感。
#### 4.深度學習插補
pros：相對其他方法準確。可以處理categorical variable。
cons：必須指定包含目標列資訊的所有列。
#### 5.新增類
missing value當作新的類NA。
#### 6.根據已知資訊插補
以“demographics.csv”中的“Age”為例：
將Age以每十歲為一個類別分類，如（19-30[1],30-40[2]...)
根據under 30和Senior citizen的資訊推導age的可能範圍。
關係如下：

| under 30 | Senior citizen | Result |
| -------- | -------------- |:------:|
| yes      |   no/x             | 19-29  |
|   no/x       | yes            |  65up  |
| no       | x              |  30up    |
| x        | no             |  19-65      |
| no         |  no              |  30-65    |
| x       | x             | Na  |

在上表得出的範圍內取平均數作為missing value的值

再比如在“services.csv”中可以由‘Referred a Friend’=‘No’推出‘Number of Referrals’=0

在‘location.csv’中，‘Lat Long’資料與‘Latitude’、‘Longitude’相互對應，可相互補齊。

### Categorical Features Encoding

#### 1.Ordinal Encoding
把Categorical Feature隨機編碼成某個數值。
#### 2.Frequency Encoding
把Categorical Feature裡面每個類別出現的數量，當成這個類別的數值。
#### 3.Target Encoding
將同樣類別的data對應的Target值的平均值作為這個類別的數值。
#### 4.Leave-One-Out Encoding
與Target Encoding類似，但是在對每一筆Data的feature算Target的平均值時，會去除掉這筆Data的Target。這樣做可以使得某一個feature的每一類encoding的結果有一定的變異性。

### Feature Selection

#### 1.Filtering Methods
先算出每個feature的某種數值（通常是某種分數），然後基於這個數值去選出較好的feature。最有名的例子可能是先算每個feature跟label的f-regression score，再依照score篩選TopK features。

#### 2.Wrapper Methods
一般而言，Wrapper Methods的步驟都是以下4步
1. 製造出多種可能的feature set
2. 基於每個feature set都train出一個我們的model
3. 比較每個model的performance，把performance最高的model對應使用的feature set選出來，當成目前最好的feature set
4. 看目前feature set大小（或是model performance）有沒有達標，如果沒有就回到第一步再loop一遍。

#### 3.SequentialFeatureSelector
分為Forward Selection和Backward Selection。這種方法每次只加/減一個feature，依序處理多次直到達到標準。Forward Selection的做法是舉出所有可能的feature set（每個feature set裡feature的數量從一個開始遞增），每個feature set都用來train一個model，每次將validation score最高的feature set保留。Backward Selection則是將validation score最低的feature set去掉，feature set中每次遞減一個feature


## Methods & Experiments

* 我們嘗試使用以下幾種模型:
    * DNN
    * lightgbm
    * XGBoost
    * svm
    * Adaboost

* 使用 5-fold cross validation，來保證實驗的穩定度
* 所有實驗節果皆透過 Grid Search 尋找最佳化參數
* 每個實驗中設定固定數值作為 random seed

### 5-Fold CV with Data Augmemtation

*  資料切為五份，每份輪流作為test set，其餘做 training set，迭代以下:
    * 對於grid search 每組參數:
        1. (optional)資料做 augmentation
        2. train model & validation
* refit 全部 data

### DNN

* Model 架構
![](https://i.imgur.com/ddGx0Sa.png)

* 使用 weighted cross entropy loss
    * SVM smote 或 K-means smote 若將資料完全補至同樣數量，效果會比不使用還差，推測是因為noise data過多
    * 因此我們選擇只將1-4類資料補到500筆左右，並使用weighted cross entropy loss 來處理 imbalance 問題

* 由grid search 找到的 Parameters:
    * learning rate: 0.001, hidden size: 200, batch_size 128
    * class_weight: 1 - 此類別樣本數 / 總樣本數

#### 結果

|                    | f1-macro CV | Public Score | Prvate Score | training time (final paramters, sec) |
| ------------------ | ----------- | ------------ | ------------ | ------------------------------------ |
| DNN                | 0.292       | 0.30069      | 0.28805      | 57.22                                |
| DNN +  kmean smote | 0.284       | 0.28352      | 0.28486      | 56.54                                |
| DNN +  SVM smote   | 0.286       | 0.29653      | 0.29857      | 56.47                                |

* 不使用 augmentation 的訓練時間反而比使用 smote 時間更長，可能是因為訓練DNN時，GPU同時跑其他任務。

### LightGBM

* 相較於 XG Boost，LightGBM做出了一些改善
    * historgram-based decision tree: 降低記憶體使用
    *  Gradient-based One-Side Sampling: 減少大量只具有小梯度的數據實例
    *  Exclusive Feature Bundling: 將許多exclusive features綁定為一個特徵，達到降維的目的。
    *  支援 Categorical Features
*  由於支援 Categorical Features，所以使用 Label Encoding
* 由grid search 找到的 Parameters:
    *  random_state=1003, class_weight=class_weight, learning_rate=0.2, max_depth=-1, n_estimators=150
        , reg_alpha=0.01, reg_lambda=0.01, subsample=0.8
    * class_weight: 1 - 此類別樣本數 / 總樣本數
    * 使用同組 parameters

#### 結果

|                    | f1-macro CV | Public Score | Private Score | training time (final paramters, sec) |
| ------------------ | ----------- | ------------ | ------------ | ------------------------------------ |
| LGBM               | 0.336       | 0.30993      | 0.28741      | 0.533                                |
| LGBM + kmeans smote | 0.336       | 0.32753      | 0.33030      | 0.376                                |
| LGBM + SVM smote   | 0.347       | 0.38517      | 0.33611      | 0.823                                |

### XGBoost
|                       | f1-macro CV | Public Score | Private Score |
| --------------------- | ----------- | ------------ | ------------- |
| XGBoost              |   0.2912          |          0.2692  |      0.3267        |
| XGBoost+kmean smote |    0.2943         |         0.3147     |    0.3239      |
### Adaboost

* AdaBoost是一種把多個不同的決策樹用一種非隨機的方式組合起來的算法。這樣的方法把多個弱分類器組合成一個強分類器，達到不錯的分類效果。並且由於其參數不多，所以易於調整參數。
* Parameters：
    * 通過grid search我找到的最佳參數：'learning_rate': 0.4, 'n_estimators': 80。其中grid search的space是：'learning_rate': [0.4,0.6,0.8,1,1.2],
        'n_estimators': range(30,150,5)。設置這樣的space的原因是，我發現n_estimators較小時效果並不是很好，直觀上說越多弱分類器組成的強分類器效果越好，但過多又會造成overfitting。
    * 同時嘗試加入兩組kmean smote和SVM smote做data augmentation。第一組的參數為{1: 600, 2: 900, 3: 900, 4: 1000, 5: 1000},第二組的參數為{1: 1000, 2: 500, 3: 500, 4: 300, 5: 300}.
#### 結果


|                       | f1-macro CV | Public Score | Private Score |
| --------------------- | ----------- | ------------ | ------------- |
| Adaboost              |   0.2812          |          0.2667  |      0.3144         |
| Adaboost+kmean smote1 |    0.2779         |         0.2798     |    0.2965      |
| Adaboost+SVM smote1   |   0.2718          |        0.2634      |        0.2701       |
| Adaboost+kmean smote2   |  0.2872           |     0.2595         |       0.3104        |
| Adaboost+SVM smote2   |   0.2797          |         0.2581     |    0.2888           |

### SVM
* SVM可以在hyperplane上可以使得邊界距離最近的訓練資料點越遠越好，這樣可以減少分類器的泛化誤差。在我的理解中，這次kaggle competition中的data，missing value很多，即使使用相對合理的方式補值但仍會造成很大的誤差。換言之，在這樣的dataset中noise較多，所以我認為SVM會是相對適合的，就結果來看確實比Adaboost好一些。
* Parameters:
    * 通過grid search我找到的最佳參數：
{'C': 1000, 'class_weight': None, 'gamma': 'auto', 'kernel': 'rbf'}。我嘗試了三種kernel：poly，sigmoid，rbf
    * class_weight: 1 - 此類別樣本數 / 總樣本數


|                  | f1-macro CV | Public Score | Private Score |
| ---------------- | ----------- | ------------ | ------------- |
| SVM              |   0.2923          |           0.2694   |             0.2762  |
| SVM+kmean smote1 |      0.3150       |       0.2803       |      0.3479         | 
| SVM+SVM smote1   |    0.3032         |      0.2758        |      0.3225         |
| SVM+kmean smote2 |   0.2942          |       0.3359       |      0.2901       |
| SVM+SVM smote2   | 0.3043        |          0.2581    |     0.2888          |



## 總結

* 可以發現，雖然public score 和 private score 的差異很大，但是若將其平均，是跟 CV score 差不多的，因此，選擇最終紀錄時，應要考慮到 CV score，而不是單單 public score。
* data augmentation 時，SVM smote 的效果較佳: 這可能是因為SVM找到的support vector，比k-means 更有效的切割樣本空間
* 由於data中的missing value很多，所以無論是使用KNN還是取平均值插補的方法仍會造成很多noise，這使得我們訓練的model不夠robust。我們認為這可能是造成預測結果在Public Score和Private Score上不穩定的重要原因之一。
## 分工


## Reference

* [imblearn SVMSMOTE](https://imbalanced-learn.org/stable/references/generated/imblearn.over_sampling.SVMSMOTE.html)
* [imblearn KMeans SMOTE](https://imbalanced-learn.org/stable/references/generated/imblearn.over_sampling.SVMSMOTE.html)
* [Light GBM](https://lightgbm.readthedocs.io/en/latest/)
* [Pytorch](https://pytorch.org/)