基础学习:
Liner Regression
$f(x)=w^{\prime} x+b$
1 | #w是列向量 矩阵由一个个列向量构成 y = dot(w_t,X)+b |
策略:通过loss衡量w和b。$loss=(f(x)-y)^{2}$
优化:
最小二乘:
^{-1})
1
w_t = np.dot(np.dot(y,X.T), np.linalg.inv(np.dot(X,X.T)))
梯度下降
X^T)
1
2
3
4
5while True:
grad = 2 *np.dot((np.dot(w_t,x)-y),x.t)
w_t -=0.1 * grad
if np.linalg.norm(w_t,ord = 2)<1e-3:
break
梯度提升树GBDT
CART回归树
GBDT是一个集成模型,可以看做是很多个基模型的线性相加,其中的基模型就是CART回归树。
CART树是一个二分决策树模型,每个节点特征取值为“是”和“不是”。
回归树生成:一个回归树对应的输入空间的一个划分,假设已经将输入空间划分为M个单元R1,R2,R3….Rm,并且每个单元都有固定的输出值cm,其中I为判别函数。
输入:训练数据集D={(x1,y1),(x2,y2),….,(xn,yn)}
输出:一颗回归树 $f(x)=\sum_{m=1}^{M} \hat{c}_{m} I\left(x \in R_{m}\right)$
。
可知:Rm上的最优输出值就是Rm内所有样本xi对应yi的均值。
如何对输入空间进行划分?:选择最优的特征作为划分。如果特征是连续变量,R1 = {x|x^j==s} and R2 = {x|x^j != s};寻找最优的变量j和最优切分点s:
回归树剪枝
先从整体树T0开始,对内部任意节点t,比较以t作为单节点树的损失与t作为根节点树的损失,如果单节点比下面一棵树还要好,就给剪掉。剪完后的树继续重复此过程。
loss:$C_{a}(T)=C(T)+\alpha|T|$
C(T)为对训练数据的误差,|T|为树的节点数量,alpha调节的是要精准度还是要模型的简单性。(过拟合与欠拟合)
GBDT
模型定义如下:$f_{t}(x)=\sum_{t=1}^{T} h_{t}(x)$;ft(x)表示第t轮的模型,ht(x)表示第t颗决策树
采用前向分步算法:$f_{t}(x)=f_{t-1}(x)+h_{t}(x)$
Loss:
第t轮的第i个样本的损失函数的负梯度表示为:
利用(xi, $r_{ti}$) (i=1,2,…m),我们可以拟合一颗CART回归树,得到了第t颗回归树,其对应的叶节点区域Rtj, j=1,2,…,J。其中J为叶子节点的个数。
针对每一个叶子节点里的样本,我们求出使损失函数最小,也就是拟合叶子节点最好的的输出值ctj如下(注意这里的yi是真实值,不是残差):
此时本轮的决策树拟合函数就得到了:
然后本轮的强学习器也就得到了:
之后一直迭代下去,直到损失函数收敛.
Xgboos
目标函数:$\mathcal{L}^{(t)}=\sum_{i=1}^{n} l\left(y_{i}, \hat{y}_{i}^{(t-1)}+f_{t}\left(\mathbf{x}_{i}\right)\right)+\Omega\left(f_{t}\right)$
- 规整项$\Omega\left(f_{t}\right)$是一个递归的式子,规整项仅仅是第t颗树的,具体起来就是这棵树所有叶子节点权重向量的二范数。
$\mathcal{L}^{(t)} \simeq \sum_{i=1}^{n}\left[l\left(y_{i}, \hat{y}^{(t-1)}\right)+g_{i} f_{t}\left(\mathbf{x}_{i}\right)+\frac{1}{2} h_{i} f_{t}^{2}\left(\mathbf{x}_{i}\right)\right]+\Omega\left(f_{t}\right)$
泰勒展开,假设残差接近于零。
麦克劳林:$f(x)=f(0)+\frac{f^{\prime}(0)}{1 !} x+\frac{f^{\prime \prime}(0)}{2 !} x^{2}+\frac{f^{\prime \prime \prime}(0)}{3 !} x^{3}+\dots+\frac{f^{(n)}(0)}{n !} x^{n}+R_{n}(x)$
$\begin{aligned} \tilde{\mathcal{L}}^{(t)} &=\sum_{i=1}^{n}\left[g_{i} f_{t}\left(\mathbf{x}_{i}\right)+\frac{1}{2} h_{i} f_{t}^{2}\left(\mathbf{x}_{i}\right)\right]+\gamma T+\frac{1}{2} \lambda \sum_{j=1}^{T} w_{j}^{2} \ &=\sum_{j=1}^{T}\left[\left(\sum_{i \in I_{j}} g_{i}\right) w_{j}+\frac{1}{2}\left(\sum_{i \in I_{j}} h_{i}+\lambda\right) w_{j}^{2}\right]+\gamma T \end{aligned}$
- 把样本 i 归类到所在的叶子节点 j 上,改写目标函数的形式如上
w的解析解:$w_{j}^{*}=-\frac{\sum_{i \in I_{j}} g_{i}}{\sum_{i \in I_{j}} h_{i}+\lambda}$
代入可得到:$\tilde{\mathcal{L}}^{(t)}(q)=-\frac{1}{2} \sum_{j=1}^{T} \frac{\left(\sum_{i \in I_{j}} g_{i}\right)^{2}}{\sum_{i \in I_{j}} h_{i}+\lambda}+\gamma T$
LightGBM
算法学习
线性回归
1 | #简单建模 |
观察标签分布。
1 | import seaborn as sns |
log(x+1)变换
1 | train_y_ln = np.log(train_y + 1) |
再次拟合验证
1 | model = model.fit(train_X, train_y_ln) |
五折交叉验证
不会把所有的数据集都拿来训练,而是分出一部分来(这一部分不参加训练)对训练集生成的参数进行测试,相对客观的判断这些参数对训练集之外的数据的符合程度。这种思想就称为交叉验证(Cross Validation)
1 | from sklearn.model_selection import cross_val_score |
绘制学习率曲线与验证曲线
1 | from sklearn.model_selection import learning_curve, validation_curve |
多模型对比
1 | train = sample_feature[continuous_feature_names + ['price']].dropna() |
嵌入式选择最常用的是L1正则化与L2正则化。在对线性回归模型加入两种正则化方法后,他们分别变成了岭回归与Lasso回归。
1 | from sklearn.linear_model import LinearRegression |
1 | model = LinearRegression().fit(train_X, train_y_ln) |
L2正则化在拟合过程中通常都倾向于让权值尽可能小,最后构造一个所有参数都比较小的模型。
1 | model = Ridge().fit(train_X, train_y_ln) |
L1正则化有助于生成一个稀疏权值矩阵,进而可以用于特征选择。
1 | model = Lasso().fit(train_X, train_y_ln) |
部分常用非线性模型
1 | from sklearn.linear_model import LinearRegression |
模型调参
1 | ## LGB的参数集合: |
贪心调参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22best_obj = dict()
for obj in objective:
model = LGBMRegressor(objective=obj)
score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))
best_obj[obj] = score
best_leaves = dict()
for leaves in num_leaves:
model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves)
score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))
best_leaves[leaves] = score
best_depth = dict()
for depth in max_depth:
model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0],
num_leaves=min(best_leaves.items(), key=lambda x:x[1])[0],
max_depth=depth)
score = np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))
best_depth[depth] = score
sns.lineplot(x=['0_initial','1_turning_obj','2_turning_leaves','3_turning_depth'], y=[0.143 ,min(best_obj.values()), min(best_leaves.values()), min(best_depth.values())])Grid Search 调参
1
2
3
4
5
6
7
8
9
10
11
12
13from sklearn.model_selection import GridSearchCV
parameters = {'objective': objective , 'num_leaves': num_leaves, 'max_depth': max_depth}
model = LGBMRegressor()
clf = GridSearchCV(model, parameters, cv=5)
clf = clf.fit(train_X, train_y)
clf.best_params_
model = LGBMRegressor(objective='regression',
num_leaves=55,
max_depth=15)
np.mean(cross_val_score(model, X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)))贝叶斯调参
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26from bayes_opt import BayesianOptimization
def rf_cv(num_leaves, max_depth, subsample, min_child_samples):
val = cross_val_score(
LGBMRegressor(objective = 'regression_l1',
num_leaves=int(num_leaves),
max_depth=int(max_depth),
subsample = subsample,
min_child_samples = int(min_child_samples)
),
X=train_X, y=train_y_ln, verbose=0, cv = 5, scoring=make_scorer(mean_absolute_error)
).mean()
return 1 - val
rf_bo = BayesianOptimization(
rf_cv,
{
'num_leaves': (2, 100),
'max_depth': (2, 100),
'subsample': (0.1, 1),
'min_child_samples' : (2, 100)
}
)
rf_bo.maximize()
1 - rf_bo.max['target']
还采用了一些基本方法来提高预测的精度
1 | plt.figure(figsize=(13,5)) |