上一節中介紹了 $ \lambda $ 的計算,lambdaMART就以計算的每個doc的 $\lambda$ 值作為label,訓練Regression Tree,並在最后對葉子節點上的樣本 $lambda$ 均值還原成 $\gamma$ ,乘以learningRate加到此前的Regression Trees上,更新score,重新對query下的doc按score排序,再次計算deltaNDCG以及 $\lambda$ ,如此迭代下去直至樹的數目達到參數設定或者在validation集上不再持續變好(一般實踐來說不在模型訓練時設置validation集合,因為validation集合一般比訓練集合小很多,很容易收斂,達不到效果,不如訓練時一步到位,然后另起test集合做結果評估)。
其實Regression Tree的訓練很簡單,最主要的就是決定如何分裂節點。lambdaMART采用最朴素的最小二乘法,也就是最小化平方誤差和來分裂節點:即對於某個選定的feature,選定一個值val,所有<=val的樣本分到左子節點,>val的分到右子節點。然后分別對左右兩個節點計算平方誤差和,並加在一起作為這次分裂的代價。遍歷所有feature以及所有可能的分裂點val(每個feature按值排序,每個不同的值都是可能的分裂點),在這些分裂中找到代價最小的。
舉個栗子,假設樣本只有上一節中計算出 $\lambda$ 的那10個:
1 qId=1830 features and lambdas 2 qId=1830 1:0.003 2:0.000 3:0.000 4:0.000 5:0.003 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(1):-0.495 3 qId=1830 1:0.026 2:0.125 3:0.000 4:0.000 5:0.027 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(2):-0.206 4 qId=1830 1:0.001 2:0.000 3:0.000 4:0.000 5:0.001 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(3):-0.104 5 qId=1830 1:0.189 2:0.375 3:0.333 4:1.000 5:0.196 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(4):0.231 6 qId=1830 1:0.078 2:0.500 3:0.667 4:0.000 5:0.086 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(5):0.231 7 qId=1830 1:0.075 2:0.125 3:0.333 4:0.000 5:0.078 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(6):-0.033 8 qId=1830 1:0.079 2:0.250 3:0.667 4:0.000 5:0.085 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(7):0.240 9 qId=1830 1:0.148 2:0.000 3:0.000 4:0.000 5:0.148 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(8):0.247 10 qId=1830 1:0.059 2:0.000 3:0.000 4:0.000 5:0.059 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(9):-0.051 11 qId=1830 1:0.071 2:0.125 3:0.333 4:0.000 5:0.074 6:0.000 7:0.000 8:0.000 9:0.000 10:0.000 lambda(10):-0.061
上表中除了第一列是qId,最后一列是lambda外,其余都是feature,比如我們選擇feature(1)的0.059做分裂點,則左子節點<=0.059的doc有: 1, 2, 3, 9;而>0.059的被安排到右子節點,doc有4, 5, 6, 7, 8, 10。由此左右兩個子節點的lambda均值分別為:
$ \bar{\lambda_L}=\frac{\lambda_1+\lambda_2+\lambda_3+\lambda_9}{4}=\frac{-0.495-0.206-0.104-0.051}{4}=-0.214$
$\bar{\lambda_R}=\frac{\lambda_4+\lambda_5+\lambda_6+\lambda_7+\lambda_8+\lambda_{10}}{6}=\frac{0.231+0.231-0.033+0.240+0.247-0.061}{6}=0.143$
繼續計算左右子節點的平方誤差和:
$s_{L}=\sum_{i\in L}{(\lambda_i-\bar{\lambda_L})^2}=(-0.495+0.214)^2+(-0.206+0.214)^2+(-0.104+0.214)^2+(-0.051+0.214)^2=0.118$
$s_{R}=\sum_{i\in R}{(\lambda_i-\bar{\lambda_R})^2}=(0.231-0.143)^2+(0.231-0.143)^2+(-0.033-0.143)^2+(0.240-0.143)^2+(0.247-0.143)^2+(0.016-0.143)^2=0.083$
因此將feature(1)的0.059的均方差(分裂代價)是:
$Cost_{0.059@feature(1)}=s_{L}+s_{R}=0.118+0.083=0.201$
我們可以像上面那樣遍歷所有feature的不同值,嘗試分裂,計算Cost,最終選擇所有可能分裂中最小Cost的那一個作為分裂點。然后將 $s_{L}$ 和 $s_{R}$ 分別作為左右子節點的屬性存儲起來,並把分裂的樣本也分別存儲到左右子節點中,然后維護一個隊列,始終按平方誤差和 s 降序插入新分裂出的節點,每次從該隊列頭部拿出一個節點(並基於這個節點上的樣本)進行分裂(即最大均方差優先分裂),直到樹的分裂次數達到參數設定(訓練時傳入的leaf值,葉子節點的個數與分裂次數等價)。這樣我們就訓練出了一棵Regression Tree。
上面講述了一棵樹的標准分裂過程,需要多提一點的是,樹的分裂還有一個參數設定:葉子節點上的最少樣本數,比如我們設定為3,則在feature(1)處,0.001和0.003兩個值都不能作為分裂點,因為用它們做分裂點,左子樹的樣本數分別是1和2,均<3。葉子節點的最少樣本數越小,模型則擬合得越好,當然也容易過擬合(over-fitting);反之如果設置得越大,模型則可能欠擬合(under-fitting),實踐中可以使用cross validation的辦法來尋找最佳的參數設定。