python机器学习融合模型:Stacking与Blending(附代码)_论文_模型竞赛_企业建模

大家好,今天给大家总结归纳了python机器学习融合模型:Stacking与Blending(附代码)。

1 堆叠法Stacking

一套弱系统能变成一个强系统吗?

图片


当你处在一个复杂的分类问题面前时,金融市场通常会出现这种情况,在搜索解决方案时可能会出现不同的方法。 虽然这些方法可以估计分类,但有时候它们都不比其他分类好。在这种情况下,合理的选择是将它们全部保留下来,然后通过整合这些部分来创建最终系统。 这种多样化的方法是最方便的做法之一:在几个系统之间划分决定,以避免把所有的鸡蛋放在一个篮子里。

一旦我对这种情况有了大量的估计,我怎样才能将N个子系统的决策结合起来?作为一个快速的答案,我可以做出平均决定并使用它。但是,是否有不同的方式充分利用我的子系统?当然有!

创造性思考!
几个具有共同目标的分类器称为多分类器。在机器学习中,多分类器是一组不同的分类器,它们进行估算并融合在一起,得到一个结合它们的结果。许多术语用于指多分类器:多模型,多分类器系统,组合分类器,决策委员会等。它们可以分为两大类:

集成方法:指使用相同的学习技术组合成一组系统来创建新系统。套袋和提升是最延伸的。 混合方法:采用一组不同的学习者并使用新的学习技术进行组合。堆叠(或堆叠泛化)是主要的混合多分类器之一。

如何构建一个由 Stacking 驱动的多分类器。

图片

图片

stacking工作流

图片

.

元分类器可以在预测的类标签上训练,也可以在预测的类概率训练。

图片

图片

举个stacking预测欧元兑美元趋势例子

想象一下,我想估算一下EURUSD的走势(欧元兑美元趋势)。首先,我把我的问题变成了一个分类问题,所以我把价格数据分成两种类型(或类):向上和向下移动。猜测每天的每一个动作并不是我的本意。我只想检测主要趋势:向上交易多头(类 = 1)和向下交易空头(类 = 0)。

图片

我已经完成了后验分割;我的意思是所有历史数据都被用来决定类别,所以它考虑了一些未来的信息。因此,我目前无法确保 iup 或 down 运动。因此,需要对今天的课程进行估算。

图片

为了这个例子的目的,我设计了三个独立的系统。他们是三个不同的学习者,使用不同的属性集。无论您使用相同的学习器算法还是它们共享某些/所有属性都没有关系;关键是它们必须足够不同以保证多样化。

图片

然后,他们根据这些概率进行交易:如果 E 高于 50%,则意味着做多,E 越大。 如果 E 低于 50%,则为空头入场,E 越小。

图片

结果不理想,仅仅比随机好

图片

系统误差相关性也较低

图片

一组较弱选手可以组成梦之队吗? 构建多分类器的目的是获得比任何单个分类器都能获得的更好的预测性能。让我们看看是否是这种情况。

我将在本例中使用的方法基于Stacking算法。 Stacking的思想是,称为级别0模型的主分类器的输出将被用作称为元模型的另一分类器的属性以近似相同的分类问题。元模型留下来找出合并机制。它将负责连接0级模型的回复和真实分类。

严格的过程包括将训练集分成不相交的集合。然后训练每个级别0的学习者关于整个数据,排除一组,并将其应用于排除组。通过对每组重复,为每个学习者获得每个数据的估计。这些估计值将成为训练元模型或1级模型的属性。由于我的数据是一个时间序列,因此我决定使用第1天到第d-1天的集合来构建第d天的估计。

图片

这与哪种模式配合使用? 元模型可以是分类树,随机森林,支持向量机......任何分类学习者都是有效的。 对于这个例子,我选择了使用最近邻居算法。 这意味着元模型将估计新数据的类别,以发现过去数据中0级分类的类似配置,然后将分配这些类似情况的类别。

让我们看看我的梦之队的成绩是多么的好......

stacking模型的平均误差值是最低的

图片

结论 这只是大量可用多分类器的一个例子。 他们不仅可以帮助您通过现代和独创的技术将您的部分解决方案融入到独特的答案中,而且可以创建一个真正的梦幻团队。 单个组件被融合到一个系统中的方式也有一个重要的改进余地。

所以,下次你需要结合时,花更多的时间来研究可能性。 通过习惯的力量避免传统的平均水平,并探索更复杂的方法。 他们可能会为你带来额外的表现

模型融合在kaggle竞赛应用

模型融合是一种非常强大的技术,可以提高各种 ML 任务的准确性。在本文中,我将分享我在 Kaggle 比赛中的集成方法。

对于第一部分,我们着眼于从提交文件创建集成。第二部分将着眼于通过堆叠泛化/混合创建集成。

我回答为什么集成会减少泛化错误。最后,我展示了不同的集成方法,以及它们的结果和代码,供您自己尝试。Kaggle Ensembling Guide我回答为什么集成会减少泛化错误。最后,我展示了不同的集成方法,以及它们的结果和代码,供您自己尝试。

stacked 产生方法是一种截然不同的组合多个模型的方法,它讲的是组合学习器的概念,但是使用的相对于bagging和boosting较少,它不像bagging和boosting,而是组合不同的模型,具体的过程如下:
1.划分训练数据集为两个不相交的集合。
2. 在第一个集合上训练多个学习器。
3. 在第二个集合上测试这几个学习器
4. 把第三步得到的预测结果作为输入,把正确的回应作为输出,训练一个高层学习器,
这里需要注意的是1-3步的效果与cross-validation,我们不是用赢家通吃,而是使用非线性组合学习器的方法

图片

将训练好的所有基模型对整个训练集进行预测,第j个基模型对第i个训练样本的预测值将作为新的训练集中第i个样本的第j个特征值,最后基于新的训练集进行训练。同理,预测的过程也要先经过所有基模型的预测形成新的测试集,最后再对测试集进行预测:

下面我们介绍一款功能强大的stacking利器,mlxtend库,它可以很快地完成对sklearn模型地stacking。

StackingClassifier 使用API及参数解析:

StackingClassifier(classifiers, meta_classifier, use_probas=False,  average_probas=False, verbose=0, use_features_in_secondary=False)

参数:

