https://yourfreetemplates.com/free-machine-learning-diagram/
上一章提到的基础学习(又称弱学习)於多数真实情况下的性能其实并不好。
低维资料时具有较高的标准差,高维资料时则是变异太大导致稳定性不够。
为了降低模型变异及提高准确度,可根据不同的数据,於各阶段使用不同的演算法来训练模型。
最终以不同权重的方式结合每个结果,得到一个更优性能的学习器。
核心理念:透过组合多个弱学习器,从而创建一个强学习器(或称「集成学习」)。
当数据非常复杂,或有多种潜在的假设时,集成学习非常实用。
这是最简单的集成学习。
将资料丢进 n 个「不同的弱学习器」,求出测试资料的预测结果,将结果向量相加。
因为分类只有 0/1,新的结果向量里的值最大为 n,最小为0。
透过投票,至少有过半数以上的学习器预测 1,才判定结果是 1,其余则为 0。
投票方法又分两种:
硬投票:预测结果是所有投票结果最多出现的类。
软投票:预测结果是所有投票结果中「概率和」最大的类。
如:预测某样本的结果为 70%、51%、1%,硬投票会判定为正样本(2 正 1 负),但软投票则会判定为负样本(70%+51%+1% < 30%+49%+99%)。
优点:简单快速,不需调整过多参数。
缺点:学习器种类上限会限制其精确度。
以鸢尾花为例,且故意拿掉部分 y 与特徵(使模型预测较不准):
from sklearn import datasets
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
ds = datasets.load_iris()
X, y = ds.data[50:, [1, 2]], ds.target[50:]
y = LabelEncoder().fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=1, stratify=y)
# 三个弱学习器:此处用逻辑斯回归、决策树和 KNN
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
lr_PL = make_pipeline(
StandardScaler(),
lr = LogisticRegression(penalty='l2', C=0.001, random_state=1)
)
dt_PL = make_pipeline(
DecisionTreeClassifier(max_depth=1, criterion='entropy', random_state=0)
)
knn_PL = make_pipeline(
StandardScaler(),
KNeighborsClassifier(n_neighbors=1, metric='minkowski')
)
all_clf = [lr_PL, dt_PL, knn_PL]
from sklearn.ensemble import VotingClassifier
ens = [('LR', lr_PL), ('DT', dt_PL), ('KNN', knn_PL)]
vc = VotingClassifier(ens, voting='soft')
clf_labels = ['Logistic regression', 'Decision tree', 'KNN', 'Voting Classifier']
all_clf = [lr_PL, dt_PL, knn_PL, vc]
# 使用 cross validation 避免过拟合
from sklearn.model_selection import cross_val_score
for clf, label in zip([lr_PL, dt, knn_PL], clf_labels):
scores = cross_val_score(
clf, X_train, y_train,
cv=10,
scoring='roc_auc'
)
print(f"ROC AUC: {scores.mean():0.2f} (+/- {scores.std():0.2f}) [{label}]")
>> ROC AUC: 0.92 (+/- 0.15) [Logistic regression]
ROC AUC: 0.87 (+/- 0.18) [Decision Tree]
ROC AUC: 0.85 (+/- 0.13) [KNN]
ROC AUC: 0.98 (+/- 0.05) [Voting Classifier]
把决策边界作图(代码在补充 1.):
直接投票法的问题-学习器种类有限,仅凭数个演算法,可能无法达到专案需求的精度。
因此,人们发明 Bootstrap AGGregatING,也就是 Bagging 装袋法来解决。
选定一弱学习器。将原样本做「会放回抽样」,生成 n 个与原数据一样大的「自助样本」。
(因此,某些样本点可能在自助样本中出现多次,某些则被忽略)
学习器会将每个自助样本都训练,最终产出 n 个模型。藉投票决定将测试样本分派(预测)到哪个类别。
优点:从样本随机抽样,降低杂讯被重复训练到的机率,进而提升模型稳定性。
缺点:只是将每次的错误率稀释掉,实际模型依旧没有学的更好。
以红酒分类为例:
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True)
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
le = LabelEncoder()
y = le.fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1, stratify=y)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
tree = DecisionTreeClassifier(criterion='entropy', random_state=1)
bag = BaggingClassifier(
base_estimator=tree,
n_estimators=500,
max_samples=1.0,
max_features=1.0,
bootstrap=True,
bootstrap_features=False,
n_jobs=1,
random_state=1
)
超参数:
1. nestimators: 创建 n 个子模型。默认 10。
2. maxsamples: 每个子模型使用 n 个样本数据训练。默认 1.0。
3. maxfeatures: 若是 int,则选取 n 个特徵;若是 float 则选取 n\X.shape[1] 个特徵。默认 1.0。
4. bootstrap: 在随机选取样本时是否将已选样本放回。默认 True。
5. bootstrapfeatures: 在随机选取特徵时是否将已选特徵放回。默认 False。
6. njobs: 用於训练和预测所需要 CPU 的数量(-1 表使用所有空闲 CPU)。
接着比较一下 一般决策树 vs. Bagging 决策树(就是随机森林)
# 1. 决策树
from sklearn.metrics import accuracy_score
tree.fit(X_train, y_train)
y_train_pred = tree.predict(X_train)
y_test_pred = tree.predict(X_test)
tree_train = accuracy_score(y_train, y_train_pred)
tree_test = accuracy_score(y_test, y_test_pred)
print(f'Decision tree train/test accuracies {tree_train:.3f} / {tree_test:.3f}')
# 2. Bagging
bag.fit(X_train, y_train)
y_train_pred = bag.predict(X_train)
y_test_pred = bag.predict(X_test)
bag_train = accuracy_score(y_train, y_train_pred)
bag_test = accuracy_score(y_test, y_test_pred)
print(f'Bagging train/test accuracies {bag_train:.3f} / {bag_test:.3f}')
>> Decision tree train/test accuracies 1.000 / 0.833
Bagging train/test accuracies 1.000 / 0.917
把决策边界作图(代码在补充 2.):
基於决策树演算法上,透过 Bagging 演算法,让多颗树生长且不进行剪枝,
并对这些树的结果进行组合(分类用简单多数投票法,回归则用平均法)。
优点:可以处理分类与回归资料。接受高维度资料。非平衡误差资料时能平衡误差。
缺点:需大量记忆体储存每颗树的资讯。无法针对单一颗树作解释。
from sklearn.datasets import load_boston
ds = datasets.load_breast_cancer()
X=pd.DataFrame(ds.data, columns=ds.feature_names)
y=pd.DataFrame(ds.target, columns=['Cancer'])
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3)
from sklearn.ensemble import RandomForestClassifier as RFC
rfc = RFC(n_estimators=100, criterion='gini', max_depth=3, random_state=1)
超参数:
1. nestimators: 要种几棵树。默认 100。
2. criterion: 不纯度方法,'gini' & 'entropy'。默认 gini。
3. maxdepth: 树的分裂层数。若 None,则扩展节点至所有叶 minsamplessplit 样本。默认 None。
4. minsamplessplit: 分裂一个内部节点所需的最小样本数。默认 2。
rfc.fit(X_train, y_train)
rfc.score(X_test, y_test)
>> 0.9415204678362573
Boosting 是指能够将弱学习器转化爲强学习器的一系列算法。
概念类似 Bagging,不同的是,它会将前一次学习器「分类错误的资料」的权重提高,以训练下一次。
学习器会学习到上一次「错误分类资料」的特性,进而提升分类结果。
优点:一般来说可得到比 Bagging 更好的结果。
缺点:若原生资料集杂讯太多,易使模型放大对杂讯的判断,导致结果失准。
以红酒分类为例,:
from sklearn.datasets import load_wine
X, y = load_wine(return_X_y=True)
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
le = LabelEncoder()
y = le.fit_transform(y)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=1, stratify=y)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
tree = DecisionTreeClassifier(criterion='entropy', max_depth=1, random_state=1)
ada = AdaBoostClassifier(
base_estimator=tree,
n_estimators=500,
learning_rate=0.01,
random_state=1
)
超参数:
1. nestimators: 创建 n 个学习器。默认 50。
2. learningrate: 学习速率。默认 1.0。
接着比较一下 一般决策树 vs. Boosting 决策树
from sklearn.metrics import accuracy_score
tree.fit(X_train, y_train)
y_train_pred = tree.predict(X_train)
y_test_pred = tree.predict(X_test)
tree_train = accuracy_score(y_train, y_train_pred)
tree_test = accuracy_score(y_test, y_test_pred)
print(f'Decision tree train/test accuracies {tree_train:.3f}/{tree_test:.3f}')
ada.fit(X_train, y_train)
y_train_pred = ada.predict(X_train)
y_test_pred = ada.predict(X_test)
ada_train = accuracy_score(y_train, y_train_pred)
ada_test = accuracy_score(y_test, y_test_pred)
print(f'AdaBoost train/test accuracies {ada_train:.3f}/{ada_test:.3f}')
>> Decision tree train/test accuracies 0.916/0.875
AdaBoost train/test accuracies 0.968/0.917
把决策边界作图(代码在补充 3.):
其原理与 Ada 类似,差别在前者利用「分类错误资料」权重定位模型的不足,後者则是透过「梯度」。
原理可参考文章 1、文章 2 & 文章 3
最有名的莫过於是 XGBoost。
XGBoost 全名 eXtreme Gradient Boosting,是 Kaggle 竞赛中常见的演算法。
它保有 Gradient Boosting 的做法,使後生成树能修正前棵树的错误。
此外,如随机森林,生成每棵树时会随机抽取特徵,使每棵树的生成不会拿全部的特徵参与决策。
故可实现平行处理。并不是说可以平行处理多颗树,而是指它可平行处理特徵选取的计算。
可说是同时结合 Bagging 和 Boosting 的优点。
为抑制模型复杂化,XGboost 在目标函数添加了 Regularization。
模型在训练时为了拟合训练资料,会产生很多高次项的函数,但反而容易被杂讯干扰导致过度拟合。
因此 L1/L2 使损失函数更平滑,抗杂讯干扰能力更大。
最後 XGboost 用到了一 & 二阶导数来生成下一棵树。
其中 Gradient 就是所谓的一阶导数,而 Hessian 即为二阶导数。
优点:准确率高。支援平行处理。抗过拟合与抗杂讯能力强。
# 同样用上面的酒类分类
from sklearn.tree import DecisionTreeClassifier
from xgboost import XGBClassifier
tree = DecisionTreeClassifier(criterion='entropy', max_depth=1, random_state=1)
xgb = XGBClassifier(
n_estimators=500,
learning_rate=0.01,
random_state=1
)
超参数:
1. nestimators: 创建 n 个学习器。
2. maxdepth: 树的最大深度,(通常设计 3~10)。默认 6。
3. booster: gbtree 树模型(默认) / gbliner 线性模型。
4. learningrate: 学习速率,(通常设计 0.01~0.2)。默认 0.3。
*完整可看: https://www.twblogs.net/a/5db37e49bd9eee310ee694ee*
与前面 Baggin / Boosting 不同,Stacking 会有两种模型:
同样用上面的酒类分类:
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.tree import DecisionTreeClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import StackingClassifier
tree = DecisionTreeClassifier(criterion='entropy', max_depth=1, random_state=1)
knn_PL = make_pipeline(
StandardScaler(),
KNeighborsClassifier(n_neighbors=1, metric='minkowski')
)
esn = [('Decision Tree', tree), ('KNN', knn_PL)]
stk = StackingClassifier(
estimators=esn,
final_estimator=LogisticRegression()
)
*超参数:
from sklearn.metrics import accuracy_score
from sklearn.model_selection import cross_val_score
labels = ['Random Forest', 'SVC', 'Stacking']
all_clf = [rf, svc_PL, stk]
for clf, label in zip(all_clf, labels):
scores = cross_val_score(
clf, X_train, y_train,
cv=10,
scoring='roc_auc'
)
print(f"ROC AUC: {scores.mean():0.2f} (+/- {scores.std():0.2f}) [{label}]")
>> ROC AUC: 0.88 (+/- 0.09) [Decision Tree]
ROC AUC: 0.90 (+/- 0.11) [KNN]
ROC AUC: 0.98 (+/- 0.05) [Stacking]
把决策边界作图(代码在补充 4.):
sc = StandardScaler()
X_train_std = sc.fit_transform(X_train)
import numpy as np
from itertools import product
x_min, x_max = X_train_std[:, 0].min() - 1, X_train_std[:, 0].max() + 1
y_min, y_max = X_train_std[:, 1].min() - 1, X_train_std[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1)
)
f, axarr = plt.subplots(nrows=2, ncols=2,
sharex='col',
sharey='row',
figsize=(7, 5))
for idx, clf, tt in zip(product([0, 1], [0, 1]), all_clf, labels):
clf.fit(X_train_std, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx[0], idx[1]].contourf(xx, yy, Z, alpha=0.3)
axarr[idx[0], idx[1]].scatter(X_train_std[y_train==0, 0],
X_train_std[y_train==0, 1],
c='blue',
marker='^',
s=50)
axarr[idx[0], idx[1]].scatter(X_train_std[y_train==1, 0],
X_train_std[y_train==1, 1],
c='green',
marker='o',
s=50)
axarr[idx[0], idx[1]].set_title(tt)
plt.text(-3.5, -5.,
s='Sepal width [standardized]',
ha='center', va='center', fontsize=12)
plt.text(-12.5, 4.5,
s='Petal length [standardized]',
ha='center', va='center',
fontsize=12, rotation=90)
plt.show()
*补充 2. 袋装法 范例的决策边界图
import numpy as np
import matplotlib.pyplot as plt
x_min = X_train[:, 0].min() - 1
x_max = X_train[:, 0].max() + 1
y_min = X_train[:, 1].min() - 1
y_max = X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,
sharex='col',
sharey='row',
figsize=(8, 3))
for idx, clf, tt in zip([0, 1],
[tree, bag],
['Decision tree', 'Bagging']):
clf.fit(X_train, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
axarr[idx].scatter(X_train[y_train == 0, 0],
X_train[y_train == 0, 1],
c='blue', marker='^')
axarr[idx].scatter(X_train[y_train == 1, 0],
X_train[y_train == 1, 1],
c='green', marker='o')
axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.show()
*补充 3. 强化法 范例的决策边界图
import numpy as np
import matplotlib.pyplot as plt
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,
sharex='col',
sharey='row',
figsize=(8, 3))
for idx, clf, tt in zip([0, 1],
[tree, ada],
['Decision tree', 'AdaBoost']):
clf.fit(X_train, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
axarr[idx].scatter(X_train[y_train == 0, 0],
X_train[y_train == 0, 1],
c='blue', marker='^')
axarr[idx].scatter(X_train[y_train == 1, 0],
X_train[y_train == 1, 1],
c='green', marker='o')
axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.show()
*补充 4. 黏合法 范例的决策边界图
import numpy as np
import matplotlib.pyplot as plt
x_min, x_max = X_train[:, 0].min() - 1, X_train[:, 0].max() + 1
y_min, y_max = X_train[:, 1].min() - 1, X_train[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1),
np.arange(y_min, y_max, 0.1))
f, axarr = plt.subplots(nrows=1, ncols=2,
sharex='col',
sharey='row',
figsize=(8, 3))
for idx, clf, tt in zip([0, 1, 2],
[tree, stk],
['Decision tree', 'Stacking']):
clf.fit(X_train, y_train)
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
axarr[idx].contourf(xx, yy, Z, alpha=0.3)
axarr[idx].scatter(X_train[y_train == 0, 0],
X_train[y_train == 0, 1],
c='blue', marker='^')
axarr[idx].scatter(X_train[y_train == 1, 0],
X_train[y_train == 1, 1],
c='green', marker='o')
axarr[idx].set_title(tt)
axarr[0].set_ylabel('Alcohol', fontsize=12)
plt.tight_layout()
plt.show()
>>: 使用 802.1X 实施网路存取控制中,让请求者(supplicant)向身份验证者(authenticator)进行身份验证且具有最少的系统管理负担(overhead)的是PEAP协议
本篇介绍现行登入密码栏位,旁边都有一个小眼睛,是如何点一下就秀出密码的呢? ▼ 完成图如下 首先先...
前言 在学习 FP 的过程中,会看到 FP 常常被拿来跟 OOP 做比较,那 OOP 究竟是什麽呢?...
平常我们很少关注编译和链结的过程,因为开发环境都集成开发的环境,比如Visual Studio、Ec...
前言 在Object [上]中我们介绍了物件的宣告、型态、拷贝等等特性,接下来我们继续介绍物件中都有...
还有印象雷神索尔里面,管理着彩虹桥的海姆达尔吗~ 只有人从彩虹桥传送进来时,第一个面对的就是他。 在...