# 特徵工程
## 數值型資料
數值型資料的第一種檢查 :
- 大小是否重要?
- 是否只需要知道他是正的還是負的?
- 或許只需要知道粗略的大小?
接著,考慮特徵的尺度 :
- 最大值和最小值是多少?
## 處理計數型資料
- 二元化 : 大於某一個數值定為1,小於某一個數值定為0
- 分箱 : 例如,利用年齡層來分組,
- 0-9歲分到第一組,10-19歲分到第二組,以此類推
- 另外也可以客製化年齡範圍,0-12歲、12-18歲、18-22歲等等
```
import numpy as np
np.floor_divide(你的list,10) # 取list裡面每個數字除以10過後的整數部分
```
- 數字跨越好幾個數量級,適合用10的次方進行分組,0-9、10-99、100-999、...
```
import numpy as np
# np.floor : 高斯符號[],無條件捨去小數部分
# np.log10(),np.log(),np.log2 : 以10、e、2為底
np.floor(np.log10(你的list))
```
- 如果計數存在很大差距,導致許多箱子裡面沒有資料,則可以用"分位數分箱",將資料分成 0.25 0.5 0.75 四等分。
```
import pandas as pd
pd.qcut(你的list,4,labels=False)
```
- Box-Cox 轉換
```
from scipy import stats
rc_bc,bc_params = stats.boxcox(你的list)
bc_params
```
## 特徵縮放
``` import sklearn.preprocseeing as preproc```
1. 最大最小縮放 ```preproc.minmax_scale(list)```
2. 標準化 ``` preproc.StandardScaler().fit_transform(list)```
3. 長度正規化 ```np.linalg.norm(list)```、```preproc.normalize(list,axis=0)```
## 交互作用(interaction term)
```
from sklearn.preprocessing import PolynomialFeatures
interaction = PolynomialFeatures(degree=2, interaction_only=False, include_bias=False)
X_inter=pd.DataFrame(interaction.fit_transform(X_train),columns=interaction.get_feature_names(input_features=X_train.columns))
```
## 類別變數編碼
- 一位有效編碼(one-hot encoding) : K種類別,K個變數,每個變數設為1,其他為0。
| One-hot encoding | e1 | e2 | e3 |
| ------- | -- | -- | -- |
| Label 1 | 1 | 0 | 0 |
| Label 2 | 0 | 1 | 0 |
| Label 3 | 0 | 0 | 1 |
- 啞變數(dummy variables) : K種類別,K-1個變數設為1,剩餘1個變數做為參考變數全為0。
| Dummy variables | e1 | e2 |
| ------- | -- | -- |
| Label 1 | 1 | 0 |
| Label 2 | 0 | 1 |
| Label 3 | 0 | 0 |
- 效果編碼(effect encoding) : 其中一種類別全部是 -1,其他都是設為1。
| Dummy variables | e1 | e2 |
| ------- | -- | -- |
| Label 1 | 1 | 0 |
| Label 2 | 0 | 1 |
| Label 3 | -1 | -1 |
## 巨大類別變數
解決方法 :
1. 使用簡單模型(Logistic、SVM),搭配one-hot encoding.
2. 壓縮特徵
(a). 特徵雜湊
a. 優點 : 計算上節省記憶體空間
b. 缺點 : 雜湊後的特徵不可解讀
(b). 分箱計數 : 使用條件機率(https://medium.com/@aks.chikara/machine-learning-handle-large-categorical-column-bin-counting-approach-cb9fadaf4e96)
1. 計算 odds ratio
2. 計算 log odds ratio
3. 遇到罕見類別,使用**退縮法back-off**,將罕見類別的計數集中在一個特殊箱子,如果計數大於一個門檻值,那個類別才能獲得屬於他自己的計數統計,否則就使用來自退縮箱的統計資訊。
3. 防範資料洩漏
實務上,加上一個Laplace(0,1)的小隨機雜訊,就可以掩蓋任何單一資料點引起的潛在洩漏。
4. 無範圍計數
分箱計數無法處理線上學習,one-hot encoding 和 特徵雜湊可以處理線上學習。
## PCA
```
from sklearn.decomposition import PCA
pca_transformer = PCA(n_components=0.8) # 涵蓋80%總變異數
pca_X_train = pca_transformer.fit_transform(data)
pca_transformer.explained_variance_ratio_
```
PCA捨棄資訊,因此降維後的模型訓練較省時,但比較不準確。
PCA常用在time series的異常偵測,建立財務模型(Factor Analysis)
## ZCA
PCA的進一步白化,但ZCA沒有縮減維度。
ZCA常用於影像學習,相鄰的像素常常有相似的顏色,ZCA白化可以移除這種相關。
## 透過 K-means 進行非線性特徵化
(https://github.com/alicezheng/feature-engineering-book/blob/master/07.03-05_K-means_featurization.ipynb)
```
from sklearn.cluster import KMeans
class KMeansFeaturizer:
``` 將每一個資料點轉換成最靠近的群集的ID```
def __init__(self, k=100, target_scale=5.0, random_state=None):
self.k = k
self.target_scale = target_scale
self.random_state = random_state
self.cluster_encoder = OneHotEncoder().fit(np.array(range(k)).reshape(-1,1))
def fit(self, X, y=None):
if y is None:
# No target variable, just do plain k-means
km_model = KMeans(n_clusters=self.k,
n_init=20,
random_state=self.random_state)
km_model.fit(X)
self.km_model_ = km_model
self.cluster_centers_ = km_model.cluster_centers_
return self
# There is target information. Apply appropriate scaling and include
# into input data to k-means
data_with_target = np.hstack((X, y[:,np.newaxis]*self.target_scale))
# Build a pre-training k-means model on data and target
km_model_pretrain = KMeans(n_clusters=self.k,
n_init=20,
random_state=self.random_state)
km_model_pretrain.fit(data_with_target)
# Run k-means a second time to get the clusters in the original space
# without target info. Initialize using centroids found in pre-training.
# Go through a single iteration of cluster assignment and centroid
# recomputation.
km_model = KMeans(n_clusters=self.k,
init=km_model_pretrain.cluster_centers_[:,:2],
n_init=1,
max_iter=1)
km_model.fit(X)
self.km_model = km_model
self.cluster_centers_ = km_model.cluster_centers_
return self
def transform(self, X, y=None):
clusters = self.km_model.predict(X)
return self.cluster_encoder.transform(clusters.reshape(-1,1))
def fit_transform(self, X, y=None):
"""Runs fit followed by transform.
"""
self.fit(X, y)
return self.transform(X, y)
```
```
# k: integer, optional, default 100, the number of clusters to group data into.
kmf_hint = KMeansFeaturizer(k=optional,target_scale=10)
```
透過K-means得到的分類結果,得到群集特徵後,放入LR,可以使模型表現變好