当前位置: 首页 > news >正文

2024-12-29-sklearn学习(26)模型选择与评估-交叉验证:评估估算器的表现 今夜偏知春气暖,虫声新透绿窗纱。

文章目录

  • sklearn学习(26) 模型选择与评估-交叉验证:评估估算器的表现
    • 26.1 计算交叉验证的指标
      • 26.1.1 cross_validate 函数和多度量评估
      • 26.1.2 通过交叉验证获取预测
    • 26.2 交叉验证迭代器
      • 26.2.1 交叉验证迭代器–循环遍历数据
        • 26.2.1.1 K 折
        • 26.2.1.2 重复 K-折交叉验证
        • 26.2.1.3 留一交叉验证 (LOO)
        • 26.2.1.4 留 P 交叉验证 (LPO)
        • 26.2.1.5 随机排列交叉验证 a.k.a. Shuffle & Split
      • 26.2.2 基于类标签、具有分层的交叉验证迭代器
        • 26.2.2.1 分层 k 折
      • 26.2.2.2 分层随机 Split
      • 26.2.3 用于分组数据的交叉验证迭代器
        • 26.2.3.1 组 k-fold
        • 26.2.3.2 留一组交叉验证
        • 26.2.3.3 留 P 组交叉验证
        • 26.2.3.4 Group Shuffle Split
      • 26.2.4 预定义的折叠 / 验证集
      • 26.2.5 交叉验证在时间序列数据中应用
        • 26.2.5.1 时间序列分割
    • 26.3 A note on shuffling
    • 26.4 交叉验证和模型选择

sklearn学习(26) 模型选择与评估-交叉验证:评估估算器的表现

文章参考网站:
https://sklearn.apachecn.org/

https://scikit-learn.org/stable/

学习预测函数的参数,并在相同数据集上进行测试是一种错误的做法:

一个仅给出测试用例标签的模型将会获得极高的分数,但对于尚未出现过的数据它则无法预测出任何有用的信息。 这种情况称为 overfitting(过拟合).

为了避免这种情况,在进行(监督)机器学习实验时,通常取出部分可利用数据作为 test set(测试数据集) X_test, y_test。需要强调的是这里说的 “experiment(实验)” 并不仅限于学术(academic),因为即使是在商业场景下机器学习也往往是从实验开始的。下面是模型训练中典型的交叉验证工作流流程图。通过网格搜索可以确定最佳参数。

grid_search_workflow.png

利用 scikit-learn 包中的 train_test_split 辅助函数可以很快地将实验数据集划分为任何训练集(training sets)和测试集(test sets)。 下面让我们载入 iris 数据集,并在此数据集上训练出线性支持向量机:

>>> import numpy as np
>>> from sklearn.model_selection import train_test_split
>>> from sklearn import datasets
>>> from sklearn import svm>>> iris = datasets.load_iris()
>>> iris.data.shape, iris.target.shape
((150, 4), (150,))

我们能快速采样到原数据集的 40% 作为测试集,从而测试(评估)我们的分类器:

>>> X_train, X_test, y_train, y_test = train_test_split(
...     iris.data, iris.target, test_size=0.4, random_state=0)>>> X_train.shape, y_train.shape
((90, 4), (90,))
>>> X_test.shape, y_test.shape
((60, 4), (60,))>>> clf = svm.SVC(kernel='linear', C=1).fit(X_train, y_train)
>>> clf.score(X_test, y_test)                           
0.96...

当评价估计器的不同设置(”hyperparameters(超参数)”)时,例如手动为 SVM 设置的 C 参数, 由于在训练集上,通过调整参数设置使估计器的性能达到了最佳状态;但 在测试集上 可能会出现过拟合的情况。 此时,测试集上的信息反馈足以颠覆训练好的模型,评估的指标不再有效反映出模型的泛化性能。 为了解决此类问题,还应该准备另一部分被称为 “validation set(验证集)” 的数据集,模型训练完成以后在验证集上对模型进行评估。 当验证集上的评估实验比较成功时,在测试集上进行最后的评估。

然而,通过将原始数据分为3个数据集合,我们就大大减少了可用于模型学习的样本数量, 并且得到的结果依赖于集合对(训练,验证)的随机选择。

这个问题可以通过 交叉验证CV 来解决。 交叉验证仍需要测试集做最后的模型评估,但不再需要验证集。

最基本的方法被称之为,k-折交叉验证 。 k-折交叉验证将训练集划分为 k 个较小的集合(其他方法会在下面描述,主要原则基本相同)。 每一个 k 折都会遵循下面的过程:

  • k − 1 k-1 k1 份训练集子集作为 training data (训练集)训练模型,
  • 将剩余的 1 份训练集子集用于模型验证(也就是把它当做一个测试集来计算模型的性能指标,例如准确率)。

k-折交叉验证得出的性能指标是循环计算中每个值的平均值。 该方法虽然计算代价很高,但是它不会浪费太多的数据(如固定任意测试集的情况一样), 在处理样本数据集较少的问题(例如,逆向推理)时比较有优势。

grid_search_cross_validation.png

26.1 计算交叉验证的指标

使用交叉验证最简单的方法是在估计器和数据集上调用 cross_val_score 辅助函数。

下面的示例展示了如何通过分割数据,拟合模型和计算连续 5 次的分数(每次不同分割)来估计 linear kernel 支持向量机在 iris 数据集上的精度:

>>> from sklearn.model_selection import cross_val_score
>>> clf = svm.SVC(kernel='linear', C=1)
>>> scores = cross_val_score(clf, iris.data, iris.target, cv=5)
>>> scores                                              
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

评分估计的平均得分和 95% 置信区间由此给出:

>>> print("Accuracy: %0.2f (+/- %0.2f)" % (scores.mean(), scores.std() * 2))
Accuracy: 0.98 (+/- 0.03)

默认情况下,每个 CV 迭代计算的分数是估计器的 score 方法。可以通过使用 scoring 参数来改变计算方式如下:

>>> from sklearn import metrics
>>> scores = cross_val_score(
...     clf, iris.data, iris.target, cv=5, scoring='f1_macro')
>>> scores                                              
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

详情请参阅 scoring 参数: 定义模型评估规则 。 在 Iris 数据集的情形下,样本在各个目标类别之间是平衡的,因此准确度和 F1-score 几乎相等。