classifiers : 基分类器,数组形式,[cl1, cl2, cl3]. 每个基分类器的属性被存储在类属性 self.clfs_.
meta_classifier : 目标分类器,即将前面分类器合起来的分类器
use_probas : bool (default: False) ,如果设置为True, 那么目标分类器的输入就是前面分类输出的类别概率值而不是类别标签
average_probas : bool (default: False),用来设置上一个参数当使用概率值输出的时候是否使用平均值。
verbose  : int, optional (default=0)。用来控制使用过程中的日志输出,当 verbose = 0时,什么也不输出,   verbose = 1,输出回归器的序号和名字。verbose = 2,输出详细的参数信息。verbose > 2,   自动将verbose设置为小于2的,verbose -2.
use_features_in_secondary : bool (default: False). 如果设置为True,那么最终的目标分类器就被基分类器产生的数据和最初的数据集同时训练。如果设置为False,最终的分类器只会使用基分类器产生的数据训练。

属性:
clfs_ : 每个基分类器的属性,list, shape 为 [n_classifiers]。
meta_clf_ : 最终目标分类器的属性

方法:

fit(X, y)
fit_transform(X, y=None, fit_params)
get_params(deep=True),如果是使用sklearn的GridSearch方法,那么返回分类器的各项参数。
predict(X)
predict_proba(X)
score(X, y, sample_weight=None), 对于给定数据集和给定label,返回评价accuracy
set_params(params),设置分类器的参数,params的设置方法和sklearn的格式一样 

python融合模型部分实战代码

 
  1. from sklearn.datasets import load_iris

  2. from mlxtend.classifier import StackingClassifier

  3. from mlxtend.feature_selection import ColumnSelector

  4. from sklearn.pipeline import make_pipeline

  5. from sklearn.linear_model import LogisticRegression

  6. pipe1 = make_pipeline(ColumnSelector(cols=(0, 2)),

  7. LogisticRegression())

  8. pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)),

  9. LogisticRegression())

  10. sclf = StackingClassifier(classifiers=[pipe1, pipe2],

  11. meta_classifier=LogisticRegression())

1.1 堆叠法的基本思想

堆叠法Stacking是近年来模型融合领域最为热门的方法,它不仅是竞赛冠军队最常采用的融合方法之一,也是工业中实际落地人工智能时会考虑的方案之一。作为强学习器的融合方法,Stacking集模型效果好、可解释性强、适用复杂数据三大优点于一身,属于融合领域最为实用的先驱方法。在Stacking的众多应用当中,CTR(广告点击率预测)中实用的GBDT+LR堆叠尤为著名。因此在《2022机器学习实战》正课当中,讲解完毕通用的stacking手段之后,我会给大家详细讲解GBDT+LR在CTR中的用法,并完成一个CTR实战。

Stacking究竟是怎样一种算法呢?它的核心思想其实非常简单——首先,如下图所示,Stacking结构中有两层算法串联,第一层叫做level 0,第二层叫做level 1,level 0里面可能包含1个或多个强学习器,而level 1只能包含一个学习器。在训练中,数据会先被输入level 0进行训练,训练完毕后,level 0中的每个算法会输出相应的预测结果。我们将这些预测结果拼凑成新特征矩阵,再输入level 1的算法进行训练。融合模型最终输出的预测结果就是level 1的学习器输出的结果。

image

在这个过程中,level 0输出的预测结果一般如下排布:

学习器1学习器2...学习器n
样本1xxxxxx...xxx
样本2xxxxxx...xxx
样本3xxxxxx...xxx
...............
样本mxxxxxx...xxx

第一列就是学习器1在全部样本上输出的结果,第二列就是学习器2在全部样本上输出的结果,以此类推。
同时,level 0上训练的多个强学习器被称为基学习器(base-model),也叫做个体学习器。在level1上训练的学习器叫元学习器(meta-model)。根据行业惯例,level 0上的学习器是复杂度高、学习能力强的学习器,例如集成算法、支持向量机,而level 1上的学习器是可解释性强、较为简单的学习器,如决策树、线性回归、逻辑回归等。有这样的要求是因为level 0上的算法们的职责是找出原始数据与标签的关系、即建立原始数据与标签之间的假设,因此需要强大的学习能力。但level 1上的算法的职责是融合个体学习器做出的假设、并最终输出融合模型的结果,相当于在寻找“最佳融合规则”,而非直接建立原始数据与标签之间的假设。

说到这里,不知道你是否有注意到,Stacking的本质是让算法找出融合规则。虽然大部分人可能从未接触过类似于Stacking算法的串联结构,但事实上Stacking的流程与投票法、均值法完全一致:

image

在投票法中,我们用投票方式融合强学习器的结果,在均值法中,我们用求均值方式融合强学习器的结果,在Stacking堆叠法中,我们用算法融合强学习器的结果。当level 1上的算法是线性回归时,其实我们就是在求解所有强学习器结果的加权求和,而训练线性回归的过程,就是找加权求和的权重的过程。同样的,当level 1上的算法是逻辑回归的时候,其实我们就是在求解所有强学习器结果的加权求和,再在求和基础上套上sigmoid函数。训练逻辑回归的过程,也就是找加权求和的权重的过程。其他任意简单的算法同理。

虽然对大多数算法来说,我们难以找出类似“加权求和”这样一目了然的名字来概括算法找出的融合规则,但本质上,level 1的算法只是在学习如何将level 0上输出的结果更好地结合起来,所以Stacking是通过训练学习器来融合学习器结果的方法均值法是将输出结果平均,投票法是将输出结果投票,前面这两种都是人为定义融合方法,但是这个Stacking是让机器帮我们找到一个最佳的融合方法。 这一方法的根本优势在于,我们可以让level 1上的元学习器向着损失函数最小化的方向训练,而其他融合方法只能保证融合后的结果有一定的提升。因此Stacking是比Voting和Averaging更有效的方法。在实际应用时,Stacking也常常表现出胜过投票或均值法的结果。
当我们了解了Stacking的本质之后,很多实现过程中的细节问题就迎刃而解了,比如:

  • 要不要对融合的算法进行精密的调参?

个体学习器粗调,元学习器精调,如果不过拟合的话,可以两类学习器都精调。理论上来说,算法输出结果越接近真实标签越好,但个体学习器精调后再融合,很容易过拟合。

  • 个体学习器算法要怎样选择才能最大化stacking的效果?

与投票、平均的状况一致,控制过拟合、增加多样性、注意算法整体的运算时间。

  • 个体学习器可以是逻辑回归、决策树这种复杂度较低的算法吗?元学习器可以是xgboost这种复杂度很高的算法吗?

都可以,一切以模型效果为准。对level 0而言,当增加弱学习器来增加模型多样性、且弱学习器的效果比较好时,可以保留这些算法。对level 1而言,只要不过拟合,可以使用任何算法。个人推荐,在分类的时候可以使用复杂度较高的算法,对回归最好还是使用简单的算法。

  • level 0和level 1的算法可不可以使用不同的损失函数?

可以,因为不同的损失函数衡量的其实是类似的差异:即真实值与预测值之间的差异。不过不同的损失对于差异的敏感性不同,如果可能的话建议使用相似的损失函数。

  • level 0和level 1的算法可不可以使用不同的评估指标?

