sklearn中StratifiedKFold和StratifiedShuffleSplit的区别

78

从标题上来看,我想知道 StratifiedKFold 参数中 shuffle=True 和不加这个参数的区别是什么。

StratifiedKFold(n_splits=10, shuffle=True, random_state=0)

并且

分层随机分割

StratifiedShuffleSplit(n_splits=10, test_size=’default’, train_size=None, random_state=0)

使用StratifiedShuffleSplit的好处是什么?


2
在 StratifiedShuffleSplit 中,您可以设置拆分次数。从 sklearn 网页:StratifiedShuffleSplit:这个交叉验证对象是 StratifiedKFold 和 ShuffleSplit 的合并,返回分层随机折叠。折叠是通过保留每个类别样本的百分比来完成的。 - gabboshow
啊,是我不好。但是你提供的 StratifiedShuffleSplit 文档中仍然写着:“这个交叉验证对象是 StratifiedKFold 和 ShuffleSplit 的合并,它返回分层随机折叠。折叠是通过保留每个类别样本的百分比来生成的。” - Vivek Kumar
5
折叠交叉验证的差异在于,每个折叠中的数据不会重叠。而在StratifiedShuffleSplit中,数据可以且可能会重叠。请参考文档页面上给出的示例以更好地理解它,特别是测试数据。在StratifiedKFold中,每个折叠中的测试数据总是不同的,而在StratifiedShuffleSplit中则可能重复。 - Vivek Kumar
那么如果我必须在两者之间进行选择,我应该选择StratifiedKFold,不是吗?我没有看到使用StratifiedShuffleSplit的优势...但是应该有,因为它是sklearn的更近期的函数...这就是我想知道的。 - gabboshow
1
听起来像是StratifiedKFold无重复抽样,而StratifiedShuffleSplit则会进行洗牌。因此,StratifiedShuffleSplit的一个优点是您可以随意抽样多次。当然,个别样本将会有重叠--因此,在样本上拟合的任何模型都将是相关的--但您可以拟合更多的模型,并且每个模型的数据更多。 - william_grisaitis
让我们这样考虑。StratifiedKFold 是真正的交叉验证。然而,StratifiedShuffleSplit 是一个“生成器”,它会随机生成不同的“训练-测试”拆分,重复 n_splits 次。 - Bs He
3个回答

105

stratKFolds 中,即使包含 shuffle,每个测试集也不应有重叠。使用 stratKFoldsshuffle=True,数据在开始时洗牌一次,然后分成所需的拆分数量。测试数据始终是其中一个拆分,训练数据是其余的拆分。

ShuffleSplit 中,数据每次都会被洗牌,然后再拆分。这意味着测试集可能会在拆分之间重叠。

请参见此代码块以了解差异示例。注意 ShuffleSplit 中测试集元素的重叠。

splits = 5

tx = range(10)
ty = [0] * 5 + [1] * 5

from sklearn.model_selection import StratifiedShuffleSplit, StratifiedKFold
from sklearn import datasets

stratKfold = StratifiedKFold(n_splits=splits, shuffle=True, random_state=42)
shufflesplit = StratifiedShuffleSplit(n_splits=splits, random_state=42, test_size=2)

print("stratKFold")
for train_index, test_index in stratKfold.split(tx, ty):
    print("TRAIN:", train_index, "TEST:", test_index)

print("Shuffle Split")
for train_index, test_index in shufflesplit.split(tx, ty):
    print("TRAIN:", train_index, "TEST:", test_index)

输出:

stratKFold
TRAIN: [0 2 3 4 5 6 7 9] TEST: [1 8]
TRAIN: [0 1 2 3 5 7 8 9] TEST: [4 6]
TRAIN: [0 1 3 4 5 6 8 9] TEST: [2 7]
TRAIN: [1 2 3 4 6 7 8 9] TEST: [0 5]
TRAIN: [0 1 2 4 5 6 7 8] TEST: [3 9]
Shuffle Split
TRAIN: [8 4 1 0 6 5 7 2] TEST: [3 9]
TRAIN: [7 0 3 9 4 5 1 6] TEST: [8 2]
TRAIN: [1 2 5 6 4 8 9 0] TEST: [3 7]
TRAIN: [4 6 7 8 3 5 1 2] TEST: [9 0]
TRAIN: [7 2 6 5 4 3 0 9] TEST: [1 8]