cv 参数是一个整数时, cross_val_score 默认使用 KFoldStratifiedKFold 策略,后者会在估计器派生自 ClassifierMixin 时使用。

也可以通过传入一个交叉验证迭代器来使用其他交叉验证策略,比如:

>>> from sklearn.model_selection import ShuffleSplit
>>> n_samples = iris.data.shape[0]
>>> cv = ShuffleSplit(n_splits=5, test_size=0.3, random_state=0)
>>> cross_val_score(clf, iris.data, iris.target, cv=cv)  
array([0.977..., 0.977..., 1.  ..., 0.955..., 1.        ])

另外一种可选方案是使用一个可迭代生成器作为索引数组产生(train, test) 划分,比如:

>>> def custom_cv_2folds(X):
...     n = X.shape[0]
...     i = 1
...     while i <= 2:
...         idx = np.arange(n * (i - 1) / 2, n * i / 2, dtype=int)
...         yield idx, idx
...         i += 1
...
>>> custom_cv = custom_cv_2folds(iris.data)
>>> cross_val_score(clf, iris.data, iris.target, cv=custom_cv)
array([1.        , 0.973...])

保留数据的数据转换

  • 正如在训练集中保留的数据上测试一个 predictor (预测器)是很重要的一样,预处理(如标准化,特征选择等)和类似的 data transformations 也应该从训练集中学习,并应用于预测数据以进行预测:
>>> from sklearn import preprocessing
>>> X_train, X_test, y_train, y_test = train_test_split(
...     iris.data, iris.target, test_size=0.4, random_state=0)
>>> scaler = preprocessing.StandardScaler().fit(X_train)
>>> X_train_transformed = scaler.transform(X_train)
>>> clf = svm.SVC(C=1).fit(X_train_transformed, y_train)
>>> X_test_transformed = scaler.transform(X_test)
>>> clf.score(X_test_transformed, y_test)  
0.9333...

Pipeline 可以更容易地组合估计器,在交叉验证下使用如下:

>>> from sklearn.pipeline import make_pipeline
>>> clf = make_pipeline(preprocessing.StandardScaler(), svm.SVC(C=1))
>>> cross_val_score(clf, iris.data, iris.target, cv=cv)
...                                                 
array([ 0.97...,  0.93...,  0.95...])

可以参阅 Pipeline(管道)和 FeatureUnion(特征联合): 合并的评估器.

26.1.1 cross_validate 函数和多度量评估

cross_validate 函数与 cross_val_score 在下面的两个方面有些不同 -

  • 它允许指定多个指标进行评估.
  • 除了测试得分之外,它还会返回一个包含训练得分,拟合次数, score-times (得分次数)的一个字典。 It returns a dict containing training scores, fit-times and score-times in addition to the test score.

对于单个度量评估,其中 scoring 参数是一个字符串,可以调用或 None , keys 将是 - ['test_score', 'fit_time', 'score_time']

而对于多度量评估,返回值是一个带有以下的 keys 的字典 - ['test_<scorer1_name>', 'test_<scorer2_name>', 'test_<scorer...>', 'fit_time', 'score_time']

return_train_score 默认设置为 True 。 它增加了所有 scorers(得分器) 的训练得分 keys 。如果不需要训练 scores ,则应将其明确设置为 False

你还可以通过设置return_estimator=True来保留在所有训练集上拟合好的估计器。

可以将多个测度指标指定为list,tuple或者是预定义评分器(predefined scorer)的名字的集合

>>> from sklearn.model_selection import cross_validate
>>> from sklearn.metrics import recall_score
>>> scoring = ['precision_macro', 'recall_macro']
>>> clf = svm.SVC(kernel='linear', C=1, random_state=0)
>>> scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,
...                         cv=5)
>>> sorted(scores.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
>>> scores['test_recall_macro']                       
array([0.96..., 1.  ..., 0.96..., 0.96..., 1.        ])

或作为一个字典 mapping 得分器名称预定义或自定义的得分函数:

>>> from sklearn.metrics.scorer import make_scorer
>>> scoring = {'prec_macro': 'precision_macro',
...            'rec_macro': make_scorer(recall_score, average='macro')}
>>> scores = cross_validate(clf, iris.data, iris.target, scoring=scoring,
...                         cv=5, return_train_score=True)
>>> sorted(scores.keys())                 
['fit_time', 'score_time', 'test_prec_macro', 'test_rec_macro','train_prec_macro', 'train_rec_macro']
>>> scores['train_rec_macro']                         
array([0.97..., 0.97..., 0.99..., 0.98..., 0.98...])

这里是一个使用单一指标的 cross_validate 的示例:

>>> scores = cross_validate(clf, iris.data, iris.target,
...                         scoring='precision_macro', cv=5,
...                         return_estimator=True)
>>> sorted(scores.keys())
['estimator', 'fit_time', 'score_time', 'test_score']

26.1.2 通过交叉验证获取预测

除了返回结果不同,函数 cross_val_predict 具有和 cross_val_score 相同的接口, 对于每一个输入的元素,如果其在测试集合中,将会得到预测结果。交叉验证策略会将可用的元素提交到测试集合有且仅有一次(否则会抛出一个异常)。

警告 :交叉预测可能使用不当

  • cross_val_predict函数的结果可能会与cross_val_score函数的结果不一样,因为在这两种方法中元素的分组方式不一样。函数cross_val_score在所有交叉验证的折子上取平均。但是,函数cross_val_predict只是简单的返回由若干不同模型预测出的标签或概率。因此,cross_val_predict不是一种适当的泛化错误的度量。

函数cross_val_predict比较适合做下列事儿:

  • 从不同模型获得的预测结果的可视化。
  • 模型混合: 在集成方法中,当一个有监督估计量的预测被用来训练另一个估计量时

可用的交叉验证迭代器在下面的章节将提到。

示例

  • Receiver Operating Characteristic (ROC) with cross validation,
  • Recursive feature elimination with cross-validation,
  • Parameter estimation using grid search with cross-validation,
  • Sample pipeline for text feature extraction and evaluation,
  • 绘制交叉验证预测图,
  • Nested versus non-nested cross-validation.

26.2 交叉验证迭代器

接下来的部分列出了一些用于生成索引标号,用于在不同的交叉验证策略中生成数据划分的工具。

26.2.1 交叉验证迭代器–循环遍历数据

假设一些数据是独立的和相同分布的 (i.i.d) 假定所有的样本来源于相同的生成过程,并假设生成过程没有记忆过去生成的样本。

在这种情况下可以使用下面的交叉验证器。

注意

  • 尽管 i.i.d 数据是机器学习理论中的一个常见假设,但在实践中很少成立。如果知道样本是使用时间相关的过程生成的,则使用 time-series aware cross-validation scheme 更安全。 同样,如果我们知道生成过程具有 group structure (群体结构)(从不同 subjects(主体) , experiments(实验), measurement devices (测量设备)收集的样本),则使用 group-wise cross-validation 更安全。
26.2.1.1 K 折

KFold 将所有的样例划分为 k k k 个组,称为折叠 (fold) (如果 k = n k=n k=n , 这等价于 Leave One Out(留一) 策略),都具有相同的大小(如果可能)。预测函数学习时使用 k − 1 k-1 k1 个折叠中的数据,最后一个剩下的折叠会用于测试。

在 4 个样例的数据集上使用 2-fold 交叉验证的示例:

>>> import numpy as np
>>> from sklearn.model_selection import KFold>>> X = ["a", "b", "c", "d"]
>>> kf = KFold(n_splits=2)
>>> for train, test in kf.split(X):
...     print("%s  %s" % (train, test))
[2 3] [0 1]
[0 1] [2 3]

这个示例是关于交叉验证的可视化的。请注意KFold不被分类所影响sphx_glr_plot_cv_indices_0041.png

每个折叠由两个 arrays 组成,第一个作为 training set ,另一个作为 test set 。 由此,可以通过使用 numpy 的索引创建训练/测试集合:

>>> X = np.array([[0., 0.], [1., 1.], [-1., -1.], [2., 2.]])
>>> y = np.array([0, 1, 0, 1])
>>> X_train, X_test, y_train, y_test = X[train], X[test], y[train], y[test]
26.2.1.2 重复 K-折交叉验证

RepeatedKFold 重复 K-Fold n 次。当需要运行时可以使用它 KFold n 次,在每次重复中产生不同的分割。

2折 K-Fold 重复 2 次的示例:

>>> import numpy as np
>>> from sklearn.model_selection import RepeatedKFold
>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4]])
>>> random_state = 12883823
>>> rkf = RepeatedKFold(n_splits=2, n_repeats=2, random_state=random_state)
>>> for train, test in rkf.split(X):
...     print("%s  %s" % (train, test))
...
[2 3] [0 1]
[0 1] [2 3]
[0 2] [1 3]
[1 3] [0 2]

