datawhale 學習筆記——建模調參入門

前言

居然又拖到了最後一天纔開始打卡,。果然 ddl 是第一生產力。

放上這次的教程鏈接:Datawhale 零基礎入門數據挖掘-Task4 建模調參

看標題就知道這次的這次的內容是建模和調參。雖然說是零基礎入門系列,但是這次的教程對真的零基礎的人來講並不是很友好,還是需要很多前置知識的。主要是機器學習模型方面的教程,教程裏給出了幾篇作者寫的文章。個人感覺需要一定門檻,如果看不懂建議參考其他的。

這次打卡還是按照教程走一遍,先梳理一下主要內容的結構。這次任務主體分爲五大部分:

  • 線性迴歸模型
  • 模型驗證
  • 嵌入式特徵選擇(上一次任務沒講的)
  • 模型對比
  • 模型調參

開始之前,先把數據準備好。

還是依舊要先讀取數據,不過這次任務的讀取數據有兩點不同:

  1. 讀取的數據是上一次任務中做特徵工程時生成的,沒有的話需要運行一下 task3 的代碼生成一下
  2. 教程中作者寫了一個 reduce_mem_usage() 函數。通過轉換數據的存儲類型來達到節約內存空間的目的。

代碼就不全粘貼了,沒什麼可說的,後面需要用到的變量是 sample_featurecontinuous_feature_names

sample_feature = reduce_mem_usage(pd.read_csv('data_for_tree.csv'))
continuous_feature_names = [x for x in sample_feature.columns if x not in ['price','brand','model','brand']]

需要根據所選特徵構造訓練集。

# 特徵處理,刪除空的數據並重置數據下標和類型
sample_feature = sample_feature.dropna().replace('-', 0).reset_index(drop=True)
sample_feature['notRepairedDamage'] = sample_feature['notRepairedDamage'].astype(np.float32)
# 構造訓練數據
train = sample_feature[continuous_feature_names + ['price']]
train_X = train[continuous_feature_names]
train_y = train['price']

線性迴歸模型

線性迴歸模型就是簡單的線性關係,類似於 a1x1+a2x2+a3x3+...+anxn+b=ya_1x_1 + a_2x_2 + a_3x_3 + ... + a_nx_n + b = y

就是說,每個自變量 xix_i 的單位變化都會導致因變量 yy 的成比例的變化(aixia_ix_i

這裏使用的是 sklearn 庫下的 LinearRegression 函數。

# 簡單的線性建模
from sklearn.linear_model import LinearRegression
model = LinearRegression(normalize=True)
model = model.fit(train_X, train_y)
print('intercept:'+ str(model.intercept_))
print(sorted(dict(zip(continuous_feature_names, model.coef_)).items(), key=lambda x:x[1], reverse=True))

運行結果:

intercept:-111820.66151155639
[(‘v_6’, 3372669.6439296836), (‘v_8’, 701432.2110340319), (‘v_9’, 169509.42711357534), (‘v_7’, 32757.63135064817), (‘v_12’, 23807.649529600818), (‘v_3’, 19739.216689565477), (‘v_11’, 13163.940983386958), (‘v_13’, 11963.46498465866), (‘v_10’, 3659.757920045777), (‘gearbox’, 878.481625388411), (‘fuelType’, 372.24870228828286), (‘bodyType’, 185.9175590029288), (‘city’, 46.98275955422143), (‘power’, 30.882991521559063), (‘brand_price_median’, 0.46125248465967494), (‘brand_amount’, 0.14337558626062372), (‘brand_price_std’, 0.13126146237474134), (‘brand_price_max’, 0.01264373865111078), (‘used_time’, 0.0006779416045904323), (‘SaleID’, 5.0161735988244534e-05), (‘train’, 3.982800990343094e-06), (‘seller’, -5.443580448627472e-06), (‘offerType’, -6.388872861862183e-06), (‘brand_price_sum’, -1.969811652902229e-05), (‘name’, -0.00024808160266330667), (‘brand_price_average’, -0.22234169615526606), (‘brand_price_min’, -1.9643720815997738),
(‘power_bin’, -56.46399500590243), (‘v_14’, -340.80766284241344), (‘kilometer’, -372.8800824482724), (‘notRepairedDamage’, -490.61611815679447), (‘v_0’, -2054.722036477167), (‘v_5’, -4343.72864602462), (‘v_4’, -15543.94705998868), (‘v_2’, -29430.03630720955), (‘v_1’, -45074.18455513423)]

這裏我得到的結果跟教程稍微不同,猜測特徵工程部分做的操作不完全一樣。

可視化可以發現,預測目標擬合得並不好。由於很多模型都假設預測目標是正態分佈的,因此後面對預測的目標 price 做了一個 log 操作。可視化後發現效果還不錯。

v_9 單一特徵進行預測,不取 log 和 取 log 的對比如下:

沒取 log 的 v_9 特徵預測圖

取 log 的 v_9 特徵預測圖

模型驗證

五折交叉驗證

對模型進行五折交叉驗證,這裏需要說明的是 cross_val_score 函數,它可以將數據分爲訓練集和測試集,並返回每次驗證時模型的得分情況。

# 交叉驗證
from sklearn.model_selection import cross_val_score
from sklearn.metrics import mean_absolute_error,  make_scorer

def log_transfer(func):
    def wrapper(y, yhat):
        result = func(np.log(y), np.nan_to_num(np.log(yhat)))
        return result
    return wrapper
# 使用線性模型對未經過 log 變換的數據進行預測
scores = cross_val_score(model, X=train_X, y=train_y_org, verbose=1, cv = 5, scoring=make_scorer(log_transfer(mean_absolute_error)))
print('AVG-org:', np.mean(scores))
# 使用線性模型對 log 變換後的數據進行預測
scores = cross_val_score(model, X=train_X, y=train_y, verbose=1, cv = 5, scoring=make_scorer(log_transfer(mean_absolute_error)))
print('AVG:', np.mean(scores))

運行結果如下:

[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 5 out of 5 | elapsed: 1.1s finished
AVG-org: 1.3684950216832068
[Parallel(n_jobs=1)]: Using backend SequentialBackend with 1 concurrent workers.
[Parallel(n_jobs=1)]: Done 5 out of 5 | elapsed: 0.7s finished
AVG: 0.02487489588467453

可以看到,做 log 處理後,模型的效果提升了兩個數量級。

模擬真實環境

需要說明的一點是,有時數據是存在時序性的,我們不能擁有上帝視角預測未來的數據。因此劃分驗證集時,需要考慮數據的時序性,模擬真實環境。即前一部分是訓練集,後一部分是驗證集,驗證集後不應再有訓練集。這是作者當時直播強調的一點,不過在這裏,並沒有什麼影響。

繪製學習率曲線

這裏利用了教程裏的 plot_learning_curve 函數來繪製,其中最主要的是調用了 learning_curve 來獲得測試和訓練時的得分。

plot_learning_curve(LinearRegression(), 'Liner_model', train_X[:1000], train_y[:1000], ylim=(0.0, 0.5), cv=5, n_jobs=1)  
plt.show()

運行結果:

學習率曲線

嵌入式特徵選擇

上一次任務中講的,特徵選擇一共有三種。前兩種是過濾式和包裹式,他們在做特徵選擇時,可以明顯的與訓練過程分離開。但嵌入式特徵選擇是邊訓練便選擇,典型的方法是L1正則化與L2正則化。(以前只知道L1、L2正則化,但並不知道這是屬於嵌入式特徵選擇,。孤陋寡聞了)

線性迴歸模型加入兩種正則化方法後,就分別變成了嶺迴歸與Lasso迴歸。

代碼粘貼一下:

from sklearn.linear_model import LinearRegression
from sklearn.linear_model import Ridge
from sklearn.linear_model import Lasso

models = [LinearRegression(),
          Ridge(),
          Lasso()]

result = dict()
for model in models:
    model_name = str(model).split('(')[0]
    scores = cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error))
    result[model_name] = scores
    print(model_name + ' is finished')

