缺失值處理
真實場景中,有很多可能導致產生稀疏。如:數據缺失、某個特徵上出現很多0項、人工進行one-hot編碼導致大量的0
理論上,數據缺失和數值0的含義是不同的,數值0是有效的
實際上,數值0的處理方式類似缺失值的處理方式,都視爲稀疏特徵
在xgboost中,數值0的處理方式和缺失值的處理方式是同一的。這只是一個計算上的優化,用於加速稀疏特徵的處理速度
對於稀疏特徵,只需要對有效值進行處理,無效值則採用默認的分裂方向。
注意每個結點的默認分裂方向可能不同。
XGBoost中實現的方式
在xgboost算法的實現中,允許對數值0進行不同的處理。可以將數值0視作缺失值,也可以將其視作有效值。
如果數值0是有真實意義的,則建議將其視作有效值。
缺失值處理算法
輸入:數據集D=(x1,y1~),(x2,y2~),...,(xN,yN~),其中樣本xi=(xi,1,xi,2,...,xi,n)T
屬於當前葉節點的樣本的下標集合I
屬於當前葉節點,且第k維特徵有效的樣本的下標集合Ik=i∈I∣xk,i=missing
輸出:當前葉節點最佳分裂點
算法
初始化:score←0,G←∑i∈Igi,H←∑i∈Ihi
遍歷各維度:k = 1,…,n
先從左邊開始遍歷
初始化 GL←0,HL←0
遍歷各拆分點:沿着第k維,將當前有效的葉節點的樣本從小到大排序,相當於所有無效特徵值的樣本放在最右側,因此可以保證無效的特徵值都在右子樹。
然後用j順序遍歷排序後的樣本下標:
GL←GL+gj,HL←HL+hjGR←G−GL,HR←H−HL
score←max(score,HL+λGL2+HR+λGR2−H+λG2)
再從右邊開始遍歷
初始化GR←0,HR←0
遍歷各拆分點:沿着第k維,將當前有效的葉節點的樣本從大到小排序,相當於所有無效特徵值的樣本放在最左側,因此可以保證無效的特徵值都在左子樹。
然後用j順序遍歷排序後的樣本下標:
GR←GR+gj,HR←HR+hjGL←G−GL,HL←H−HR
score←max(score,HL+λGL2+HR+λGR2−H+λG2)
選取最大的score對應的維度和拆分點作爲最優拆分點
其他優化
預排序
xgboost提出column block 數據結構來降低排序時間
每一個block代表一個屬性,樣本在該block中按照它在該屬性的值排好序
這些block只需要在程序開始的時候計算一次,後續排序只需要線性掃描這些block即可
由於屬性之間是獨立的,因此在每個維度尋找劃分點可以並行計算
block可以僅存放樣本的索引,而不是樣本本身,這樣節省了大量的存儲空間
緩存命中率的優化
Cache-aware預取
由於在column block中,樣本的順序會被打亂,這會使得從導數數組中獲取gi時的緩存命中率較低。
因此xgboost提出了cache-aware預取算法,用於提升緩存命中率
xgboost會以minibatch的方式累加數據,然後在後臺開啓一個線程來加載需要用到的導數gi
這裏有個這種,minibatch太大,則會引起cache miss;太小,則並行程度較低
out of score 大數據集
xgboost利用硬盤來處理超過內存容量的大數據。其中使用了下列技術
使用block 壓縮技術來環節內存和硬盤的數據交換IO:數據按列壓縮,並且在硬盤到內存的傳輸過程中被自動解壓縮
數據隨機分片到多個硬盤,每個硬盤對應一個預取線程,從而加大"內存-硬盤"交換數據的吞吐量