类似地, RepeatedStratifiedKFold 在每个重复中以不同的随机化重复 n 次分层的 K-Fold 。

26.2.1.3 留一交叉验证 (LOO)

LeaveOneOut (或 LOO) 是一个简单的交叉验证。每个学习集都是通过除了一个样本以外的所有样本创建的,测试集是被留下的样本。 因此,对于 n n n 个样本,我们有 n n n 个不同的训练集和 n n n 个不同的测试集。这种交叉验证程序不会浪费太多数据,因为只有一个样本是从训练集中删除掉的:

>>> from sklearn.model_selection import LeaveOneOut>>> X = [1, 2, 3, 4]
>>> loo = LeaveOneOut()
>>> for train, test in loo.split(X):
...     print("%s  %s" % (train, test))
[1 2 3] [0]
[0 2 3] [1]
[0 1 3] [2]
[0 1 2] [3]

LOO 潜在的用户选择模型应该权衡一些已知的警告。 当与 k k k 折交叉验证进行比较时,可以从 n n n 样本中构建 n n n 模型,而不是 k k k 模型,其中 n > k n>k n>k 。 此外,每个在 n − 1 n-1 n1 个样本而不是在 ( k − 1 ) n / k (k-1)n/k (k1)n/k 上进行训练。在两种方式中,假设 k k k 不是太大,并且 k < n k<n k<n , LOO 比 k k k 折交叉验证计算开销更加昂贵。

就精度而言, LOO 经常导致较高的方差作为测试误差的估计器。直观地说,因为 n n n 个样本中的 n − 1 n-1 n1 被用来构建每个模型,折叠构建的模型实际上是相同的,并且是从整个训练集建立的模型。

但是,如果学习曲线对于所讨论的训练大小是陡峭的,那么 5- 或 10- 折交叉验证可以泛化误差增高。

作为一般规则,大多数作者和经验证据表明, 5- 或者 10- 交叉验证应该优于 LOO 。

参考资料:

  • http://www.faqs.org/faqs/ai-faq/neural-nets/part3/section-12.html;
  • T. Hastie, R. Tibshirani, J. Friedman, The Elements of Statistical Learning, Springer 2009
  • L. Breiman, P. Spector Submodel selection and evaluation in regression: The X-random case, International Statistical Review 1992;
  • R. Kohavi, A Study of Cross-Validation and Bootstrap for Accuracy Estimation and Model Selection, Intl. Jnt. Conf. AI
  • R. Bharat Rao, G. Fung, R. Rosales, On the Dangers of Cross-Validation. An Experimental Evaluation, SIAM 2008;
  • G. James, D. Witten, T. Hastie, R Tibshirani, An Introduction to Statistical Learning, Springer 2013.
26.2.1.4 留 P 交叉验证 (LPO)

LeavePOutLeaveOneOut 非常相似,因为它通过从整个集合中删除 p p p 个样本来创建所有可能的 训练/测试集。对于 n n n 个样本,这产生了 ( n p ) {n \choose p} (pn) 个 训练-测试 对。与 LeaveOneOutKFold 不同,当 p > 1 p>1 p>1 时,测试集会重叠。

在有 4 个样例的数据集上使用 Leave-2-Out 的示例:

>>> from sklearn.model_selection import LeavePOut>>> X = np.ones(4)
>>> lpo = LeavePOut(p=2)
>>> for train, test in lpo.split(X):
...     print("%s  %s" % (train, test))
[2 3] [0 1]
[1 3] [0 2]
[1 2] [0 3]
[0 3] [1 2]
[0 2] [1 3]
[0 1] [2 3]
26.2.1.5 随机排列交叉验证 a.k.a. Shuffle & Split