result = pd.DataFrame(result)
result.index = ['cv' + str(x) for x in range(1, 6)]
print(result)

運行結果:

		LinearRegression     Ridge     Lasso
cv1          0.190851  0.194948  0.383810
cv2          0.193835  0.197714  0.382179
cv3          0.194196  0.198252  0.383611
cv4          0.191812  0.195694  0.380331
cv5          0.195868  0.199817  0.383783

這裏簡單介紹一下 L1 和 L2 的區別,就不粘貼教程裏的可視化代碼了。

L1 的懲罰項是權值的絕對值之和,因此學到的權值參數小的會儘可能趨向於0,大的會儘可能變大,最後會得到一個稀疏矩陣,0 很多;L2 的懲罰項是權值的平方和,因此權值的絕對值會儘可能小,這樣平方求和後的值就會變小,最後得到一個所有權值都向 0 靠近的參數矩陣。

模型對比

這部分教程介紹的比較少,主要是做了一個簡單模型性能的對比,包括線性模型、決策樹模型、隨機森林、梯度提升樹、多層感知機、XGBoost 和 LGBM。

運行教程代碼的結果:

模型對比結果

可以明顯看出來,隨機森林、XGBoost 和 LGBM的效果比較好。

模型調參

主要有三種方式:貪心、網格和貝葉斯。

需要提前設定好可能的參數集合。

這部分代碼就不粘貼了,主要記錄一下我的理解。

貪心調參

主要思路是遍歷每一個參數,使用其中效果最好的參數繼續訓練模型,搜索下一個參數。

網格搜索

教程裏使用的是 sklearn.model_selection 庫裏的 GridSearchCV 函數。網格調參是一種窮舉搜索方法,遍歷所有的參數組合,選出最好的那一組。

貝葉斯調參

教程中使用的是 BayesianOptimization 函數來做的。

貝葉斯調參的方法是一種自動調參的方式。前兩種調參的方法運行效率比較低,運行時間很慢。貝葉斯的方法在於,他會建立一個概率模型,基於以前的評估結果,來最小化這個模型值。簡而言之,在嘗試下一組參數時,會參考以前的參數結果,避免做無用功。

最後

不得不說,還是高估了自己的自控力,拖延症真的得治呀。

不過這次學習還是學到了很多東西,雖然很多東西沒有深入瞭解。最讓人興奮的還是大佬的各種可視化操作,看着各種數據被各種可視化出來,感覺好TM神奇。

好好學習,天天向上。又是瞎捅咕的一天,沒幹畢設的事內心還是有點愧疚。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章