个人建议level 0与level 1上的算法必须使用相同的模型评估指标。虽然Stacking中串联了两组算法,但这两组算法的训练却是完全分离的。在深度学习当中,我们也有类似的强大算法串联弱小算法的结构,例如,卷积神经网络就是由强大的卷积层与弱小的线性层串联,卷积层的主要职责是找出特征与标签之间的假设,而线性层的主要职责是整合假设、进行输出。但在深度学习中,一个网络上所有层的训练是同时进行的,每次降低损失函数时需要更新整个网络上的权重。但在Stacking当中,level 1上的算法在调整权重时,完全不影响level 0的结果,因此为了保证两组算法最终融合后能够得到我们想要的结果,在训练时一定要以唯一评估指标为基准进行训练。

2 在sklearn中实现stacking

class sklearn.ensemble.StackingClassifier(
estimators,
final_estimator=None, *,
cv=None,
stack_method="auto",
n_jobs=None,
passthrough=False,
verbose=0)

class sklearn.ensemble.StackingRegressor(
estimators,
final_estimator=None,*,
cv=None,
n_jobs=None,
passthrough=False,
verbose=0)

参数说明
estimators个体评估器的列表。在sklearn中,只使用单一评估器作为个体评估器时,
模型可以运行,但效果往往不太好。
final_estimator元学习器,只能有一个评估器。当融合模型执行分类任务时,元学习器一定是分类算法,
当融合模型执行回归任务时,元学习器一定是回归算法。
cv用于指定交叉验证的具体类型、折数等细节。
可以执行简单的K折交叉验证,也可以输入sklearn中交叉验证类。
stack_method只有分类器才有的参数,表示个体学习器输出的具体测试结果。
passthrough在训练元学习器时,是否加入原始数据作为特征矩阵。
n_jobs, verbose线程数与监控参数。

在sklearn当中,只要输入estimatorsfinal_estimator,就可以执行stacking了。我们可以沿用在投票法中使用过的个体学习器组合,并使用随机森林作为元学习器来完成stacking:

  • 工具库 & 数据
 
  1. import matplotlib.pyplot as plt

  2. from sklearn.model_selection import KFold, cross_validate

  3. from sklearn.datasets import load_digits #分类 - 手写数字数据集

  4. from sklearn.datasets import load_iris

  5. from sklearn.datasets import load_boston

  6. from sklearn.model_selection import train_test_split

  7. from sklearn.neighbors import KNeighborsClassifier as KNNC

  8. from sklearn.neighbors import KNeighborsRegressor as KNNR

  9. from sklearn.tree import DecisionTreeRegressor as DTR

  10. from sklearn.tree import DecisionTreeClassifier as DTC

  11. from sklearn.linear_model import LinearRegression as LR

  12. from sklearn.linear_model import LogisticRegression as LogiR

  13. from sklearn.ensemble import RandomForestRegressor as RFR

  14. from sklearn.ensemble import RandomForestClassifier as RFC

  15. from sklearn.ensemble import GradientBoostingRegressor as GBR

  16. from sklearn.ensemble import GradientBoostingClassifier as GBC

  17. from sklearn.naive_bayes import GaussianNB

  18. from sklearn.ensemble import StackingClassifier

 
  1. Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.2,random_state=1412)