ShuffleSplit

ShuffleSplit 迭代器 将会生成一个用户给定数量的独立的训练/测试数据划分。样例首先被打散然后划分为一对训练测试集合。

可以通过设定明确的 random_state ,使得伪随机生成器的结果可以重复。

这是一个使用的小示例:

>>> from sklearn.model_selection import ShuffleSplit
>>> X = np.arange(5)
>>> ss = ShuffleSplit(n_splits=3, test_size=0.25,
...     random_state=0)
>>> for train_index, test_index in ss.split(X):
...     print("%s  %s" % (train_index, test_index))
...
[1 3 4] [2 0]
[1 4 3] [0 2]
[4 0 2] [1 3]

下面是交叉验证行为的可视化。注意ShuffleSplit不受分类的影响

sphx_glr_plot_cv_indices_0061.png

ShuffleSplit 可以替代 KFold 交叉验证,因为其提供了细致的训练 / 测试划分的 数量和样例所占的比例等的控制。

26.2.2 基于类标签、具有分层的交叉验证迭代器

一些分类问题在目标类别的分布上可能表现出很大的不平衡性:例如,可能会出现比正样本多数倍的负样本。在这种情况下,建议采用如 StratifiedKFoldStratifiedShuffleSplit 中实现的分层抽样方法,确保相对的类别频率在每个训练和验证 折叠 中大致保留。

26.2.2.1 分层 k 折

StratifiedKFoldk-fold 的变种,会返回 stratified(分层) 的折叠:每个小集合中, 各个类别的样例比例大致和完整数据集中相同。

在有 10 个样例的,有两个略不均衡类别的数据集上进行分层 3-fold 交叉验证的示例:

>>> from sklearn.model_selection import StratifiedKFold>>> X = np.ones(10)
>>> y = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
>>> skf = StratifiedKFold(n_splits=3)
>>> for train, test in skf.split(X, y):
...     print("%s  %s" % (train, test))
[2 3 6 7 8 9] [0 1 4 5]
[0 1 3 4 5 8 9] [2 6 7]
[0 1 2 4 5 6 7] [3 8 9]

下面是该交叉验证方法的可视化。 sphx_glr_plot_cv_indices_0071.png

RepeatedStratifiedKFold 可用于在每次重复中用不同的随机化重复分层 K-Fold n 次。

26.2.2.2 分层随机 Split

下面是该交叉验证方法的可视化。 sphx_glr_plot_cv_indices_0091.png

StratifiedShuffleSplitShuffleSplit 的一个变种,会返回直接的划分,比如: 创建一个划分,但是划分中每个类的比例和完整数据集中的相同。

26.2.3 用于分组数据的交叉验证迭代器

如果潜在的生成过程产生依赖样本的 groups ,那么 i.i.d. 假设将会被打破。

这样的数据分组是特定于域的。一个示例是从多个患者收集医学数据,从每个患者身上采集多个样本。而这样的数据很可能取决于个人群体。 在我们的示例中,每个样本的患者 ID 将是其 group identifier (组标识符)。

在这种情况下,我们想知道在一组特定的 groups 上训练的模型是否能很好地适用于看不见的 group 。为了衡量这一点,我们需要确保验证对象中的所有样本来自配对训练折叠中完全没有表示的组。

下面的交叉验证分离器可以用来做到这一点。 样本的 grouping identifier (分组标识符) 通过 groups 参数指定。

26.2.3.1 组 k-fold

GroupKFold 是 k-fold 的变体,它确保同一个 group 在测试和训练集中都不被表示。 例如,如果数据是从不同的 subjects 获得的,每个 subject 有多个样本,并且如果模型足够灵活以高度人物指定的特征中学习,则可能无法推广到新的 subject 。 GroupKFold 可以检测到这种过拟合的情况。 Imagine you have three subjects, each with an associated number from 1 to 3:

>>> from sklearn.model_selection import GroupKFold>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"]
>>> groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]>>> gkf = GroupKFold(n_splits=3)
>>> for train, test in gkf.split(X, y, groups=groups):
...     print("%s  %s" % (train, test))
[0 1 2 3 4 5] [6 7 8 9]
[0 1 2 6 7 8 9] [3 4 5]
[3 4 5 6 7 8 9] [0 1 2]

每个 subject 都处于不同的测试阶段,同一个科目从来没有在测试和训练过程中。请注意,由于数据不平衡,折叠的大小并不完全相同。

下面是该交叉验证方法的可视化。

sphx_glr_plot_cv_indices_0051.png

26.2.3.2 留一组交叉验证

LeaveOneGroupOut 是一个交叉验证方案,它根据第三方提供的 array of integer groups (整数组的数组)来提供样本。这个组信息可以用来编码任意域特定的预定义交叉验证折叠。

每个训练集都是由除特定组别以外的所有样本构成的。

例如,在多个实验的情况下, LeaveOneGroupOut 可以用来根据不同的实验创建一个交叉验证:我们使用除去一个实验的所有实验的样本创建一个训练集:

>>> from sklearn.model_selection import LeaveOneGroupOut>>> X = [1, 5, 10, 50, 60, 70, 80]
>>> y = [0, 1, 1, 2, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3, 3]
>>> logo = LeaveOneGroupOut()
>>> for train, test in logo.split(X, y, groups=groups):
...     print("%s  %s" % (train, test))
[2 3 4 5 6] [0 1]
[0 1 4 5 6] [2 3]
[0 1 2 3] [4 5 6]

另一个常见的应用是使用时间信息:例如,组可以是收集样本的年份,从而允许与基于时间的分割进行交叉验证。

26.2.3.3 留 P 组交叉验证

LeavePGroupsOut 类似于 LeaveOneGroupOut ,但为每个训练/测试集删除与 P P P 组有关的样本。

Leave-2-Group Out 的示例:

>>> from sklearn.model_selection import LeavePGroupsOut>>> X = np.arange(6)
>>> y = [1, 1, 1, 2, 2, 2]
>>> groups = [1, 1, 2, 2, 3, 3]
>>> lpgo = LeavePGroupsOut(n_groups=2)
>>> for train, test in lpgo.split(X, y, groups=groups):
...     print("%s  %s" % (train, test))
[4 5] [0 1 2 3]
[2 3] [0 1 4 5]
[0 1] [2 3 4 5]
26.2.3.4 Group Shuffle Split

