数据挖掘实战(三):特征工程-二手车交易价格预测
基本介紹
調參效果有限,特征工程的好壞決定最終的排名和成績
將數據轉換為能更好地表示潛在問題的特征
內容介紹(精華)
說明:以下內容中,加粗的部分為實戰中使用到的方法,有具體的實現代碼,剩余的相關處理技術后續再補充上。
常見的特征工程包括:
- 通過箱線圖(或3-Sigma)分析刪除異常值
- BOX-COX轉換(處理有偏分布)
- 長尾截斷
- 標準化(轉換為標準正態分布)
- 歸一化(轉換到[0, 1]區間)
- 針對冪律分布,可以采用公式:log?(1+x1+median?)\log \left(\frac{1+x}{1+m e \operatorname{dian}}\right)log(1+median1+x?)
- 等頻分桶
- 等距分桶
- Best-KS分桶(類似利用基尼指數進行二分類)
- 卡方分桶
- 不處理(針對類似XGBoost等樹模型)
- 刪除(特征缺失的數據太多,可以考慮刪除)
- 插值補全,包括均值/中位數/眾數/建模預測/多重插補/壓縮感知補全/矩陣補全等
- 分箱,缺失值一個箱
- 構造統計量特征,報告計數,求和,比例,標準差等
- 時間特征,包括相對時間和絕對時間,節假日,雙休日等
- 地理信息,包括分箱,分布編碼等方法
- 非線性變換,包括log/平方/根號等
- 特征組合,特征交叉
- 仁者見仁,智者見智
- 過濾式(filter):先對數據進行特征選擇,然后再訓練學習器,常見的方法有Relief/方差選擇法/相關系數法/卡方檢驗法/互信息法
- 包裹式(wrapper):直接把最終將要使用的學習器的性能作為特征子集的評價準則,常見方法有LVM(Las Vegas Wrapper)
- 嵌入式(embedding):結果過濾式和包裹式,學習器訓練過程中自動進行了特征選擇,常見的有lasso回歸
- PCA/LDA/ICA
代碼示例
導入數據
import pandas as pd import numpy as np import matplotlib import matplotlib.pyplot as plt import seaborn as snsTrain_data = pd.read_csv('used_car_train_20200313.csv', sep=' ') Test_data = pd.read_csv('used_car_testA_20200313.csv', sep=' ') print(Train_data.shape) print(Test_data.shape)刪除異常值
下面為利用箱線圖剔除異常值的函數
def outliers_proc(data, col_name, scale=3):"""用于清洗異常值,默認用 box_plot(scale=3)進行清洗:param data: 接收 pandas 數據格式:param col_name: pandas 列名:param scale: 尺度:return:"""def box_plot_outliers(data_ser, box_scale):"""利用箱線圖去除異常值:param data_ser: 接收 pandas.Series 數據格式:param box_scale: 箱線圖尺度,:return:"""iqr = box_scale * (data_ser.quantile(0.75) - data_ser.quantile(0.25))val_low = data_ser.quantile(0.25) - iqrval_up = data_ser.quantile(0.75) + iqrrule_low = (data_ser < val_low)rule_up = (data_ser > val_up)return (rule_low, rule_up), (val_low, val_up)data_n = data.copy()data_series = data_n[col_name]rule, value = box_plot_outliers(data_series, box_scale=scale)index = np.arange(data_series.shape[0])[rule[0] | rule[1]]print("Delete number is: {}".format(len(index)))data_n = data_n.drop(index)data_n.reset_index(drop=True, inplace=True)print("Now column number is: {}".format(data_n.shape[0]))index_low = np.arange(data_series.shape[0])[rule[0]]outliers = data_series.iloc[index_low]print("Description of data less than the lower bound is:")print(pd.Series(outliers).describe())index_up = np.arange(data_series.shape[0])[rule[1]]outliers = data_series.iloc[index_up]print("Description of data larger than the upper bound is:")print(pd.Series(outliers).describe())fig, ax = plt.subplots(1, 2, figsize=(10, 7))sns.boxplot(y=data[col_name], data=data, palette="Set1", ax=ax[0])sns.boxplot(y=data_n[col_name], data=data_n, palette="Set1", ax=ax[1])return data_n實戰中,刪除power特征的異常數據。
注意:測試集的數據不能刪除
運行結果:
特征構造
使用時間data['creatDate'] - data['regDate']反應汽車使用時間,一般來說價格與使用時間成反比。不過要注意,數據里有時間出錯的格式,所以我們需要使用errors='coerce'將無效值強制轉換為NaN。
從郵編中提取城市信息,相當于加入了先驗知識。提取regionCode的第一位代表不同的城市。
此處計算某品牌的銷售統計量,也可以計算其他特征的統計量,這里要用train 的數據計算統計量。
運行結果示例:
將上述分組統計的數據,合并到原來的數據集中
data = data.merge(brand_fe, how='left', on='brand') data.head()數據分桶
以 power 為例,這時候我們的缺失值也進桶了。
最后,刪除不需要的數據,axis=1表示刪除一列。
data = data.drop(['creatDate', 'regDate', 'regionCode'], axis=1) data.columns結果:
目前的數據其實已經可以給樹模型使用了,所以我們導出一下。
data.to_csv('data_for_tree.csv', index=0)特征構造(LR,NN)
不同模型對數據集的要求不同,所以分開構造
名義變量轉換成啞元變量,利用pandas實現one hot encode,可參考網址。
data = pd.get_dummies(data, columns=['model', 'brand', 'bodyType', 'fuelType', 'gearbox','notRepairedDamage', 'power_bin']) data.columns最后,存儲數據給LR用
data.to_csv('data_for_lr.csv', index=0)特征篩選
相關性分析,從相關性較大的特征之間,去除一個,可以計算出相關系數,或者看相關性矩陣圖。其中,method參數的值可以是:
- pearson:來衡量兩個數據集合是否在一條線上面,即針對線性數據的相關系數計算,針對非線性數據便會有誤差。
- kendall:用于反映分類變量相關性的指標,即針對無序序列的相關系數,非正太分布的數據
- spearman:非線性的,非正太分析的數據的相關系數
沒有詳細研究,單純記錄下,使用pip install mlxtend安裝。
from mlxtend.feature_selection import SequentialFeatureSelector as SFS from sklearn.linear_model import LinearRegression sfs = SFS(LinearRegression(),k_features=10,forward=True,floating=False,scoring = 'r2',cv = 0) x = data.drop(['price'], axis=1) x = x.fillna(0) y = data['price'] sfs.fit(x, y) sfs.k_feature_names_ # 畫出來,可以看到邊際效益 from mlxtend.plotting import plot_sequential_feature_selection as plot_sfs import matplotlib.pyplot as plt fig1 = plot_sfs(sfs.get_metric_dict(), kind='std_dev') plt.grid() plt.show()大部分情況下都是使用這種方式做特征篩選! 下一章節補上
經驗總結
(屯著……)
有些比賽的特征是匿名特征,這導致我們并不清楚特征相互直接的關聯性,這時我們就只有單純基于特征進行處理,比如裝箱,groupby,agg 等這樣一些操作進行一些特征統計,此外還可以對特征進行進一步的 log,exp 等變換,或者對多個特征進行四則運算(如上面我們算出的使用時長),多項式組合等然后進行篩選。由于特性的匿名性其實限制了很多對于特征的處理,當然有些時候用 NN 去提取一些特征也會達到意想不到的良好效果。
深入分析背后的業務邏輯或者說物理原理,從而才能更好的找到 magic。
當然特征工程其實是和模型結合在一起的,這就是為什么要為 LR NN 做分桶和特征歸一化的原因,而對于特征的處理效果和特征重要性等往往要通過模型來驗證。
機器學習基礎知識
問題記錄
Q1: 特征構造中為什么要把訓練集和測試集放在一起?
A1:放到一起處理其中的特征,比如,時間轉換,地理編碼等特征構造措施。以及后面涉及到的統計量特征。
Q2:怎么理解先驗知識?
A2:當你說:這是一幢別墅。你腦子里面是有“別墅”這個概念的,以及關于別墅的一些屬性,然后你才知道你眼前這個東西叫做“別墅”。前面的“別墅”這個概念就是你對眼前建筑的先驗知識。
Q3:地理編碼處理中,提取的部分樣本的城市代碼為空?【待處理】
A3:有的二手車的regionCode為3位數,提取出的值為空,為空的樣本也可以看作是同一個城市的,但是這里并沒有處理,當作缺失值的嗎???
Q4:構造統計量特征中,test的數據是否也需要計算統計量?(很重要)
A4:猜想:需要,訓練好模型后,test數據需要有相應的統計特征,才能進行預測。
猜想不完全對。
Q5:數據分桶的原因沒有看的太懂?
A5:
- 離散后稀疏向量內積乘法運算速度更快,計算結果也方便存儲,容易擴展
- 離散后的特征對異常值更具魯棒性,如 age>30 為 1 否則為 0,對于年齡為 200 的也不會對模型造成很大的干擾
- 特征離散后模型更穩定,如用戶年齡區間,不會因為用戶年齡長了一歲就變化
- 離散化后可以引入特征交叉,更好的引入非線性。如果年齡分了M個桶,收入分了N個桶,則可以組合出M*N個特征。
- 分桶之后相當于引入了一個分段函數,利用這個分段函數表達了一些非線性的意義。這也就是常說的離散化之后可以增加非線性的含義。
參考:連續特征離散化的意義
Q6:LR,NN,LightGBM ,XGBoost 是啥?
A6:
- LR:LinearRegression 線性回歸
- NN:近鄰 (Nearest Neighbor)
- XGBoost:一種改進后的樹模型,詳細參考網站
- LightGBM:微軟推出了一個新的boosting框架,想要挑戰xgboost的江湖地位,詳細參考網站
Q7:樹模型和LR NN對數據集的要求是什么?
A7:
Q8:km 的比較正常,應該是已經做過分桶了,怎么看出來的?
A8:橫軸為0-14的整數,應該是將汽車行駛里程數,分成了15個桶。
Q9:長尾分布【待處理】
A9:
總結
以上是生活随笔為你收集整理的数据挖掘实战(三):特征工程-二手车交易价格预测的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Task 1 天池赛 - 二手车交易价格
- 下一篇: fill数组填充