# 特徵工程 ## 數值型資料 數值型資料的第一種檢查 : - 大小是否重要? - 是否只需要知道他是正的還是負的? - 或許只需要知道粗略的大小? 接著,考慮特徵的尺度 : - 最大值和最小值是多少? ## 處理計數型資料 - 二元化 : 大於某一個數值定為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,可以使模型表現變好