GroupShuffleSplit 迭代器是 ShuffleSplitLeavePGroupsOut 的组合,它生成一个随机划分分区的序列,其中为每个分组提供了一个组子集。

这是使用的示例:

>>> from sklearn.model_selection import GroupShuffleSplit>>> X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 0.001]
>>> y = ["a", "b", "b", "b", "c", "c", "c", "a"]
>>> groups = [1, 1, 2, 2, 3, 3, 4, 4]
>>> gss = GroupShuffleSplit(n_splits=4, test_size=0.5, random_state=0)
>>> for train, test in gss.split(X, y, groups=groups):
...     print("%s  %s" % (train, test))
...
[0 1 2 3] [4 5 6 7]
[2 3 6 7] [0 1 4 5]
[2 3 4 5] [0 1 6 7]
[4 5 6 7] [0 1 2 3]

下面是该交叉验证方法的可视化。

sphx_glr_plot_cv_indices_0081.png

当需要 LeavePGroupsOut 的操作时,这个类的信息是很有必要的,但是 组 的数目足够大,以至于用 P P P 组生成所有可能的分区将会花费很大的代价。在这种情况下, GroupShuffleSplit 通过 LeavePGroupsOut 提供了一个随机(可重复)的训练 / 测试划分采样。

26.2.4 预定义的折叠 / 验证集

对一些数据集,一个预定义的,将数据划分为训练和验证集合或者划分为几个交叉验证集合的划分已经存在。 可以使用 PredefinedSplit 来使用这些集合来搜索超参数。

比如,当使用验证集合时,设置所有验证集合中的样例的 test_fold 为 0,而将其他样例设置为 -1 。

26.2.5 交叉验证在时间序列数据中应用

时间序列数据的特点是时间 (autocorrelation(自相关性)) 附近的观测之间的相关性。 然而,传统的交叉验证技术,例如 KFoldShuffleSplit 假设样本是独立的且分布相同的,并且在时间序列数据上会导致训练和测试实例之间不合理的相关性(产生广义误差的估计较差)。 因此,对 “future(未来)” 观测的时间序列数据模型的评估至少与用于训练模型的观测模型非常重要。为了达到这个目的,一个解决方案是由 TimeSeriesSplit 提供的。

26.2.5.1 时间序列分割

TimeSeriesSplitk-fold 的一个变体,它首先返回 k k k 折作为训练数据集,并且 ( k + 1 ) (k+1) (k+1) 折作为测试数据集。 请注意,与标准的交叉验证方法不同,连续的训练集是超越前者的超集。 另外,它将所有的剩余数据添加到第一个训练分区,它总是用来训练模型。

这个类可以用来交叉验证以固定时间间隔观察到的时间序列数据样本。

对具有 6 个样本的数据集进行 3-split 时间序列交叉验证的示例:

>>> from sklearn.model_selection import TimeSeriesSplit>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])
>>> y = np.array([1, 2, 3, 4, 5, 6])
>>> tscv = TimeSeriesSplit(n_splits=3)
>>> print(tscv)  
TimeSeriesSplit(max_train_size=None, n_splits=3)
>>> for train, test in tscv.split(X):
...     print("%s  %s" % (train, test))
[0 1 2] [3]
[0 1 2 3] [4]
[0 1 2 3 4] [5]

26.3 A note on shuffling

如果数据的顺序不是任意的(比如说,相同标签的样例连续出现),为了获得有意义的交叉验证结果,首先对其进行 打散是很有必要的。然而,当样例不是独立同分布时打散则是不可行的。例如:样例是相关的文章,以他们发表的时间 进行排序,这时候如果对数据进行打散,将会导致模型过拟合,得到一个过高的验证分数:因为验证样例更加相似(在时间上更接近) 于训练数据。

一些交叉验证迭代器, 比如 KFold ,有一个内建的在划分数据前进行数据索引打散的选项。注意:

  • 这种方式仅需要很少的内存就可以打散数据。
  • 默认不会进行打散,包括设置 cv=some_integer (直接)k 折叠交叉验证的 cross_val_score , 表格搜索等。注意 train_test_split 会返回一个随机的划分。
  • 参数 random_state 默认设置为 None ,这意为着每次进行 KFold(..., shuffle=True) 时,打散都是不同的。 然而, GridSearchCV 通过调用 fit 方法验证时,将会使用相同的打散来训练每一组参数。
  • 为了保证结果的可重复性(在相同的平台上),应该给 random_state 设定一个固定的值。

26.4 交叉验证和模型选择

交叉验证迭代器可以通过网格搜索得到最优的模型超参数,从而直接用于模型的选择。 这是另一部分 调整估计器的超参数 的主要内容。

相关文章:

2024-12-29-sklearn学习(26)模型选择与评估-交叉验证:评估估算器的表现 今夜偏知春气暖,虫声新透绿窗纱。

文章目录 sklearn学习(26) 模型选择与评估-交叉验证&#xff1a;评估估算器的表现26.1 计算交叉验证的指标26.1.1 cross_validate 函数和多度量评估26.1.2 通过交叉验证获取预测 26.2 交叉验证迭代器26.2.1 交叉验证迭代器–循环遍历数据26.2.1.1 K 折26.2.1.2 重复 K-折交叉验…...

Spring Boot + MinIO 实现分段、断点续传,让文件传输更高效

一、引言 在当今的互联网应用中&#xff0c;文件上传是一个常见的功能需求。然而&#xff0c;传统的文件上传方式在面对大文件或不稳定的网络环境时&#xff0c;可能会出现性能瓶颈和上传失败的问题。 传统文件上传&#xff0c;就像是用一辆小推车搬运大型家具&#xff0c;一…...

获取用户详细信息-ThreadLocal优化

Thread全局接口可用&#xff0c;不用再重复编写。所以为了代码的复用&#xff0c;使用Thread。把之前的内容&#xff08;函数的参数和map与username&#xff09;注释掉&#xff0c;换为Thread传过来的内容&#xff08;map与username&#xff09;。 因为Thread需要在拦截器里面…...

R语言6种将字符转成数字的方法,写在新年来临之际