image

  • 定义交叉验证函数
 
  1. def fusion_estimators(clf):

  2. 对融合模型做交叉验证,对融合模型的表现进行评估

  3. cv = KFold(n_splits=5,shuffle=True,random_state=1412)

  4. results = cross_validate(clf,Xtrain,Ytrain

  5. ,cv = cv

  6. ,scoring = "accuracy"

  7. ,n_jobs = -1

  8. ,return_train_score = True

  9. ,verbose=False)

  10. test = clf.fit(Xtrain,Ytrain).score(Xtest,Ytest)

  11. print("train_score:{}".format(results["train_score"].mean())

  12. cv_mean:{}".format(results["test_score"].mean())

  13. test_score:{}".format(test)

 
  1. def individual_estimators(estimators):

  2. 对模型融合中每个评估器做交叉验证,对单一评估器的表现进行评估

  3. for estimator in estimators:

  4. cv = KFold(n_splits=5,shuffle=True,random_state=1412)

  5. results = cross_validate(estimator[1],Xtrain,Ytrain

  6. ,cv = cv

  7. ,scoring = "accuracy"

  8. ,n_jobs = -1

  9. ,return_train_score = True

  10. ,verbose=False)

  11. test = estimator[1].fit(Xtrain,Ytrain).score(Xtest,Ytest)

  12. print(estimator[0]

  13. train_score:{}".format(results["train_score"].mean())

  14. cv_mean:{}".format(results["test_score"].mean())

  15. test_score:{}".format(test)

  • 个体学习器与元学习器的定义

我们之前在讲解Voting投票法的时候已经对如何定义个体学习器做出了详细的解释,也做了很多努力找出下面的7个模型。在这里,我们就沿用Voting当中选出的7个模型:

 
  1. clf1 = LogiR(max_iter = 3000, C=0.1, random_state=1412,n_jobs=8)

  2. clf2 = RFC(n_estimators= 100,max_features="sqrt",max_samples=0.9, random_state=1412,n_jobs=8)

  3. clf3 = GBC(n_estimators= 100,max_features=16,random_state=1412)

  4. clf4 = DTC(max_depth=8,random_state=1412)

  5. clf5 = KNNC(n_neighbors=10,n_jobs=8)

  6. clf7 = RFC(n_estimators= 100,max_features="sqrt",max_samples=0.9, random_state=4869,n_jobs=8)

  7. clf8 = GBC(n_estimators= 100,max_features=16,random_state=4869)

  8. estimators = [("Logistic Regression",clf1), ("RandomForest", clf2)

  9. , ("GBDT",clf3), ("Decision Tree", clf4), ("KNN",clf5)

  10. #, ("Bayes",clf6)

  11. , ("RandomForest2", clf7), ("GBDT2", clf8)

  • 导入sklearn进行建模
 
  1. final_estimator = RFC(n_estimators=100

  2. , min_impurity_decrease=0.0025

  3. , random_state= 420, n_jobs=8)

  4. clf = StackingClassifier(estimators=estimators #level0的7个体学习器

  5. ,final_estimator=final_estimator #level 1的元学习器

  6. ,n_jobs=8)

没有调过拟合之前:也就是没有加min_impurity_decrease=0.0025

 
  1. fusion_estimators(clf) #没有过拟合限制

  2. cv_mean:0.9812112853271389

  3. test_score:0.9861111111111112

加上过拟合之后

 
  1. fusion_estimators(clf) #精调过拟合

  2. cv_mean:0.9812185443283005

  3. test_score:0.9888888888888889

benchmark投票法堆叠法
5折交叉验证0.96660.98330.9812(↓)
测试集结果0.95270.98890.9889(-)

可以看到,stacking在测试集上的分数与投票法Voting持平,但在5折交叉验证分数上却没有投票法高。这可能是由于现在我们训练的数据较为简单,但数据学习难度较大时,stacking的优势就会慢慢显现出来。当然,我们现在使用的元学习器几乎是默认参数,我们可以针对元学习器使用贝叶斯优化进行精妙的调参,然后再进行对比,堆叠法的效果可能超越投票法。

3 元学习器的特征矩阵

3.1 元学习器特征矩阵的2个问题

在Stacking过程中,个体学习器会原始数据上训练、预测,再把预测结果排布成新特征矩阵,放入元学习器进行学习。其中,个体学习器的预测结果、即元学习器需要训练的矩阵一般如下排布:

学习器1学习器2...学习器n
样本1xxxxxx...xxx
样本2xxxxxx...xxx
样本3xxxxxx...xxx
...............
样本mxxxxxx...xxx

根据我们对机器学习以及模型融合的理解,不难发现以下两个问题:

  • 首先,元学习器的特征矩阵中的特征一定很少

1个个体学习器只能输出1组预测结果,我们对这些预测结果进行排列,新特征矩阵中的特征数就等于个体学习器的个数。一般融合模型中个体学习器最多有20-30个,也就是说元学习器的特征矩阵中最多也就20-30个特征。这个特征量对于工业、竞赛中的机器学习算法来说是远远不够的。

  • 其次,元学习器的特征矩阵中样本量也不太多

个体学习器的职责是找到原始数据与标签之间的假设,为了验证这个假设是否准确,我们需要查看的是个体学习器的泛化能力。只有当个体学习器的泛化能力较强时,我们才能安心的将个体学习器输出的预测结果放入元学习器中进行融合。


然而。在我们训练stacking模型时,我们一定是将原始数据集分为训练集、验证集和测试集三部分——


其中测试集是用于检测整个融合模型的效果的,因此在训练过程中不能使用。


训练集用于训练个体学习器,属于已经完全透露给个体学习器的内容,如果在训练集上进行预测,那预测结果是“偏高”的、无法代表个体学习器的泛化能力。


因此最后剩下能够用来预测、还能代表个体学习器真实学习水平的,就只剩下很小的验证集了。一般验证集最多只占整个数据集的30%-40%,这意味着元学习器所使用的特征矩阵里的样本量最多也就是原始数据的40%。
无怪在行业惯例当中,元学习器需要是一个复杂度较低的算法,因为元学习器的特征矩阵在特征量、样本量上都远远小于工业机器学习所要求的标准。为了解决这两个问题,在Stacking方法当中存在多种解决方案,而这些解决方案可以通过sklearn中的stacking类实现。

class sklearn.ensemble.StackingClassifier(estimators, final_estimator=None, *, cv=None, stack_method="auto", n_jobs=None, passthrough=False, verbose=0)

class sklearn.ensemble.StackingRegressor(estimators, final_estimator=None, *, cv=None, n_jobs=None, passthrough=False, verbose=0)

参数说明
estimators个体评估器的列表。在sklearn中,只使用单一评估器作为个体评估器时,
模型可以运行,但效果往往不太好。
final_estimator元学习器,只能有一个评估器。当融合模型执行分类任务时,元学习器一定是分类算法,
当融合模型执行回归任务时,元学习器一定是回归算法。
cv用于指定交叉验证的具体类型、折数等细节。
可以执行简单的K折交叉验证,也可以输入sklearn中交叉验证类。
stack_method只有分类器才有的参数,表示个体学习器输出的具体测试结果。
passthrough在训练元学习器时,是否加入原始数据作为特征矩阵。
n_jobs, verbose线程数与监控参数。
3.2 样本量太少的解决方案:交叉验证
  • 参数cv,在stacking中执行交叉验证
    在stacking方法被提出的原始论文当中,原作者自然也意识到了元学习器的特征矩阵样本量太少这个问题,因此提出了在stacking流程内部使用交叉验证来扩充元学习器特征矩阵的想法,即在内部对每个个体学习器做交叉验证,但并不用这个交叉验证的结果来验证泛化能力,而是直接把交叉验证当成了生产数据的工具。

具体的来看,在stacking过程中,我们是这样执行交叉验证的——

对任意个体学习器来说,假设我们执行5折交叉验证,我们会将训练数据分成5份,并按照4份训练、1份验证的方式总共建立5个模型,训练5次:
 

image


在交叉验证过程中,每次验证集中的数据都是没有被放入模型进行训练的,因此这些验证集上的预测结果都可以衡量模型的泛化能力。

一般来说,交叉验证的最终输出是5个验证集上的分数,但计算分数之前我们一定是在5个验证集上分别进行预测,并输出了结果。所以我们可以在交叉验证中建立5个模型,轮流得到5个模型输出的预测结果,而这5个预测结果刚好对应全数据集中分割的5个子集。这是说,我们完成交叉验证的同时,也对原始数据中全部的数据完成了预测。现在,只要将5个子集的预测结果纵向堆叠,就可以得到一个和原始数据中的样本一一对应的预测结果。这种纵向堆叠正像我们在海滩上堆石子(stacking)一样,这也是“堆叠法”这个名字的由来。
 

image


用这样的方法来进行预测,可以让任意个体学习器输出的预测值数量 = 样本量,如此,元学习器的特征矩阵的行数也就等于原始数据的样本量了:

学习器1学习器2...学习器n
样本1xxxxxx...xxx
样本2xxxxxx...xxx
样本3xxxxxx...xxx
...............
样本mxxxxxx...xxx

在stacking过程中,这个交叉验证流程是一定会发生的,不属于我们可以人为干涉的范畴。不过,我们可以使用参数cv来决定具体要使用怎样的交叉验证,包括具体使用几折验证,是否考虑分类标签的分布等等。具体来说,参数cv中可以输入:

输入None,默认使用5折交叉验证


输入sklearn中任意交叉验证对象


输入任意整数,表示在Stratified K折验证中的折数。Stratified K折验证是会考虑标签中每个类别占比的交叉验证,如果选择Stratified K折交叉验证,那每次训练时交叉验证会保证原始标签中的类别比例 = 训练标签的类别比例 = 验证标签的类别比例
 

image


现在你知道Stacking是如何处理元学习器的特征矩阵样本太少的问题了。需要再次强调的是,内部交叉验证的并不是在验证泛化能力,而是一个生产数据的工具,因此交叉验证本身没有太多可以调整的地方。唯一值得一提的是,当交叉验证的折数较大时,模型的抗体过拟合能力会上升、同时学习能力会略有下降。当交叉验证的折数很小时,模型更容易过拟合。但如果数据量足够大,那使用过多的交叉验证折数并不会带来好处,反而只会让训练时间增加而已:

 
  1. estimators = [("Logistic Regression",clf1), ("RandomForest", clf2)

  2. , ("GBDT",clf3), ("Decision Tree", clf4), ("KNN",clf5)

  3. #, ("Bayes",clf6)

  4. , ("RandomForest2", clf7), ("GBDT2", clf8)

  5. final_estimator = RFC(n_estimators=100

  6. , min_impurity_decrease=0.0025

  7. , random_state= 420, n_jobs=8)

 
  1. clf = StackingClassifier(estimators=estimators

  2. ,final_estimator=final_estimator

  3. , cv = cv

  4. , n_jobs=8)

  5. clf.fit(Xtrain,Ytrain)

  6. print((time.time() - start)) #消耗时间

  7. print(clf.score(Xtrain,Ytrain)) #训练集上的结果

  8. print(clf.score(Xtest,Ytest)) #测试集上的结果

 

可以看到,随着cv中折数的上升,训练时间一定会上升,但是模型的表现却不一定。因此,选择5~10折交叉验证即可。同时,由于stacking当中自带交叉验证,又有元学习器这个算法,因此堆叠法的运行速度是比投票法、均值法缓慢很多的,这是stacking堆叠法不太人性化的地方。

3.3 特征太少的解决方案
  • 参数stack_method,更换个体学习器输出的结果类型

对于分类stacking来说,如果特征量太少,我们可以更换个体学习器输出的结果类型。具体来说,如果个体学习器输出的是具体类别(如[0,1,2]),那1个个体学习器的确只能输出一列预测结果。但如果把输出的结果类型更换成概率值、置信度等内容,输出结果的结构一下就可以从一列拓展到多列。

如果这个行为由参数stack_method控制,这是只有StackingClassifier才拥有的参数,它控制个体分类器具体的输出。stack_method里面可以输入四种字符串:"auto", "predict_proba", "decision_function", "predict",除了"auto"之外其他三个都是sklearn常见的接口。

 
  1. clf = LogiR(max_iter=3000, random_state=1412)

  2. clf = clf.fit(Xtrain,Ytrain)

 
  1. clf.predict_proba(Xtrain)

image

 
  1. #decision_function:每个样本点到分类超平面的距离,可以衡量置信度

  2. #对于无法输出概率的算法,如SVM,我们通常使用decision_function来输出置信度

  3. clf.decision_function(Xtrain)

image

 

image


对参数stack_method有:

输入"auto",sklearn会在每个个体学习器上按照"predict_proba", "decision_function", "predict"的顺序,分别尝试学习器可以使用哪个接口进行输出。即,如果一个算法可以使用predict_proba接口,那就不再尝试后面两个接口,如果无法使用predict_proba,就尝试能否使用decision_function。


输入三大接口中的任意一个接口名,则默认全部个体学习器都按照这一接口进行输出。然而,如果遇见某个算法无法按照选定的接口进行输出,stacking就会报错。

因此,我们一般都默认让stack_method保持为"auto"。从上面的我们在逻辑回归上尝试的三个接口结果来看,很明显,当我们把输出的结果类型更换成概率值、置信度等内容,输出结果的结构一下就可以从一列拓展到多列。

  • predict_proba

对二分类,输出样本的真实标签1的概率,一列

对n分类,输出样本的真实标签为[0,1,2,3...n]的概率,一共n列

  • decision_function

对二分类,输出样本的真实标签为1的置信度,一列

对n分类,输出样本的真实标签为[0,1,2,3...n]的置信度,一共n列

  • predict

对任意分类形式,输出算法在样本上的预测标签,一列

在实践当中,我们会发现输出概率/置信度的效果比直接输出预测标签的效果好很多,既可以向元学习器提供更多的特征、还可以向元学习器提供个体学习器的置信度。我们在投票法中发现使用概率的“软投票”比使用标签类被的“硬投票”更有效,也是因为考虑了置信度。

  • 参数passthrough,将原始特征矩阵加入新特征矩阵

对于分类算法,我们可以使用stack_method,但是对于回归类算法,我们没有这么多可以选择的接口。回归类算法的输出永远就只有一列连续值,因而我们可以考虑将原始特征矩阵加入个体学习器的预测值,构成新特征矩阵。这样的话,元学习器所使用的特征也不会过于少了。当然,这个操作有较高的过拟合风险,因此当特征过于少、且stacking算法的效果的确不太好的时候,我们才会考虑这个方案。

控制是否将原始数据加入特征矩阵的参数是passthrough,我们可以在该参数中输入布尔值。当设置为False时,表示不将原始特征矩阵加入个体学习器的预测值,设置为True时,则将原始特征矩阵加入个体学习器的预测值、构成大特征矩阵。

  • 接口transform与属性stack_method_
 
  1. estimators = [("Logistic Regression",clf1), ("RandomForest", clf2)

  2. , ("GBDT",clf3), ("Decision Tree", clf4), ("KNN",clf5)

  3. #, ("Bayes",clf6)

  4. , ("RandomForest2", clf7), ("GBDT2", clf8)

 
  1. final_estimator = RFC(n_estimators=100

  2. , min_impurity_decrease=0.0025

  3. , random_state= 420, n_jobs=8)

  4. clf = StackingClassifier(estimators=estimators

  5. ,final_estimator=final_estimator

  6. ,stack_method = "auto"

  7. ,n_jobs=8)

clf = clf.fit(Xtrain,Ytrain)

当我们训练完毕stacking算法后,可以使用接口transform来查看当前元学习器所使用的训练特征矩阵的结构

 
  1. clf.transform(Xtrain).shape

image


这个70 代表这个一共有7个个体学习器,每个个体学习器都有10个概率输出
如之前所说,这个特征矩阵的行数就等于训练的样本量:

 

不过你能判断为什么这里有70列吗?因为我们有7个个体学习器,而现在数据是10分类的数据,因此每个个体学习器都输出了类别[0,1,2,3,4,5,6,7,8,9]所对应的概率,因此总共产出了70列数据:

pd.DataFrame(clf.transform(Xtrain)).head()

image


如果加入参数passthrough,特征矩阵的特征量会变得更大:

 
  1. clf = StackingClassifier(estimators=estimators

  2. ,final_estimator=final_estimator

  3. ,stack_method = "auto"

  4. ,passthrough = True

  5. ,n_jobs=8)

clf = clf.fit(Xtrain,Ytrain)
 
  1. clf.transform(Xtrain).shape #这里就等于70 + 原始特征矩阵的特征数量64

image


使用属性stack_method_,我们可以查看现在每个个体学习器都使用了什么接口做为预测输出:

clf.stack_method_

["predict_proba",
"predict_proba",
"predict_proba",
"predict_proba",
"predict_proba",
"predict_proba",
"predict_proba"]

不难发现,7个个体学习器都使用了predict_proba的概率接口进行输出,这与我们选择的算法都是可以输出概率的算法有很大的关系

4 Stacking融合的训练/测试流程

现在我们已经知道了stacking算法中所有关于训练的信息,我们可以梳理出如下训练流程:

  • stacking的训练
  1. 将数据分割为训练集、测试集,其中训练集上的样本为(M_{train}),测试集上的样本量为(M_{test})
     
  2. 将训练集输入level 0的个体学习器,分别在每个个体学习器上进行交叉验证。在每个个体学习器上,将所有交叉验证的验证结果纵向堆叠形成预测结果。假设预测结果为概率值,当融合模型执行回归或二分类任务时,该预测结果的结构为((M_{train},1)),当融合模型执行K分类任务时(K>2),该预测结果的结构为((M_{train},K))
     
  3. 将所有个体学习器的预测结果横向拼接,形成新特征矩阵。假设共有N个个体学习器,则新特征矩阵的结构为((M_{train}, N))。如果是输出多分类的概率,那最终得出的新特征矩阵的结构为((M_{train}, N*K))
     
  4. 将新特征矩阵放入元学习器进行训练。

image

不难发现,虽然训练的流程看起来比较流畅,但是测试却不知道从何做起,因为:

  • 最终输出预测结果的是元学习器,因此直觉上来说测试数据集或许应该被输入到元学习器当中。然而,元学习器是使用新特征矩阵进行预测的,新特征矩阵的结构与规律都与原始数据不同,所以元学习器根本不可能接受从原始数据中分割出来的测试数据。因此正确的做法应该是让测试集输入level 0的个体学习器。

  • 然而,这又存在问题了:level 0的个体学习器们在训练过程中做的是交叉验证,而交叉验证只会输出验证结果,不会留下被训练的模型。因此在level 0中没有可以用于预测的、已经训练完毕的模型。

为了解决这个矛盾在我们的训练流程中,存在着隐藏的步骤:

  • stacking的训练
  1. 将数据分割为训练集、测试集,其中训练集上的样本为(M_{train}),测试集上的样本量为(M_{test})
     
  2. 将训练集输入level 0的个体学习器,分别在每个个体学习器上进行交叉验证。在每个个体学习器上,将所有交叉验证的验证结果纵向堆叠形成预测结果。假设预测结果为概率值,当融合模型执行回归或二分类任务时,该预测结果的结构为((M_{train},1)),当融合模型执行K分类任务时(K>2),该预测结果的结构为((M_{train},K))
     
  3. 隐藏步骤:使用全部训练数据对所有个体学习器进行训练,为测试做好准备。
     
  4. 将所有个体学习器的预测结果横向拼接,形成新特征矩阵。假设共有N个个体学习器,则新特征矩阵的结构为((M_{train}, N)).
     
  5. 将新特征矩阵放入元学习器进行训练。
  • stacking的测试
  1. 将测试集输入level0的个体学习器,分别在每个个体学习器上预测出相应结果。假设测试结果为概率值,当融合模型执行回归或二分类任务时,该测试结果的结构为((M_{test},1)),当融合模型执行K分类任务时(K>2),该测试结果的结构为((M_{test},K))
     
  2. 将所有个体学习器的预测结果横向拼接为新特征矩阵。假设共有N个个体学习器,则新特征矩阵的结构为((M_{test}, N)).
     
  3. 将新特征矩阵放入元学习器进行预测。

因此在stacking中,不仅要对个体学习器完成全部交叉验证,还需要在交叉验证结束后,重新使用训练数据来训练所有的模型。无怪Stacking融合的复杂度较高、并且运行缓慢了。

到现在,我们已经讲解完毕投票法和堆叠法了。在sklearn中,我们讲解了下面4个类:

融合方法
投票法ensemble.VotingClassifier
平均法ensemble.VotingRegressor
堆叠法分类ensemble.StackingClassifier
堆叠法回归ensemble.StackingRegressor

虽然这些类是模型融合方法,但我们可以像使用任意单一算法类一样任意地使用这些方法——我们可以很轻松地对这些类执行手动调参、交叉验证、网格搜索、贝叶斯优化、管道打包等操作,而无需担心代码的兼容问题。但需要注意的是,sklearn中的融合工具只支持sklearn中的评估器,不支持xgb、lgbm的原生代码。因此,如果我们想要对原生代码下的模型进行融合,必须自己手写融合过程。

二 改进后的堆叠法:Blending

1 Blending的基本思想与流程

Blending融合是在Stacking融合的基础上改进过后的算法。在之前的课程中我们提到,堆叠法stacking在level1上使用算法,这可以令融合本身向着损失函数最小化的方向进行,同时stacking使用自带的内部交叉验证来生成数据,可以深度使用训练数据,让模型整体的效果更好。但在这些操作的背后,存在两个巨大的问题:

  • stacking融合需要巨大的计算量,需要的时间和算力成本较高,以及

  • stacking融合在数据和算法上都过于复杂,因此融合模型过拟合的可能性太高

针对stacking存在的这两个问题,竞赛冠军队们持续探索,并且在实践过程中创造了多种改进的stacking方法。今天,多种stacking方法中较为有效的方法之一就是著名的Blending方法。Blending直译为“混合”,但它的核心思路其实与Stacking完全一致:使用两层算法串联,level0上存在多个强学习器,level1上有且只有一个元学习器,且level0上的强学习器负责拟合数据与真实标签之间的关系、并输出预测结果、组成新的特征矩阵,然后让level1上的元学习器在新的特征矩阵上学习并预测。

image

然而,与stacking不同的是,为了降低计算量、降低融合模型过拟合风险,Blending取消了K折交叉验证、并且大大地降低了元学习器所需要训练的数据量,其具体流程如下:

  • blending的训练
  1. 将数据分割为训练集、验证集与测试集,其中训练集上的样本为(M_{train}),验证集上的样本为(M_v),测试集上的样本量为(M_{test})
     
  2. 将训练集输入level 0的个体学习器,分别在每个个体学习器上训练。训练完毕后,在验证集上进行验证,输出验证集上的预测结果。假设预测结果为概率值,当融合模型执行回归或二分类任务时,该预测结果的结构为((M_v,1)),当融合模型执行K分类任务时(K>2),该预测结果的结构为((M_v,K))。此时此刻,所有个体学习器都被训练完毕了。
     
  3. 将所有个体学习器的验证结果横向拼接,形成新特征矩阵。假设共有N个个体学习器,则新特征矩阵的结构为((M_v, N))。
     
  4. 将新特征矩阵放入元学习器进行训练。
  • blending的测试
  1. 将测试集输入level0的个体学习器,分别在每个个体学习器上预测出相应结果。假设测试结果为概率值,当融合模型执行回归或二分类任务时,该测试结果的结构为((M_{test},1)),当融合模型执行K分类任务时(K>2),该测试结果的结构为((M_{test},K))
     
  2. 将所有个体学习器的预测结果横向拼接为新特征矩阵。假设共有N个个体学习器,则新特征矩阵的结构为((M_{test}, N)).
     
  3. 将新特征矩阵放入元学习器进行预
    测。

2 手动实现Blending算法

 
  1. def BlendingClassifier(X,y,estimators,final_estimator,test_size=0.2,vali_size=0.4):

  2. X,y:整体数据集,会被分割为训练集、测试集、验证集三部分

  3. estimators: level0的个体学习器,输入格式形如sklearn中要求的[(名字,算法),(名字,算法)...]

  4. test_size:测试集占全数据集的比例

  5. vali_size:验证集站全数据集的比例

  6. #2.分训练和验证集,验证集占完整数据集的比例为0.4,因此占排除测试集之后的比例为0.4/(1-0.2)

  7. X_,Xtest,y_,Ytest = train_test_split(X,y,test_size=test_size,random_state=1412)

  8. Xtrain,Xvali,Ytrain,Yvali = train_test_split(X_,y_,test_size=vali_size/(1-test_size),random_state=1412)

  9. #建立空dataframe用于保存个体学习器上的验证结果,即用于生成新特征矩阵

  10. #新建空列表用于保存训练完毕的个体学习器,以便在测试中使用

  11. NewX_vali = pd.DataFrame()

  12. trained_estimators = []

  13. #循环、训练每个个体学习器、并收集个体学习器在验证集上输出的概率

  14. for clf_id, clf in estimators:

  15. clf = clf.fit(Xtrain,Ytrain)

  16. val_predictions = pd.DataFrame(clf.predict_proba(Xvali))

  17. #保存结果,在循环中逐渐构筑新特征矩阵

  18. NewX_vali = pd.concat([NewX_vali,val_predictions],axis=1)

  19. trained_estimators.append((clf_id,clf))

  20. #元学习器在新特征矩阵上训练、并输出训练分数

  21. final_estimator = final_estimator.fit(NewX_vali,Yvali)

  22. train_score = final_estimator.score(NewX_vali,Yvali)

  23. #建立空dataframe用于保存个体学习器上的预测结果,即用于生成新特征矩阵

  24. NewX_test = pd.DataFrame()

  25. #循环,在每个训练完毕的个体学习器上进行预测,并收集每个个体学习器上输出的概率

  26. for clf_id,clf in trained_estimators:

  27. test_prediction = pd.DataFrame(clf.predict_proba(Xtest))

  28. #保存结果,在循环中逐渐构筑特征矩阵

  29. NewX_test = pd.concat([NewX_test,test_prediction],axis=1)

  30. #元学习器在新特征矩阵上测试、并输出测试分数

  31. test_score = final_estimator.score(NewX_test,Ytest)

  32. print(train_score,test_score)

 
  1. clf1 = LogiR(max_iter = 3000, C=0.1, random_state=1412,n_jobs=8)

  2. clf2 = RFC(n_estimators= 100,max_features="sqrt",max_samples=0.9, random_state=1412,n_jobs=8)

  3. clf3 = GBC(n_estimators= 100,max_features=16,random_state=1412)

  4. clf4 = DTC(max_depth=8,random_state=1412)

  5. clf5 = KNNC(n_neighbors=10,n_jobs=8)

  6. clf7 = RFC(n_estimators= 100,max_features="sqrt",max_samples=0.9, random_state=4869,n_jobs=8)

  7. clf8 = GBC(n_estimators= 100,max_features=16,random_state=4869)

  8. estimators = [("Logistic Regression",clf1), ("RandomForest", clf2)

  9. , ("GBDT",clf3), ("Decision Tree", clf4), ("KNN",clf5)

  10. #, ("Bayes",clf6)

  11. #, ("RandomForest2", clf7), ("GBDT2", clf8)

 
  1. final_estimator = RFC(n_estimators= 100

  2. #, max_depth = 8

  3. , min_impurity_decrease=0.0025

  4. , random_state= 420, n_jobs=8)

 
  1. #很明显,过拟合程度比Stacking要轻,但是测试集的表现没有stacking强

  2. BlendingClassifier(X,y,estimators,final_estimator)

image

 
  1. #验证比例越大,模型学习能力越弱 - 注意验证集比例上限0.8,因为有0.2是测试数据

  2. BlendingClassifier(X,y,estimators,final_estimator,vali_size=0.7)

image

 
  1. #blending的运行速度比stacking快了不止一个档次……

  2. BlendingClassifier(X,y,estimators,final_estimator,vali_size=0.1)

image

benchmark投票法StackingBlending
5折交叉验证0.96660.98330.9812(↓)-
测试集结果0.95270.98890.9889(-)0.9833(↓)

从结果来看,投票法表现最稳定和优异,这与我们选择的数据集是较为简单的数据集有关,同时投票法也是我们调整最多、最到位的算法。在大型数据集上运行时,stacking和blending会展现出更多的优势。到这里我们的blending就讲解完毕了,在《2022机器学习实战》正式课程当中,我们将会更详细地讲解Blending在xgboost等复杂算法上的应用。

参考:https://www.cnblogs.com/lipu123/p/17563377.html

更多python机器学习相关知识,请关注公众号(python风控模型)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/89192.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自定义热加载:如何不停机实现核心代码更新

文章目录 1. 常见的几种实现代码热更新的几种方式对于开发环境我们可以使用部署环境1. 使用 Arthas 的 redefine 命令来加载新的 class 文件2. 利用 URLClassLoader 动态加载3. 通过Java的Instrumentation API 也是可以实现的 2. 实现1. ClassScanner扫描目录和加载类2. 定时任…

Mybatis学习笔记7 参数处理专题

Mybatis学习笔记6 使用时的一些小技巧_biubiubiu0706的博客-CSDN博客 1.单个简单类型参数 2.Map参数 3.实体类参数 4.多参数 5.Param注解(命名参数) 6.Param源码分析 建表 插入点数据 新建模块 pom.xml <?xml version"1.0" encoding"UTF-8"?&…

SpringBoot 学习(七)Swagger

7. Swagger 7.1 简介 便于前后端集成联调RestFul Api 文档在线生成工具 > Api 文档与 Api 定义同步更新直接运行&#xff0c;在线测试 Api 接口 7.2 springboot 集成 swagger (1) 导入依赖 <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger…

2001-2021年上市公司基于Jones 修正模型的盈余管理测度(含原始数据+stata 计算代码)

2001-2021年上市公司基于Jones 修正模型的盈余管理测度&#xff08;含原始数据stata 计算代码&#xff09; 1、时间&#xff1a;2001-2021 年 3、范围&#xff1a;沪深 A 股上市公司 4、指标&#xff1a;经营活动现金流、总资产、净利润、总收入、固定资产、应收账款、盈余管…

如何快速做跨业务测试?

当业务任务多且人力资源不充足的情况下&#xff0c;不同业务的同学可能需要去不同的业务进行临时支援&#xff0c;可能在时间方面有长有短&#xff0c;但是如何迈出第一步是很多人需要关心的一件事。 本文以实际跨业务测试经验&#xff08;订单业务测试人员如何测试售后业务&a…

什么是HTTP/2?它与HTTP/1.1相比有什么改进?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ HTTP/2 简介⭐ 主要的改进和特点⭐ 总结⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端…

梦想让生活得以忍受-寄语机器视觉工程师

我&#xff0c;曾梦想梦想走天涯&#xff0c;看看这世界的繁华&#xff0c;年少的心总有些轻狂&#xff0c;如今四海为家。 大家都听过这首歌&#xff0c;迎来很多打工人的共鸣&#xff0c;著名作家海明威曾说&#xff0c;“一个人可以被打败&#xff0c;但不可以被毁灭”&…

Web自动化测试 —— 如何进行Selenium页面数据及元素交互?啊哈

前言&#xff1a; Web自动化测试是一种常用的测试方式&#xff0c;通过在浏览器中模拟用户操作以及与页面元素的交互&#xff0c;可以有效地检验页面的功能性以及稳定性。Selenium是一款流行的Web自动化测试工具&#xff0c;在本篇文章中&#xff0c;我们将介绍如何使用Seleni…

Echarts 自适应不生效解决(CPK分析工具直方图为例)

示例代码为左上方的CPK分析直方图组件 <template><div ref="cpk" id="cpk" style="height: 300px; width: 100%"></div> </template><script> import * as echarts from "echarts"; import { deboun…

HarmonyOS开发:解决DevEco Studio低版本导入高版本项目运行失败问题

前言 基于DevEco Studio 4.0 Beta2&#xff0c;hvigorVersion为3.0.2&#xff0c;开发了一个项目&#xff0c;上传到了远程仓库&#xff0c;当同事下载后&#xff0c;却始终无法运行&#xff0c;频繁报错&#xff0c;由于API都是使用的9&#xff0c;第一感觉就是开发环境不同&a…

Qt: 鼠标形状设置

设置全局鼠标形状 设置完毕后&#xff0c;整个APP的任何窗体&#xff0c;包括Dialog中的鼠标形状都会被修改为设定类型&#xff0c;某一个控件设定的鼠标形状将被替换。一般不建议使用 QCursor cursor;//创建鼠标对象 cursor.setShape(Qt::CursorShape::ClosedHandCursor);//…

创建线程的4种方法

目录 一.前言 1.关于进程调度 (1)为什么要调度? (2)调度的真正对象 (3)调度的资源 2.线程 (1).线程的写法 (2)线程创建的方法 1.继承Thread (1)使用继承Thread,重写run的方式来创建线程 (2)继承Thread,使用匿名内部类 2.实现Runnable (1)使用实现Runnable,重写run…

Android系统之编译Intel5.1问题解决

1.jdk问题: ************************************************************ You are attempting to build with the incorrect version of java.Your version is: openjdk version "1.7.0_75" OpenJDK Runtime Environment (build 1.7.0_75-b13) OpenJDK 64-Bit Se…

微服务线上问题排查困难?不知道问题出在哪一环?那是你还不会分布式链路追踪

咱们以前单体应用里面有很多的应用和功能&#xff0c;依赖各个功能之间相互调用&#xff0c;使用公共的代码包等等&#xff0c;排查问题&#xff0c;使用类似于 gdb/dlv 工具或者直接查看代码日志&#xff0c;进行定位和分析 但是现在我们基本上都是微服务架构了&#xff0c;将…

JavaScript入门——(2)基础语法(上)

一、JavaScript介绍 1.1 JavaScript是什么 1.1.1 JavaScript是什么&#xff1f; JavaScript是一种运行在客户端&#xff08;浏览器&#xff09;的编程语言&#xff0c;实现人机交互效果。 注意&#xff1a;HTML和CSS是标记语言。 1.1.2 作用&#xff08;做什么&#xff1f…

2023最新最详细软件测试技术面试题【含答案】

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程&#xff0c;刷完面试就稳了&#xff0c;你也可以当高薪软件测试工程师&#xff08;自动化测试&#xff09; 有这样一个面试题&#xff1a;在一个Web测试页面上&#xff0c;有一个输入框&#xff0c;一个计数器&…

【STM32单片机】u8g2智能风扇设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用STM32F103C8T6单片机控制器&#xff0c;使用按键、IIC OLED模块、DS18B20温度传感器、直流电机、红外遥控等。 主要功能&#xff1a; 初始化后进入温度显示界面&#xff0c;系统初始状态为手动…

软件测试工作步骤详情

软件测试步骤按照研发阶段一般分为5个部分&#xff1a;单元测试、集成测试、确认测试、系统测试、验收测试&#xff0c;下面将不同阶段需要的一些工作内容做一下梳理希望可以帮助到大家。 一、单元测试的内容&#xff1a;&#xff08;白盒为主&#xff0c;黑盒为辅&#xff09;…

Ubuntu 安装 CUDA 与 CUDNN GPU加速引擎

一、NVIDIA&#xff08;英伟达&#xff09;显卡驱动安装 NVIDIA显卡驱动可以通过指令sudo apt purge nvidia*删除以前安装的NVIDIA驱动版本&#xff0c;重新安装。 1.1. 关闭系统自带驱动nouveau 注意&#xff01;在安装NVIDIA驱动以前需要禁止系统自带显卡驱动nouveau&#xf…

Diffusion Autoencoders: Toward a Meaningful and Decodable Representation

Diffusion Autoencoders: Toward a Meaningful and Decodable Representation (Paper reading) Konpat Preechakul, VISTEC, Thailand, CVPR22 Oral, Cited:117, Code, Paper 1. 前言 扩散概率模型 (DPM) 在图像生成方面取得了显着的质量&#xff0c;可与 GAN 相媲美。但是与…