关于何时使用它们,我倾向于在进行任何交叉验证时使用stratKFolds,并且我使用 ShuffleSplit 将数据集分成2份用作训练/测试集。但我相信两者还有其他用例。


1
+1 针对您出色的回答。请问,您能否回答我的问题 - Md. Sabbir Ahmed

80
@Ken Syme已经给出了非常好的答案,我只想补充一些内容。
  • StratifiedKFoldKFold的一个变体。首先,StratifiedKFold会对您的数据进行洗牌,然后将数据分成n_splits份。现在,它将使用每个部分作为测试集。请注意,它仅会在拆分之前随机洗牌一次数据

使用 shuffle = True,数据将由您的random_state进行洗牌。否则,数据将由np.random(默认值)进行洗牌。 例如,当n_splits = 4,并且您的数据有3个类别(标签)用于y(因变量)时。4个测试集可以覆盖所有数据而不重叠。

enter image description here

另一方面,{{StratifiedShuffleSplit}}是{{ShuffleSplit}}的变体。首先,{{StratifiedShuffleSplit}}对数据进行洗牌,然后将数据分成{{n_splits}}个部分。但这还不够。在这一步之后,{{StratifiedShuffleSplit}}选择一个部分作为测试集。然后它重复相同的过程{{n_splits-1}}次,以获取{{n_splits-1}}个其他测试集。看下面的图片,使用相同的数据,但这次4个测试集并没有涵盖所有数据,即测试集之间存在重叠。

enter image description here

因此,这里的区别在于StratifiedKFold仅随机洗牌并分割一次,因此测试集不会重叠,而StratifiedShuffleSplit在每次分割之前都会随机洗牌,并分割n_splits次,测试集可能会重叠。
注意:这两种方法使用“分层折叠”(因此两个名称中都出现了“分层”一词)。这意味着每个部分保留与原始数据相同的每个类别(标签)样本的百分比。您可以在交叉验证文档中阅读更多信息。

8
完美的解释!! - Atendra Gautam

15

KFold、StratifiedKFold和StratifiedShuffleSplit的输出示例:

KFold、StratifiedKFold和StratifiedShuffleSplit 的输出示例

上述图片输出是对@Ken Syme代码的扩展:

from sklearn.model_selection import KFold, StratifiedKFold, StratifiedShuffleSplit
SEED = 43
SPLIT = 3

X_train = [0,1,2,3,4,5,6,7,8]
y_train = [0,0,0,0,0,0,1,1,1]   # note 6,7,8 are labelled class '1'

print("KFold, shuffle=False (default)")
kf = KFold(n_splits=SPLIT, random_state=SEED)
for train_index, test_index in kf.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)

print("KFold, shuffle=True")
kf = KFold(n_splits=SPLIT, shuffle=True, random_state=SEED)
for train_index, test_index in kf.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)

print("\nStratifiedKFold, shuffle=False (default)")
skf = StratifiedKFold(n_splits=SPLIT, random_state=SEED)
for train_index, test_index in skf.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)
    
print("StratifiedKFold, shuffle=True")
skf = StratifiedKFold(n_splits=SPLIT, shuffle=True, random_state=SEED)
for train_index, test_index in skf.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)
    
print("\nStratifiedShuffleSplit")
sss = StratifiedShuffleSplit(n_splits=SPLIT, random_state=SEED, test_size=3)
for train_index, test_index in sss.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)

print("\nStratifiedShuffleSplit (can customise test_size)")
sss = StratifiedShuffleSplit(n_splits=SPLIT, random_state=SEED, test_size=2)
for train_index, test_index in sss.split(X_train, y_train):
    print("TRAIN:", train_index, "TEST:", test_index)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接