咱们临床研究中&#xff0c;拿到数据后首先要对数据进行清洗&#xff0c;把数据变成咱们想要的格式&#xff0c;才能进行下一步分析&#xff0c;其中数据中的字符转成数字是个重要的内容&#xff0c;因为字符中常含有特殊符号&#xff0c;不利于分析&#xff0c;转成数字后才能…...

Go语言方法和接收器类型详解

Go语言方法和接收器类型详解 1. 方法接收器类型 1.1 值接收器 值接收器方法不会改变接收器的状态&#xff0c;因为Go语言会在调用时复制接收器的值。因此&#xff0c;任何对接收器成员变量的修改都只会影响副本&#xff0c;而不会影响原始结构体实例。 type Person struct …...

Linux常用命令总结

目录 查询java服务的pid查询pid上的进程占用的端口方法 1&#xff1a;使用 lsof 查询端口方法 2&#xff1a;使用 netstat 查询端口方法 3&#xff1a;使用 ss 命令查询端口 system相关命令 查询java服务的pid JPS查询pid上的进程占用的端口 要根据进程 ID&#xff08;PID&am…...

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录

Linux总结之CentOS Stream 9安装mysql8.0实操安装成功记录 由于网上很多的mysql8.0安装教程都是老版本或者安装过程记录有问题&#xff0c;导致经常安装到一半需要删除重新安装。所以将成功的实操安装过程记录一下&#xff0c;方面后面查阅&#xff0c;大家还有问题的可以在此讨…...

ROS2软件架构全面解析-学习如何设计通信中间件框架

前言 ROS&#xff08;Robot Operating System&#xff09; 2 是一个用于开发机器人应用的软件平台&#xff0c;也称为机器人软件开发工具包 (SDK)。 ROS2是ROS1的迭代升级版本 &#xff0c;最主要的升级点是引入DDS&#xff08;Data Distribution Service&#xff09;为基础的…...

基于微信小程序的校园自助打印系统

博主介绍&#xff1a;java高级开发&#xff0c;从事互联网行业六年&#xff0c;熟悉各种主流语言&#xff0c;精通java、python、php、爬虫、web开发&#xff0c;已经做了多年的设计程序开发&#xff0c;开发过上千套设计程序&#xff0c;没有什么华丽的语言&#xff0c;只有实…...

Linux命令——3.网络与用户

文章目录 一、网络1.网络测试与诊断2.网络接口配置3.无线网络配置4.防火墙与网络管理6.防火墙管理1&#xff09;firewalld命令2&#xff09;iptables命令 二、用户和群组1.管理员模式2.用户账户管理1&#xff09;useradd创建2&#xff09;usermod修改3&#xff09;userdel 删除…...

2、redis的持久化

redis的持久化 在redist当中&#xff0c;高可用的技术包括持久化&#xff0c;主从复制&#xff0c;哨兵模式&#xff0c;集群。 持久化是最简单的高可用的方法&#xff0c;作用就是备份数据。即将数据保存到硬盘&#xff0c;防止进程退出导致数据丢失。 redis持久化方式&…...

建造者模式 Builder Pattern

在创建一个对象的时候&#xff0c;构造器参数有点多&#xff0c;而且有些参数还是可选的&#xff0c;再者还有不少同类型的&#xff0c;那就更应该使用 builder 模式了。 使用 Builder 模式的初衷是 把易变性&#xff08;mutability&#xff09;移动到Builder类&#xff0c;而…...

制作一个类似ChatGPT的AI对话网站,模型能力使用ChatGPT

要快速搭建一个类似ChatGPT的AI对话网站&#xff0c;并且使用类似ChatGPT的模型能力&#xff0c;可以考虑以下技术和工具&#xff1a; ### 1. **使用现有的AI模型平台** - **OpenAI API**: 如果你希望使用类似于ChatGPT的能力&#xff0c;OpenAI提供了强大的API服务&#xff08…...

LinuxC高级day2

1.在家目录下创建目录文件&#xff0c;dir a.dir下创建dir1和dir2 b.把当前目录下的所有文件拷贝到dir1中&#xff0c; c.把当前目录下的所有脚本文件拷贝到dir2中 d.把dir2打包并压缩为dir2.tar.xz e.再把dir2.tar.xz移动到dir1中 f.解压dir1中的压缩包 g.使用tree工具&#x…...

Word格式修改

经常修改格式&#xff0c;留下这篇汇总 Word的累加符号上下标变右标指定目录&#xff1a;word如何取消封面或者目录下方的页码&#xff0c;页码从正文开始加参考文献&#xff1a;【Word】怎样给论文添加引用参考文献删空白页&#xff1a; word中无法删除空白页怎么办&#xff…...

深度学习-稀疏卷积

步骤&#xff1a; 1、构建输入输出哈希表&#xff1b; 输入哈希表的键为激活点的索引&#xff0c;值为激活点的坐标&#xff1b;输出哈希表的键为激活点对应的输出点的索引&#xff0c;值为输出点的坐标。 2、构建规则书&#xff1b; 规则书的每一行包含4个值&#xff0c;分别是…...

Microsoft Visual Studio中的/MT, /MTd,/MD,/MDd分别是什么意思?

1. /MT&#xff0c;/MTd&#xff0c;/MD&#xff0c;/MDd的含义 /MT&#xff0c;/MTd&#xff0c;/MD&#xff0c;/MDd是 Microsoft Visual C 编译器的运行时库链接选项。它们决定了程序如何链接 C 运行时库&#xff08;CRT&#xff09;。具体含义如下&#xff1a; /MT&#x…...

交换机关于环路、接口绑定、链路聚合的相关知识

文章目录 1、对交换机SW-1进行配置&#xff0c;仅允许Host-1通过Ethernet0/0/1接口与Host-3和Host-4通信&#xff0c;Host-2无法与其他主机通信。2、关闭生成树协议&#xff0c;验证环路造成的影响3、关闭生成树协议通过链路聚合实现两条链路正常通信并提高链路可靠性。 内容包…...

5.微服务灰度发布落地实践(rocketmq增强)

文章目录 前言发送端灰度增强订阅端灰度增强 前言 上一篇分析了&#xff0c;在灰度发布实现中为什么要对消息队列灰度发布进行增强。本篇主要介绍如何实现rocketmq 灰度发布的增强. 发送端灰度增强 订阅端灰度增强...

