XGBoost是Kaggle上的比賽神器按摘,近些年在kaggle或天池比賽上時(shí)常能斬獲大獎(jiǎng),不過(guò)這樣的歷史正在改變迫靖!最近幾年神經(jīng)網(wǎng)絡(luò)的優(yōu)勢(shì)開始從非結(jié)構(gòu)數(shù)據(jù)向結(jié)構(gòu)數(shù)據(jù)延伸院峡,而且在一些Kaggle比賽中取得非常不錯(cuò)的成績(jī)。
XGBoost很牛系宜,不過(guò)更牛的應(yīng)該是NN! 這章我們通過(guò)一個(gè)實(shí)例來(lái)說(shuō)明照激,本實(shí)例基于相同數(shù)據(jù),使用XGBoost和神經(jīng)網(wǎng)絡(luò)(NN)對(duì)類別數(shù)據(jù)轉(zhuǎn)換為數(shù)字盹牧。XGBoost是屬于Tree Model俩垃,故是否使用One-hot影響不大(通過(guò)測(cè)試,確實(shí)如此汰寓,相反口柳,如果轉(zhuǎn)換為one-hot將大大增加內(nèi)存開銷),所以使用xgboost的數(shù)據(jù)轉(zhuǎn)換為數(shù)字后有滑,沒(méi)有再轉(zhuǎn)換為one-hot編碼跃闹。對(duì)神經(jīng)網(wǎng)絡(luò)(NN)而言,是否把數(shù)據(jù)轉(zhuǎn)換為One-hot毛好,影響比較大望艺,所以使用NN的模型數(shù)據(jù)已轉(zhuǎn)換為One-hot。
兩種算法測(cè)試結(jié)果為表2-1肌访。
訓(xùn)練及測(cè)試數(shù)據(jù)沒(méi)有打亂找默,其中測(cè)試數(shù)據(jù)是最新原數(shù)據(jù)的10%。
2.1 XGBoost簡(jiǎn)介
2.1.1概述
XGBoost的全稱是eXtreme Gradient Boosting吼驶,由很多CART(Classification And Regression Tree)樹集成惩激,其中CART是對(duì)分類決策樹和回歸決策樹的總稱。
分類決策樹一般使用信息增益蟹演、信息增益率风钻、基尼系數(shù)來(lái)選擇特征的依據(jù)。CART回歸樹是假設(shè)樹為二叉樹酒请,通過(guò)不斷將特征進(jìn)行分裂魄咕。比如當(dāng)前樹結(jié)點(diǎn)是基于第j個(gè)特征值進(jìn)行分裂的哮兰,設(shè)該特征值小于s的樣本劃分為左子樹,大于s的樣本劃分為右子樹喝滞。因此,當(dāng)我們?yōu)榱饲蠼庾顑?yōu)的切分特征j和最優(yōu)的切分點(diǎn)s做盅,就轉(zhuǎn)化為求解這么一個(gè)目標(biāo)函數(shù)窘哈。
只要遍歷所有特征的的所有切分點(diǎn),就能找到最優(yōu)的切分特征和切分點(diǎn)图筹。最終得到一棵回歸樹。
2.1.2 主要原理
XGBoost本質(zhì)上還是一個(gè)GBDT(Gradient Boosting Decision Tree)让腹,但為力爭(zhēng)把速度和效率發(fā)揮到極致远剩,所以叫X (Extreme) GBoosted。GBDT的原理就是所有弱分類器的結(jié)果相加等于預(yù)測(cè)值骇窍,然后下一個(gè)弱分類器去擬合誤差函數(shù)對(duì)預(yù)測(cè)值的梯度(或殘差)(這個(gè)梯度/殘差就是預(yù)測(cè)值與真實(shí)值之間的誤差)瓜晤。一個(gè)弱分類器如何去擬合誤差函數(shù)殘差?
舉一個(gè)非常簡(jiǎn)單的例子腹纳,比如我今年30歲了痢掠,但計(jì)算機(jī)或者模型GBDT并不知道我今年多少歲,那GBDT咋辦呢嘲恍?
(1)它會(huì)在第一個(gè)弱分類器(或第一棵樹中)隨便用一個(gè)年齡比如20歲來(lái)擬合志群,然后發(fā)現(xiàn)誤差有10歲;
(2)在第二棵樹中蛔钙,用6歲去擬合剩下的損失,發(fā)現(xiàn)差距還有4歲荠医;
(3)在第三棵樹中用3歲擬合剩下的差距吁脱,發(fā)現(xiàn)差距只有1歲了;
(4)在第四課樹中用1歲擬合剩下的殘差彬向,完美兼贡。
最終,四棵樹的結(jié)論加起來(lái)娃胆,就是真實(shí)年齡30歲遍希。實(shí)際工程中GBDT是計(jì)算負(fù)梯度,用負(fù)梯度近似殘差里烦。
注意凿蒜,為何GBDT可以用用負(fù)梯度近似殘差呢?
回歸任務(wù)下州泊,GBDT 在每一輪的迭代時(shí)對(duì)每個(gè)樣本都會(huì)有一個(gè)預(yù)測(cè)值,此時(shí)的損失函數(shù)為均方差損失函數(shù),表達(dá)式如下:
那此時(shí)的負(fù)梯度是這樣計(jì)算的演训,具體表達(dá)式如下:
所以,當(dāng)損失函數(shù)選用均方損失函數(shù)是時(shí)乌奇,每一次擬合的值就是(真實(shí)值 - 當(dāng)前模型預(yù)測(cè)的值)礁苗,即殘差。此時(shí)的變量是疏叨,即“當(dāng)前預(yù)測(cè)模型的值”蚤蔓,也就是對(duì)它求負(fù)梯度秀又。
更多詳細(xì)內(nèi)容可參考:https://blog.csdn.net/v_july_v/article/details/81410574
2.1.3 主要優(yōu)點(diǎn)
(1)目標(biāo)表達(dá)式:
XGBoost優(yōu)化了GBDT的目標(biāo)函數(shù)。一方面昏苏,在GBDT的基礎(chǔ)上加入了正則項(xiàng)洼专,包括葉子節(jié)點(diǎn)的個(gè)數(shù)和每個(gè)葉子節(jié)點(diǎn)輸出的L2模的平方和壶熏,正則項(xiàng)可以控制樹的復(fù)雜度,讓模型傾向于學(xué)習(xí)簡(jiǎn)單的模型帽哑,防止過(guò)擬合妻枕;另外屡谐,XGBoost還支持線性分類器,傳統(tǒng)的GBDT是以CART算法作為基學(xué)習(xí)器饵撑。
(2)使用Shrinkage:
對(duì)每棵樹的預(yù)測(cè)結(jié)果采用了shrinkage滑潘,相當(dāng)于學(xué)習(xí)率,降低模型對(duì)單顆樹的依賴粹舵,提升模型的泛化能力。
(3)采用列采樣:
XGBoost借助了隨機(jī)森林的優(yōu)點(diǎn)稠茂,采用了列采樣诱担,進(jìn)一步防止過(guò)擬合,加速訓(xùn)練過(guò)程摇邦,而傳統(tǒng)的GBDT則沒(méi)有列采樣施籍。
(4)優(yōu)化方法:
XGBoost對(duì)損失函數(shù)的展開采用了一階梯度和二階梯度丑慎,而傳統(tǒng)的GBDT只采用了一階梯度。
(5)增益計(jì)算:
對(duì)分裂依據(jù)進(jìn)行了優(yōu)化腻异。不同于CART算法捂掰,XGBoost采用了新的基于一階導(dǎo)數(shù)和二階導(dǎo)數(shù)的統(tǒng)計(jì)信息作為樹的結(jié)構(gòu)分?jǐn)?shù),采用分列前的結(jié)構(gòu)與分裂后的結(jié)構(gòu)得分的增益作為分裂依據(jù)姐帚,選擇增益最大的特征值作為分裂點(diǎn)罐旗,替代了回歸樹的誤差平方和九秀。
(6)最佳增益節(jié)點(diǎn)查找:
XGBoost在尋找最佳分離點(diǎn)的方式上采用了近似算法鼓蜒,基于權(quán)重的分位數(shù)劃分方式(權(quán)重為二階梯度)娇豫。主要是對(duì)特征取值進(jìn)行分桶冯痢,然后基于桶的值計(jì)算增益浦楣。
(7)預(yù)排序椒振。
在尋找最佳增益節(jié)點(diǎn)時(shí),將所有數(shù)據(jù)放入內(nèi)存進(jìn)行計(jì)算夹供,得到預(yù)排序結(jié)果哮洽,然后在計(jì)算分裂增益的時(shí)候直接調(diào)用。
(8)缺失值處理
對(duì)于特征的值有缺失的樣本匪凉,Xgboost可以自動(dòng)學(xué)習(xí)出他的分裂方向再层。Xgboost內(nèi)置處理缺失值的規(guī)則聂受。
(9)支持并行。
眾所周知碗旅,Boosting算法是順序處理的扛芽,也是說(shuō)Boosting不是一種串行的結(jié)構(gòu)嗎?怎么并行的茫孔?注意XGBoost的并行不是tree粒度的并行馍悟。XGBoost也是一次迭代完才能進(jìn)行下一次迭代的(第t次迭代的代價(jià)函數(shù)里包含)锣咒。XGBoost的并行式在特征粒度上的,也就是說(shuō)每一顆樹的構(gòu)造都依賴于前一顆樹绽左。
2.1.4 XGBoost的模型參數(shù)
XGBoost使用字典的方式存儲(chǔ)參數(shù)戏蔑,主要參數(shù)有如下這些:
params = {
? ? 'booster':'gbtree',
? ? 'objective':'multi:softmax',? # 多分類問(wèn)題
? ? 'num_class':10,? # 類別數(shù)总棵,與multi softmax并用
? ? 'gamma':0.1,? ? # 用于控制是否后剪枝的參數(shù)彻舰,越大越保守刃唤,一般0.1 0.2的樣子
? ? 'max_depth':12,? # 構(gòu)建樹的深度,越大越容易過(guò)擬合
? ? 'lambda':2,? # 控制模型復(fù)雜度的權(quán)重值的L2 正則化項(xiàng)參數(shù)笼裳,參數(shù)越大,模型越不容 易過(guò)擬合
? ? 'subsample':0.7, # 隨機(jī)采樣訓(xùn)練樣本
? ? 'colsample_bytree':3,# 這個(gè)參數(shù)默認(rèn)為1拜轨,是每個(gè)葉子里面h的和至少是多少
? ? ? # 對(duì)于正負(fù)樣本不均衡時(shí)的0-1分類而言,假設(shè)h在0.01附近法牲, ? #min_child_weight為1意味著葉子節(jié)點(diǎn)中最少需要包含100個(gè)樣本拒垃。 #這個(gè)參數(shù)非常影響結(jié)果,控制葉子節(jié)點(diǎn)中二階導(dǎo)的和的最小值谤牡,該 #參數(shù)值越小,越容易過(guò)擬合套么。
? ? 'silent':0,? # 設(shè)置成1 則沒(méi)有運(yùn)行信息輸入胚泌,最好是設(shè)置成0
? ? 'eta':0.007,? # 如同學(xué)習(xí)率
? ? 'seed':1000,
? ? 'nthread':7,? #CPU線程數(shù)
? ? #'eval_metric':'auc'
}
安裝XGBoost建議使用conda命令玷室。如:conda install py-xgboost=0.90
2.2 NN簡(jiǎn)介
使用的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)如下圖所示
本實(shí)例使用的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)比較簡(jiǎn)單箩兽,共4層汗贫,除輸入、輸出層外摊唇,中間是兩個(gè)全連接層。輸入層1183個(gè)節(jié)點(diǎn),這個(gè)正好是特征轉(zhuǎn)換為one-hot后的元素個(gè)數(shù)幢踏,第1個(gè)隱含層的節(jié)點(diǎn)是1000,激活函數(shù)為relu许师,第2個(gè)隱含層的節(jié)點(diǎn)數(shù)為500房蝉,激活函數(shù)為relu,輸出層1個(gè)節(jié)點(diǎn)微渠,激活函數(shù)為sigmoid搭幻。
2.3 數(shù)據(jù)集簡(jiǎn)介
這里使用德國(guó)Rossmann超市2013、2014逞盆、2015三年的銷售數(shù)據(jù),具體數(shù)據(jù)文件包括:
train.csv-包括銷售在內(nèi)的歷史數(shù)據(jù)
test.csv-測(cè)試數(shù)據(jù)(不包括銷售)
store.csv-有關(guān)商店的補(bǔ)充信息
這些數(shù)據(jù)可從這里下載:https://www.kaggle.com/c/rossmann-store-sales/data
1桌肴、train.csv-包括銷售在內(nèi)的歷史數(shù)據(jù),共有9列彪置,每列的含義如下:
date(日期):代表存儲(chǔ)期
DayOfWeek(星期幾):7表示周日耀盗,6表示周六以此類推
store(商店):每個(gè)商店的唯一ID
sale(銷售):特定日期的營(yíng)業(yè)額(這是您的預(yù)期)
customer(客戶):特定日期的客戶數(shù)量
open(開):為對(duì)存儲(chǔ)是否被打開的指示:0 =關(guān)閉,1 =開
promo(促銷):表示商店當(dāng)天是否在進(jìn)行促銷
StateHoliday(州假日):通常扫尺,除州外襟交,所有商店都在州法定假日關(guān)閉形纺。請(qǐng)注意挪捕,所有學(xué)校在公共假日和周末都關(guān)閉鉴嗤。a =公共假期,b =復(fù)活節(jié)假期坯认,c =圣誕節(jié)恩伺,0 =無(wú)
SchoolHoliday(學(xué)校假日):指示(商店,日期)是否受到公立學(xué)校關(guān)閉的影響
(1)導(dǎo)入數(shù)據(jù)
import pandas as pd
import numpy as np
store = pd.read_csv(r".\data\rossmann\store.csv")
train = pd.read_csv(r".\data\rossmann\train.csv",index_col = "Date",parse_dates = ['Date'],low_memory=False)
test = pd.read_csv(r".\data\rossmann\test.csv",index_col = "Date",parse_dates = ['Date'],low_memory=False)
(2)查看前5行數(shù)據(jù)。
(3)查看是否有空值
#查看是否有空值
train.isnull().sum()
Store 0
DayOfWeek 0
Sales 0
Customers 0
Open 0
Promo 0
StateHoliday 0
SchoolHoliday 0
dtype: int64
(4)查看各特征的不同值
#查看各字段的不同值
train['Year'] = train.index.year
print("共有幾年的數(shù)據(jù):",train['Year'].unique())
print("共有幾種促銷方法:",train['Promo'].unique())
共有幾年的數(shù)據(jù): [2015 2014 2013]
共有幾種促銷方法: [1 0]
2烂完、store.csv數(shù)據(jù)集簡(jiǎn)介
StoreType- 區(qū)分4種不同的商店模型:a,b储耐,c,d
Assortment分類 -描述分類級(jí)別:a =基本,b =額外,c =擴(kuò)展
CompetitionDistance-距離最近的競(jìng)爭(zhēng)對(duì)手商店的距離(以米為單位)
CompetitionOpenSince [Month / Year] -給出最近的競(jìng)爭(zhēng)對(duì)手開放的大概年份和月份。
Promo促銷 -表示商店當(dāng)天是否在進(jìn)行促銷
Promo2 -Promo2是某些商店的連續(xù)和連續(xù)促銷:0 =商店不參與,1 =商店正在參與
Promo2Since [年/周] -描述商店開始參與Promo2的年份和日歷周。
PromoInterval-描述啟動(dòng)Promo2的連續(xù)間隔翔忽,并指定重新開始促銷的月份旨别。例如儿捧,“ Feb,May旧找,Aug,Nov”表示該商店的每一輪始于該年任何一年的2月,5月驼壶,8月,11月
2.4使用Xgboost算法實(shí)例
2.4.1 讀取數(shù)據(jù)
(1)導(dǎo)入模塊
import pickle
import csv
#屏蔽警告信息
import warnings
warnings.filterwarnings('ignore')
(2)定義數(shù)據(jù)預(yù)處理函數(shù)
#把csv文件轉(zhuǎn)換為字典
def csv2dicts(csvfile):
? ? data = []
? ? keys = []
? ? for row_index, row in enumerate(csvfile):
? ? ? ? #把第一行標(biāo)題打印出來(lái)
? ? ? ? if row_index == 0:
? ? ? ? ? ? keys = row
? ? ? ? ? ? print(row)
? ? ? ? ? ? continue
? ? ? ? # if row_index % 10000 == 0:
? ? ? ? #? ? print(row_index)
? ? ? ? data.append({key: value for key, value in zip(keys, row)})
? ? return data
#如果值為空高蜂,則用'0'填充
def set_nan_as_string(data, replace_str='0'):
? ? for i, x in enumerate(data):
? ? ? ? for key, value in x.items():
? ? ? ? ? ? if value == '':
? ? ? ? ? ? ? ? x[key] = replace_str
? ? ? ? data[i] = x
(3)讀取數(shù)據(jù)
train_data = "train.csv"
store_data = "store.csv"
store_states = 'store_states.csv'
#讀取數(shù)據(jù)
with open(train_data) as csvfile:
? ? data = csv.reader(csvfile, delimiter=',')
? ? with open('train_data.pickle', 'wb') as f:
? ? ? ? data = csv2dicts(data)
? ? ? ? #頭尾倒過(guò)來(lái)
? ? ? ? data = data[::-1]
? ? ? ? #序列化聪黎,把數(shù)據(jù)保存到文件中
? ? ? ? pickle.dump(data, f, -1)
? ? ? ? print(data[:3])
2.4.2 預(yù)處理數(shù)據(jù)
(1)導(dǎo)入模塊
import pickle
from datetime import datetime
from sklearn import preprocessing
import numpy as np
import random
random.seed(42)
(2)讀取處理后的文件
with open('train_data.pickle', 'rb') as f:
? ? train_data = pickle.load(f)
? ? num_records = len(train_data)
with open('store_data.pickle', 'rb') as f:
? ? store_data = pickle.load(f)
(3)定義預(yù)處理store數(shù)據(jù)函數(shù)
#對(duì)時(shí)間特征進(jìn)行拆分和轉(zhuǎn)換,是是否促銷promo等特征轉(zhuǎn)換為整數(shù)
def feature_list(record):
? ? dt = datetime.strptime(record['Date'], '%Y-%m-%d')
? ? store_index = int(record['Store'])
? ? year = dt.year
? ? month = dt.month
? ? day = dt.day
? ? day_of_week = int(record['DayOfWeek'])
? ? try:
? ? ? ? store_open = int(record['Open'])
? ? except:
? ? ? ? store_open = 1
? ? promo = int(record['Promo'])
? ? #同時(shí)返回state對(duì)應(yīng)的簡(jiǎn)稱
? ? return [store_open,
? ? ? ? ? ? store_index,
? ? ? ? ? ? day_of_week,
? ? ? ? ? ? promo,
? ? ? ? ? ? year,
? ? ? ? ? ? month,
? ? ? ? ? ? day,
? ? ? ? ? ? store_data[store_index - 1]['State']
? ? ? ? ? ? ]
(4)生成訓(xùn)練數(shù)據(jù)
train_data_X = []
train_data_y = []
for record in train_data:
? ? if record['Sales'] != '0' and record['Open'] != '':
? ? ? ? fl = feature_list(record)
? ? ? ? train_data_X.append(fl)
? ? ? ? train_data_y.append(int(record['Sales']))
print("Number of train datapoints: ", len(train_data_y))
print(min(train_data_y), max(train_data_y))
2.4.3 保存預(yù)處理數(shù)據(jù)
(1)把各類別特征轉(zhuǎn)換為整數(shù)备恤,并保存為pickle文件
full_X = train_data_X
full_X = np.array(full_X)
train_data_X = np.array(train_data_X)
les = []
#對(duì)每列進(jìn)行處理稿饰,先把類別轉(zhuǎn)換為數(shù)值,然后轉(zhuǎn)換為獨(dú)熱編碼
for i in range(train_data_X.shape[1]):
? ? le = preprocessing.LabelEncoder()
? ? le.fit(full_X[:, i])
? ? les.append(le)
? ? train_data_X[:, i] = le.transform(train_data_X[:, i])
with open('les.pickle', 'wb') as f:
? ? pickle.dump(les, f, -1)
train_data_X = train_data_X.astype(int)
train_data_y = np.array(train_data_y)
#保存數(shù)據(jù)到feature_train_data.pickle文件
with open('feature_train_data.pickle', 'wb') as f:
? ? pickle.dump((train_data_X, train_data_y), f, -1)
? ? print(train_data_X[0], train_data_y[0])
2.4.4 采樣生成訓(xùn)練與測(cè)試數(shù)據(jù)
(1)讀取數(shù)據(jù)
train_ratio = 0.9
f = open('feature_train_data.pickle', 'rb')
(X, y) = pickle.load(f)
num_records = len(X)
train_size = int(train_ratio * num_records)
(2)生成訓(xùn)練與測(cè)試集
X_train = X[:train_size]
X_val = X[train_size:]
y_train = y[:train_size]
y_val = y[train_size:]
(3)定義采樣函數(shù)
def sample(X, y, n):
? ? '''random samples'''
? ? num_row = X.shape[0]
? ? indices = numpy.random.randint(num_row, size=n)
? ? return X[indices, :], y[indices]
(4)采樣數(shù)據(jù)
X_train, y_train = sample(X_train, y_train, 200000) # Simulate data sparsity
print("Number of samples used for training: " + str(y_train.shape[0]))
2.4.5 構(gòu)建模型
(1)導(dǎo)入模塊
import tensorflow as tf
import numpy
numpy.random.seed(123)
from sklearn import linear_model
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
import xgboost as xgb
from sklearn import neighbors
from sklearn.preprocessing import Normalizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import Model as KerasModel
from tensorflow.keras.layers import Input, Dense, Activation, Reshape,Flatten
from tensorflow.keras.layers import Concatenate
from tensorflow.keras.layers import Embedding
from tensorflow.keras.callbacks import ModelCheckpoint
(2)構(gòu)建xgboost模型
class Model(object):
? ? def evaluate(self, X_val, y_val):
? ? ? ? assert(min(y_val) > 0)
? ? ? ? guessed_sales = self.guess(X_val)
? ? ? ? relative_err = numpy.absolute((y_val - guessed_sales) / y_val)
? ? ? ? result = numpy.sum(relative_err) / len(y_val)
? ? ? ? return result
class XGBoost(Model):
? ? def __init__(self, X_train, y_train, X_val, y_val):
? ? ? ? super().__init__()
? ? ? ? dtrain = xgb.DMatrix(X_train, label=numpy.log(y_train))
? ? ? ? evallist = [(dtrain, 'train')]
? ? ? ? param = {'nthread': -1,
? ? ? ? ? ? ? ? 'max_depth': 7,
? ? ? ? ? ? ? ? 'eta': 0.02,
? ? ? ? ? ? ? ? 'silent': 1,
? ? ? ? ? ? ? ? 'objective': 'reg:linear',
? ? ? ? ? ? ? ? 'colsample_bytree': 0.7,
? ? ? ? ? ? ? ? 'subsample': 0.7}
? ? ? ? num_round = 3000
? ? ? ? self.bst = xgb.train(param, dtrain, num_round, evallist)
? ? ? ? print("Result on validation data: ", self.evaluate(X_val, y_val))
? ? def guess(self, feature):
? ? ? ? dtest = xgb.DMatrix(feature)
? ? ? ? return numpy.exp(self.bst.predict(dtest))
2.4.6 訓(xùn)練模型
models = []
print("Fitting XGBoost...")
models.append(XGBoost(X_train, y_train, X_val, y_val))
運(yùn)行結(jié)果如下:
[2980] train-rmse:0.148366
[2981] train-rmse:0.148347
[2982] train-rmse:0.148314
[2983] train-rmse:0.148277
[2984] train-rmse:0.148238
[2985] train-rmse:0.148221
[2986] train-rmse:0.148218
[2987] train-rmse:0.148187
[2988] train-rmse:0.148182
[2989] train-rmse:0.148155
[2990] train-rmse:0.148113
[2991] train-rmse:0.148113
[2992] train-rmse:0.148067
[2993] train-rmse:0.148066
[2994] train-rmse:0.148064
[2995] train-rmse:0.148062
[2996] train-rmse:0.148048
[2997] train-rmse:0.148046
[2998] train-rmse:0.148046
[2999] train-rmse:0.148041
Result on validation data: 0.14628885960491078
2.5 使用NN算法實(shí)例
2.5.1 預(yù)處理數(shù)據(jù)
導(dǎo)入數(shù)據(jù)露泊、對(duì)數(shù)據(jù)進(jìn)行預(yù)處理喉镰,這些與2.4小節(jié)中的2.4.1、2.4.2一樣滤淳,接下來(lái)對(duì)個(gè)特征先轉(zhuǎn)換為數(shù)字梧喷,然后轉(zhuǎn)換為one-hot編碼砌左,并保存脖咐。
(1)把數(shù)據(jù)轉(zhuǎn)換為one-hot編碼
encoded_x = None
full_X = train_data_X
full_X = np.array(full_X)
train_data_X = np.array(train_data_X)
for i in range(train_data_X.shape[1]):
? ? label_encoder = preprocessing.LabelEncoder()
? ? feature = label_encoder.fit_transform(train_data_X[:,i])
? ? feature = feature.reshape(train_data_X.shape[0], 1)
? ? onehot_encoder = preprocessing.OneHotEncoder(sparse=False)
? ? feature = onehot_encoder.fit_transform(feature)
? ? if encoded_x is None:
? ? ? ? encoded_x = feature
? ? else:
? ? ? ? encoded_x = np.concatenate((encoded_x,feature),axis=1)
print("X shape: : ", encoded_x.shape)
(2)保存數(shù)據(jù)
train_data_X =encoded_x.astype(int)
train_data_y = np.array(train_data_y)
#保存數(shù)據(jù)到feature_train_data.pickle文件
with open('feature_train_data.pickle', 'wb') as f:
? ? pickle.dump((train_data_X, train_data_y), f, -1)
? ? print(train_data_X[0], train_data_y[0])
2.5.2 生成訓(xùn)練數(shù)據(jù)
(1)讀取數(shù)據(jù)
train_ratio = 0.9
f = open('feature_train_data.pickle', 'rb')
(X, y) = pickle.load(f)
num_records = len(X)
train_size = int(train_ratio * num_records)
(2)生成訓(xùn)練數(shù)據(jù)
X_train = X[:train_size]
X_val = X[train_size:]
y_train = y[:train_size]
y_val = y[train_size:]
(3)定義采樣函數(shù)
def sample(X, y, n):
? ? '''random samples'''
? ? num_row = X.shape[0]
? ? indices = numpy.random.randint(num_row, size=n)
? ? return X[indices, :], y[indices]
(4)通過(guò)采樣生成訓(xùn)練數(shù)據(jù)
X_train, y_train = sample(X_train, y_train, 200000) # Simulate data sparsity
print("Number of samples used for training: " + str(y_train.shape[0]))
2.5.3 構(gòu)建神經(jīng)網(wǎng)絡(luò)模型
(1)導(dǎo)入模塊
import tensorflow as tf
import numpy
numpy.random.seed(123)
from sklearn import linear_model
from sklearn.ensemble import RandomForestRegressor
from sklearn.svm import SVR
from sklearn.preprocessing import StandardScaler
import xgboost as xgb
from sklearn import neighbors
from sklearn.preprocessing import Normalizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.models import Model as KerasModel
from tensorflow.keras.layers import Input, Dense, Activation, Reshape,Flatten
from tensorflow.keras.layers import Concatenate
from tensorflow.keras.layers import Embedding
from tensorflow.keras.callbacks import ModelCheckpoint
(2)定義Model類?
class Model(object):
? ? def evaluate(self, X_val, y_val):
? ? ? ? assert(min(y_val) > 0)
? ? ? ? guessed_sales = self.guess(X_val)
? ? ? ? relative_err = numpy.absolute((y_val - guessed_sales) / y_val)
? ? ? ? result = numpy.sum(relative_err) / len(y_val)
? ? ? ? return result
(3)構(gòu)建神經(jīng)網(wǎng)絡(luò)
class NN(Model):
? ? def __init__(self, X_train, y_train, X_val, y_val):
? ? ? ? super().__init__()
? ? ? ? self.epochs = 10
? ? ? ? self.checkpointer = ModelCheckpoint(filepath="best_model_weights.hdf5", verbose=1, save_best_only=True)
? ? ? ? self.max_log_y = max(numpy.max(numpy.log(y_train)), numpy.max(numpy.log(y_val)))
? ? ? ? self.__build_keras_model()
? ? ? ? self.fit(X_train, y_train, X_val, y_val)
? ? def __build_keras_model(self):
? ? ? ? self.model = Sequential()
? ? ? ? self.model.add(Dense(1000, kernel_initializer="uniform", input_dim=1183))
? ? ? ? #self.model.add(Dense(1000, kernel_initializer="uniform", input_dim=8))
? ? ? ? self.model.add(Activation('relu'))
? ? ? ? self.model.add(Dense(500, kernel_initializer="uniform"))
? ? ? ? self.model.add(Activation('relu'))
? ? ? ? self.model.add(Dense(1))
? ? ? ? self.model.add(Activation('sigmoid'))
? ? ? ? self.model.compile(loss='mean_absolute_error', optimizer='adam')
? ? def _val_for_fit(self, val):
? ? ? ? val = numpy.log(val) / self.max_log_y
? ? ? ? return val
? ? def _val_for_pred(self, val):
? ? ? ? return numpy.exp(val * self.max_log_y)
? ? def fit(self, X_train, y_train, X_val, y_val):
? ? ? ? self.model.fit(X_train, self._val_for_fit(y_train),
? ? ? ? ? ? ? ? ? ? ? validation_data=(X_val, self._val_for_fit(y_val)),
? ? ? ? ? ? ? ? ? ? ? epochs=self.epochs, batch_size=128,
? ? ? ? ? ? ? ? ? ? ? # callbacks=[self.checkpointer],
? ? ? ? ? ? ? ? ? ? ? )
? ? ? ? # self.model.load_weights('best_model_weights.hdf5')
? ? ? ? print("Result on validation data: ", self.evaluate(X_val, y_val))
? ? def guess(self, features):
? ? ? ? result = self.model.predict(features).flatten()
? ? ? ? return self._val_for_pred(result)
2.5.4 訓(xùn)練模型
models = []
print("Fitting NN...")
for i in range(1):
? ? models.append(NN(X_train, y_train, X_val, y_val))
運(yùn)行結(jié)果:
Fitting NN...
Train on 200000 samples, validate on 84434 samples
Epoch 1/10
200000/200000 [==============================] - 12s 60us/sample - loss: 0.0121 - val_loss: 0.0142
Epoch 2/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0080 - val_loss: 0.0104
Epoch 3/10
200000/200000 [==============================] - 11s 53us/sample - loss: 0.0071 - val_loss: 0.0100
Epoch 4/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0064 - val_loss: 0.0099
Epoch 5/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0059 - val_loss: 0.0098
Epoch 6/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0055 - val_loss: 0.0103
Epoch 7/10
200000/200000 [==============================] - 11s 55us/sample - loss: 0.0051 - val_loss: 0.0100
Epoch 8/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0047 - val_loss: 0.0099
Epoch 9/10
200000/200000 [==============================] - 11s 53us/sample - loss: 0.0045 - val_loss: 0.0102
Epoch 10/10
200000/200000 [==============================] - 11s 54us/sample - loss: 0.0042 - val_loss: 0.0100
Result on validation data: 0.10825838109273625
接下來(lái)將用更多實(shí)例,從多個(gè)角度比較NN與傳統(tǒng)ML的比較汇歹,帶EE(Entity Embedding)的NN與不帶NN的比較屁擅,帶EE的傳統(tǒng)ML與不帶EE的傳統(tǒng)ML,以及EE在ML的頂級(jí)應(yīng)用(如推薦算法、預(yù)測(cè)等問(wèn)題上的使用)产弹。
EE就像一座橋梁派歌,把結(jié)構(gòu)化數(shù)據(jù)與NN(或深度學(xué)習(xí)算法)連接在一起弯囊,大大發(fā)揮了NN在處理結(jié)構(gòu)化數(shù)據(jù)方面的潛能(即NN強(qiáng)大的學(xué)習(xí)能力),深度學(xué)習(xí)將徹底改變傳統(tǒng)機(jī)器學(xué)習(xí)胶果。