32单片机从入门到精通之开发环境——库文件(六)

每个人都有自己的追求和梦想&#xff0c;但要实现这些梦想并不容易。在追逐梦想的路上&#xff0c;我们会遇到各种困难和挫折&#xff0c;甚至会感到无助和失望。然而&#xff0c;正是这些困难和挫折让我们更加坚韧和坚定地追求自己的目标。不要害怕失败&#xff0c;失败只是暂…...

大电流和大电压采样电路

大电压采样电路&#xff1a; 需要串联多个电阻进行分压&#xff0c;从而一级一级降低电压&#xff0c;防止电阻损坏或者短路直接打穿MCU。 为什么需要加电压跟随器&#xff1a;进行阻抗的隔离&#xff0c;防止MCU的IO阻抗对分压产生影响&#xff1a; 大电流检测电路&#xff…...

用户态和内核态?

目录 一、定义与特点 二、功能与权限差异 三、安全性与稳定性 四、系统调用与交互 五、参考 用户态和内核态是操作系统中的两种基本运行状态&#xff0c;它们各自具有不同的特点和权限&#xff0c;共同构成了操作系统的运行基础。以下是对用户态和内核态的详细解释&#x…...

Qt天气预报系统设计界面布局第四部分左边

Qt天气预报系统设计 1、第四部分左边的第一部分1.1添加控件1.2修改控件名字 2、第四部分左边的第二部分2.1添加控件2.2修改控件名字 3、第四部分左边的第三部分3.1添加控件3.2修改控件名字 4、对整个widget04l调整 1、第四部分左边的第一部分 1.1添加控件 拖入一个widget&…...

【Spring MVC 常用注解】注解驱动开发的魔法

在 Spring MVC 中&#xff0c;注解可以说是开发者的“魔法棒”&#xff0c;通过简单的注解配置&#xff0c;开发者能够实现请求处理、参数绑定、响应返回等复杂功能&#xff0c;真正做到“少写代码多干活”。 我们接下来就来一起看看 Spring MVC 中常用的注解&#xff0c;它们的…...

FFmpeg 4.3 音视频-多路H265监控录放C++开发二十一.4,SDP协议分析

SDP在4566 中有详细描述。 SDP 全称是 Session Description Protocol&#xff0c; 翻译过来就是描述会话的协议。 主要用于两个会话实体之间的媒体协商。 什么叫会话呢&#xff0c;比如一次网络电话、一次电话会议、一次视频聊天&#xff0c;这些都可以称之为一次会话。 那为什…...

STM32 高级 WIFi案例1:测试AT指令

需求描述 测试AT指令是否能够正常控制ESP32的wifi&#xff0c;比如重启、读取设备信息等。 思路&#xff1a; stm32通过串口usart2向ESP32发布命令。ESP32通过串口1返回信息。 配置&#xff1a; 第一步&#xff1a;对ESP32芯片烧录可以读取stm32命令的固件&#xff08;fac…...

Mono里运行C#脚本18—mono_image_load_names

前面已经分析完成加载CLR的流表,接着下来就是使用前面分析的数据,更进一步来处理了。下面就是通过函数mono_image_load_names获得程序集的名称和模块名称。 在CLI定义的文档里,表Assembly : 0x20: Assembly表结构信息,以下是该表各列的简要说明: HashAlgId: 这是一个4字…...

Java和Python区别: 应用领域与性能抉择的深度解析

文章目录 1. 引言2. 语言特性对比&#xff1a;灵活性与严谨性的碰撞3. 应用场景分析&#xff1a;专注任务的工具选择3.1 数据库交互&#xff1a;Java 的优势所在3.2 图像识别与计算&#xff1a;Python 的专长3.3 Web 开发 4. 高并发请求处理&#xff1a;架构设计与硬件选择4.1 …...

SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者

SQL Server详细使用教程(包含启动SQL server服务、建立数据库、建表的详细操作) 非常适合初学者 文章目录 目录 前言 一、启动SQL server服务的三种方法 1.不启动SQL server服务的影响 2.方法一&#xff1a;利用cmd启动SQL server服务 3.方法二&#xff1a;利用SQL Serv…...

基于Docker+模拟器的Appium自动化测试(二)

模拟器的设置 打开“夜神模拟器”的系统设置&#xff0c;切换到“手机与网络”页&#xff0c;选中网络设置下的“开启网络连接”和“开启网络桥接模式”复选框&#xff0c;而后选择“静态IP”单选框&#xff0c;在IP地址中输入“192.168.0.105”&#xff0c;网关等内容不再赘述…...

CSS系列(47)-- Animation Timeline详解

前端技术探索系列&#xff1a;CSS Animation Timeline详解 ⏱️ 致读者&#xff1a;探索动画时间线的艺术 &#x1f44b; 前端开发者们&#xff0c; 今天我们将深入探讨 CSS Animation Timeline&#xff0c;这个强大的动画控制特性。 基础概念 &#x1f680; 时间线定义 …...

1、pycharm、python下载与安装

1、去官网下载pycharm 官网&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows 2、在等待期间&#xff0c;去下载python 进入官网地址&#xff1a;https://www.python.org/downloads/windows/ 3、安装pycharm 桌面会出现快捷方式 4、安装python…...

【翻译】优化加速像素着色器执行的方法

中文翻译 在回复我的 Twitter 私信时,我遇到了一个关于如何提高像素/片段着色器执行速度的问题。这是一个相当广泛的问题,具体取决于每个 GPU/平台和游戏内容的特性,但我在本帖中扩展了我“头脑风暴”式的回答,以便其他人也觉得有用。这不是一份详尽的清单,更像是一个高层…...

ZLib库使用详细教程 以及标准ZLib函数和QT自带压缩函数比较

1. 下载Zlib 官网下载地址如下&#xff1a;http://www.zlib.net/ 2. 利用cmake编译zlib 有两种方法可以打开cmake-gui winR输入cmd打开命令行&#xff0c;在命令行中输入cmake-gui可以直接打开应用界面找到你一开始安装cmake的文件夹&#xff0c;在bin子文件夹中双击cmake-…...

android stdudio环境: gradle一直安装失败

一、一直显示如下错误 The specified Gradle distribution file:/home/wangqingyuan/.gradle/wrapper/dists/gradle-8.6-bin/gradle-8.6-bin.zip does not exist. 经分析&#xff0c;是因为应用本身设置了gradle版本的地址为本地&#xff1a; 应用目录&#xff1a;gradle/gra…...

2024年12月31日Github流行趋势

项目名称&#xff1a;free-programming-books 项目地址url&#xff1a;https://github.com/EbookFoundation/free-programming-books项目语言&#xff1a;HTML历史star数&#xff1a;344575今日star数&#xff1a;432项目维护者&#xff1a;vhf, eshellman, davorpa, MHM5000, …...

音视频入门基础:MPEG2-TS专题(24)——FFmpeg源码中,显示TS流每个packet的pts、dts的实现

音视频入门基础&#xff1a;MPEG2-TS专题系列文章&#xff1a; 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;1&#xff09;——MPEG2-TS官方文档下载 音视频入门基础&#xff1a;MPEG2-TS专题&#xff08;2&#xff09;——使用FFmpeg命令生成ts文件 音视频入门基础…...

设计模式の状态策略责任链模式

文章目录 前言一、状态模式二、策略模式三、责任链模式 前言 本篇是关于设计模式中的状态模式、策略模式、以及责任链模式的学习笔记。 一、状态模式 状态模式是一种行为设计模式&#xff0c;核心思想在于&#xff0c;使某个对象在其内部状态改变时&#xff0c;改变该对象的行为…...

TI毫米波雷达原始数据解析之Lane数据交换

TI毫米波雷达原始数据解析之Lane数据交换 背景Lane 定义Lane 确认确认LVDS Lane 数量的Matlab 代码数据格式参考 背景 解析使用mmWave Studio 抓取的ADC Data Lane 定义 芯片与DCA100之间的数据使用LVDS接口传输&#xff0c;使用mmWave Studio 配置过程中有一个选项是LVDS L…...

Python-Pdf转Markdown

使用pdfminer.sixmarkdownify pdfminer.six可以提取Pdf文本内容markdownify可以将文本内容写markdown文件 安装 pip install pdfminer.six pip install markdownify实现 from pdfminer.high_level import extract_text from markdownify import markdownifydef pdf2markdo…...

win32汇编环境下,双击窗口程序内生成的listview列表控件的某行,并提取其内容的示例程序

;运行效果 ;双击后 ;上源码&#xff0c;仔细研究里面的几条备注就理解原理了 ;提取窗口程序内生成的listview列表控件的内容示例程序 ;抄下面源码&#xff0c;可以在radasm里面直接编译运行。主要的部分加了备注。 ;>>>>>>>>>>>>>>…...

对45家“AI+安全”产品/方案的分析

一. 关键洞察 “AI+安全”创新非常活跃,一片百家争鸣之势,赛道选择上,以事件分诊Incident Triage、 安全辅助Security Copilots、自动化Automation三者为主为主,这充分反映了当前安全运营的主要需求,在产品理念选择上以 AI 和 自动化为主,这确实又切合上了在关键…...

家用电器销售系统|Java|SSM|JSP|

【技术栈】 1⃣️&#xff1a;架构: B/S、MVC 2⃣️&#xff1a;系统环境&#xff1a;Windowsh/Mac 3⃣️&#xff1a;开发环境&#xff1a;IDEA、JDK1.8、Maven、Mysql5.7 4⃣️&#xff1a;技术栈&#xff1a;Java、Mysql、SSM、Mybatis-Plus、JSP、jquery,html 5⃣️数据库可…...

小程序租赁系统构建指南与市场机会分析

内容概要 在当今竞争激烈的市场环境中&#xff0c;小程序租赁系统正崭露头角&#xff0c;成为企业转型与创新的重要工具。通过这个系统&#xff0c;商户能够快速推出自己的小程序&#xff0c;无需从头开发&#xff0c;节省了大量时间和资金。让我们来看看这个系统的核心功能吧…...

《XML Schema 字符串数据类型》

《XML Schema 字符串数据类型》 1. 引言 XML Schema 是一种用于描述和验证 XML 文档结构和内容的语言。在 XML Schema 中&#xff0c;字符串数据类型是一种基本的数据类型&#xff0c;用于表示文本数据。本文将详细介绍 XML Schema 中的字符串数据类型&#xff0c;包括其定义…...

探索框架领域的新兴技术:微框架与插件化框架的崛起

近年来&#xff0c;随着软件开发技术的快速发展&#xff0c;开发者对框架的需求也在不断变化。从传统的重量级框架到轻量级微框架&#xff0c;以及支持高度扩展性的插件化框架&#xff0c;技术生态系统日新月异。本文旨在介绍这些新兴框架技术中的一些小众但创新的理念与实现&a…...

【数据结构-单调队列】力扣2762. 不间断子数组

给你一个下标从 0 开始的整数数组 nums 。nums 的一个子数组如果满足以下条件&#xff0c;那么它是 不间断 的&#xff1a; i&#xff0c;i 1 &#xff0c;…&#xff0c;j 表示子数组中的下标。对于所有满足 i < i1, i2 < j 的下标对&#xff0c;都有 0 < |nums[i1…...

【复盘】2024年终总结

工作 重构风控系统 今年上半年其实就是整体重构系统&#xff0c;经历了多次加班的&#xff0c;其中的辛酸苦辣只有自己知道&#xff0c;现在来看的话&#xff0c;其实对自己还有一定的成长&#xff0c;从这件事情上也明白 绩效能不能拿到A&#xff0c;在分配的任务的时候就决…...

QT 学习第十四天 QWidget布局

QT 学习十四天 布局 布局管理Qt Widgets 布局布局管理器简介基本布局管理器栅格布局管理器窗体布局管理器综合使用布局管理器设置部件大小可扩展窗口 布局管理 今天讲 Qt Widgets 和 Qt Quick 中的布局。 前者主要用布局管理器 后者除了布局管理器还有基于锚的布局&#xff08…...

各个Spring Cloud版本有何主要差异

Spring Cloud 的各个版本之间确实存在一些关键差异&#xff0c;这些差异主要体现在功能更新、性能优化、对新技术的支持以及对旧有技术的替代等方面。 1. Spring Cloud Dalston 这是 Spring Cloud 的一个早期版本&#xff0c;它提供了微服务架构所需的基本组件&#xff0c;如服…...