在 GroupKFold
来源中, random_state
设置为None
def __init__(self, n_splits=3):
super(GroupKFold, self).__init__(n_splits, shuffle=False,
random_state=None)
因此,多次运行时(代码来自here)
import numpy as np
from sklearn.model_selection import GroupKFold
for i in range(0,10):
X = np.array([[1, 2], [3, 4], [5, 6], [7, 8]])
y = np.array([1, 2, 3, 4])
groups = np.array([0, 0, 2, 2])
group_kfold = GroupKFold(n_splits=2)
group_kfold.get_n_splits(X, y, groups)
print(group_kfold)
for train_index, test_index in group_kfold.split(X, y, groups):
print("TRAIN:", train_index, "TEST:", test_index)
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
print(X_train, X_test, y_train, y_test)
print
print
O / P
GroupKFold(n_splits=2)
('TRAIN:', array([0, 1]), 'TEST:', array([2, 3]))
(array([[1, 2],
[3, 4]]), array([[5, 6],
[7, 8]]), array([1, 2]), array([3, 4]))
('TRAIN:', array([2, 3]), 'TEST:', array([0, 1]))
(array([[5, 6],
[7, 8]]), array([[1, 2],
[3, 4]]), array([3, 4]), array([1, 2]))
GroupKFold(n_splits=2)
('TRAIN:', array([0, 1]), 'TEST:', array([2, 3]))
(array([[1, 2],
[3, 4]]), array([[5, 6],
[7, 8]]), array([1, 2]), array([3, 4]))
('TRAIN:', array([2, 3]), 'TEST:', array([0, 1]))
(array([[5, 6],
[7, 8]]), array([[1, 2],
[3, 4]]), array([3, 4]), array([1, 2]))
等等......
分裂是相同的。
如何为random_state
设置GroupKFold
,以便在几个不同的交叉验证试验中获得不同(但可重复)的拆分集?
例如,我想要
GroupKFold(n_splits=2, random_state=42)
('TRAIN:', array([0, 1]),
'TEST:', array([2, 3]))
('TRAIN:', array([2, 3]),
'TEST:', array([0, 1]))
GroupKFold(n_splits=2, random_state=13)
('TRAIN:', array([0, 2]),
'TEST:', array([1, 3]))
('TRAIN:', array([1, 3]),
'TEST:', array([0, 2]))
到目前为止,似乎策略可能是首先使用sklearn.utils.shuffle
,如post中所述。然而,这实际上只是重新排列每个折叠的元素 - 它不会给我们新的分裂。
from sklearn.utils import shuffle
from sklearn.model_selection import GroupKFold
import numpy as np
import sys
import pdb
random_state = int(sys.argv[1])
X = np.arange(20).reshape((10,2))
y = np.arange(10)
groups = np.array([0,0,0,1,2,3,4,5,6,7])
def cv(X, y, groups, random_state):
X_s, y_s, groups_s = shuffle(X,y, groups, random_state=random_state)
cv_out = GroupKFold(n_splits=2)
cv_out_splits = cv_out.split(X_s, y_s, groups_s)
for train, test in cv_out_splits:
print "---"
print X_s[test]
print y_s[test]
print "test groups", groups_s[test]
print "train groups", groups_s[train]
pdb.set_trace()
print "***"
cv(X, y, groups, random_state)
输出:
>python sshuf.py 32
***
---
[[ 2 3]
[ 4 5]
[ 0 1]
[ 8 9]
[12 13]]
[1 2 0 4 6]
test groups [0 0 0 2 4]
train groups [7 6 1 3 5]
---
[[18 19]
[16 17]
[ 6 7]
[10 11]
[14 15]]
[9 8 3 5 7]
test groups [7 6 1 3 5]
train groups [0 0 0 2 4]
>python sshuf.py 234
***
---
[[12 13]
[ 4 5]
[ 0 1]
[ 2 3]
[ 8 9]]
[6 2 0 1 4]
test groups [4 0 0 0 2]
train groups [7 3 1 5 6]
---
[[18 19]
[10 11]
[ 6 7]
[14 15]
[16 17]]
[9 5 3 7 8]
test groups [7 3 1 5 6]
train groups [4 0 0 0 2]
答案 0 :(得分:8)
KFold
仅在shuffle=True
时才被随机化。 Some datasets should not be shuffled. GroupKFold
根本没有随机化。因此random_state=None
。GroupShuffleSplit
可能更接近您所寻找的内容。基于群组的分割者的比较:
GroupKFold
中,测试集形成了所有数据的完整分区。LeavePGroupsOut
组合出所有可能的P组子集;对于P> 1,测试集将重叠。 1.由于这意味着P ** n_groups
完全分裂,通常你需要一个小P,并且通常需要LeaveOneGroupOut
,这与GroupKFold
与k=1
基本相同。GroupShuffleSplit
没有说明连续测试集之间的关系;每个列车/测试拆分都是独立完成的。顺便说一下,
Dmytro Lituiev has proposed an alternative GroupShuffleSplit
algorithm更适合在指定test_size
的测试集中获取正确数量的样本(不仅仅是正确数量的组)。
答案 1 :(得分:1)
random_state
依赖_iter_test_masks( ... random_state = None )
方法,
正如科幻小说super(...)
来源中自我记录的那样。实例化中使用的random_state
参数(.__init__()
是
"只是"存储并留给用户的创造力,如果它将以test_mask
代的任何定制方式使用或不会被使用(如在科学家来源评论中字面表达的那样):
(CIT:)
# Since subclasses must implement either _iter_test_masks or
# _iter_test_indices, neither can be abstract.
def _iter_test_masks(self, X=None, y=None, groups=None):
"""Generates boolean masks corresponding to test sets.
By default, delegates to _iter_test_indices(X, y, groups)
"""
for test_index in self._iter_test_indices(X, y, groups):
test_mask = np.zeros(_num_samples(X), dtype=np.bool)
test_mask[test_index] = True
yield test_mask
定义一个依赖外部提供的进程random_state != None
也应该执行一个公平的做法来保护 - 保存/存储RNG的实际当前状态(RNG_stateTUPLE = numpy.random.get_state()
),设置从.__init__()
调用接口,完成后,从保存的(numpy.random.set_state( RNG_stateTUPLE )
)恢复RNG状态。
这样一种自定义过程既可以获得random_state
值所需的依赖性,也可以获得可重复性。
的 Q.E.D。强>
答案 2 :(得分:1)
到目前为止,我的解决方案是简单地随机拆分组。这可能导致非常不平衡的群体(我认为GroupKFold
旨在抵御),但希望每组的观察数量很少。
from sklearn.utils import shuffle
from sklearn.model_selection import GroupKFold
from numpy.random import RandomState
import numpy as np
import sys
import pdb
random_state = int(sys.argv[1])
X = np.arange(20).reshape((10,2))
y = np.arange(10)
groups = np.array([0,0,0,1,2,3,4,5,6,7])
for el in zip(range(len(y)),X,y,groups):
print "ix, X, y, groups", el
def RandGroupKfold(groups, n_splits, random_state=None, shuffle_groups=False):
ix = np.array(range(len(groups)))
unique_groups = np.unique(groups)
if shuffle_groups:
prng = RandomState(random_state)
prng.shuffle(unique_groups)
splits = np.array_split(unique_groups, n_splits)
train_test_indices = []
for split in splits:
mask = [el in split for el in groups]
train = ix[np.invert(mask)]
test = ix[mask]
train_test_indices.append((train, test))
return train_test_indices
splits = RandGroupKfold(groups, n_splits=3, random_state=random_state, shuffle_groups=True)
for train, test in splits:
print "---"
for el in zip(train, X[train], y[train], groups[train]):
print "train ix, X, y, groups", el
for el in zip(test, X[test], y[test], groups[test]):
print "test ix, X, y, groups", el
数据:
ix, X, y, groups (0, array([0, 1]), 0, 0)
ix, X, y, groups (1, array([2, 3]), 1, 0)
ix, X, y, groups (2, array([4, 5]), 2, 0)
ix, X, y, groups (3, array([6, 7]), 3, 1)
ix, X, y, groups (4, array([8, 9]), 4, 2)
ix, X, y, groups (5, array([10, 11]), 5, 3)
ix, X, y, groups (6, array([12, 13]), 6, 4)
ix, X, y, groups (7, array([14, 15]), 7, 5)
ix, X, y, groups (8, array([16, 17]), 8, 6)
ix, X, y, groups (9, array([18, 19]), 9, 7)
随机状态为4
---
train ix, X, y, groups (0, array([0, 1]), 0, 0)
train ix, X, y, groups (1, array([2, 3]), 1, 0)
train ix, X, y, groups (2, array([4, 5]), 2, 0)
train ix, X, y, groups (3, array([6, 7]), 3, 1)
train ix, X, y, groups (4, array([8, 9]), 4, 2)
train ix, X, y, groups (7, array([14, 15]), 7, 5)
train ix, X, y, groups (8, array([16, 17]), 8, 6)
test ix, X, y, groups (5, array([10, 11]), 5, 3)
test ix, X, y, groups (6, array([12, 13]), 6, 4)
test ix, X, y, groups (9, array([18, 19]), 9, 7)
---
train ix, X, y, groups (4, array([8, 9]), 4, 2)
train ix, X, y, groups (5, array([10, 11]), 5, 3)
train ix, X, y, groups (6, array([12, 13]), 6, 4)
train ix, X, y, groups (8, array([16, 17]), 8, 6)
train ix, X, y, groups (9, array([18, 19]), 9, 7)
test ix, X, y, groups (0, array([0, 1]), 0, 0)
test ix, X, y, groups (1, array([2, 3]), 1, 0)
test ix, X, y, groups (2, array([4, 5]), 2, 0)
test ix, X, y, groups (3, array([6, 7]), 3, 1)
test ix, X, y, groups (7, array([14, 15]), 7, 5)
---
train ix, X, y, groups (0, array([0, 1]), 0, 0)
train ix, X, y, groups (1, array([2, 3]), 1, 0)
train ix, X, y, groups (2, array([4, 5]), 2, 0)
train ix, X, y, groups (3, array([6, 7]), 3, 1)
train ix, X, y, groups (5, array([10, 11]), 5, 3)
train ix, X, y, groups (6, array([12, 13]), 6, 4)
train ix, X, y, groups (7, array([14, 15]), 7, 5)
train ix, X, y, groups (9, array([18, 19]), 9, 7)
test ix, X, y, groups (4, array([8, 9]), 4, 2)
test ix, X, y, groups (8, array([16, 17]), 8, 6)
随机状态为5
---
train ix, X, y, groups (0, array([0, 1]), 0, 0)
train ix, X, y, groups (1, array([2, 3]), 1, 0)
train ix, X, y, groups (2, array([4, 5]), 2, 0)
train ix, X, y, groups (3, array([6, 7]), 3, 1)
train ix, X, y, groups (5, array([10, 11]), 5, 3)
train ix, X, y, groups (7, array([14, 15]), 7, 5)
train ix, X, y, groups (8, array([16, 17]), 8, 6)
test ix, X, y, groups (4, array([8, 9]), 4, 2)
test ix, X, y, groups (6, array([12, 13]), 6, 4)
test ix, X, y, groups (9, array([18, 19]), 9, 7)
---
train ix, X, y, groups (4, array([8, 9]), 4, 2)
train ix, X, y, groups (5, array([10, 11]), 5, 3)
train ix, X, y, groups (6, array([12, 13]), 6, 4)
train ix, X, y, groups (8, array([16, 17]), 8, 6)
train ix, X, y, groups (9, array([18, 19]), 9, 7)
test ix, X, y, groups (0, array([0, 1]), 0, 0)
test ix, X, y, groups (1, array([2, 3]), 1, 0)
test ix, X, y, groups (2, array([4, 5]), 2, 0)
test ix, X, y, groups (3, array([6, 7]), 3, 1)
test ix, X, y, groups (7, array([14, 15]), 7, 5)
---
train ix, X, y, groups (0, array([0, 1]), 0, 0)
train ix, X, y, groups (1, array([2, 3]), 1, 0)
train ix, X, y, groups (2, array([4, 5]), 2, 0)
train ix, X, y, groups (3, array([6, 7]), 3, 1)
train ix, X, y, groups (4, array([8, 9]), 4, 2)
train ix, X, y, groups (6, array([12, 13]), 6, 4)
train ix, X, y, groups (7, array([14, 15]), 7, 5)
train ix, X, y, groups (9, array([18, 19]), 9, 7)
test ix, X, y, groups (5, array([10, 11]), 5, 3)
test ix, X, y, groups (8, array([16, 17]), 8, 6)
答案 3 :(得分:1)
受到user0的answer(无法评论)的启发,但速度更快:
def RandomGroupKFold_split(groups, n, seed=None): # noqa: N802
"""
Random analogous of sklearn.model_selection.GroupKFold.split.
:return: list of (train, test) indices
"""
groups = pd.Series(groups)
ix = np.arange(len(groups))
unique = np.unique(groups)
np.random.RandomState(seed).shuffle(unique)
result = []
for split in np.array_split(unique, n):
mask = groups.isin(split)
train, test = ix[~mask], ix[mask]
result.append((train, test))
return result
答案 4 :(得分:0)
我想组合k组的代码,还希望训练和测试集中的班级比例相同。因此,我在各组上进行了k倍分层,以便在折痕中保持相同的类别比率,然后使用这些组在折痕中放置样本。我还将随机种子包括在分层中以解决不同的拆分问题。
def Stratified_Group_KFold(Y, groups, n, seed=None):
unique = np.unique(groups)
group_Y = []
for group in unique:
y = Y[groups.index(subject)]
group_Y.append(y)
group_X = np.zeros_like(unique)
skf_group = StratifiedKFold(n_splits = n, random_state = seed, shuffle=True)
result = []
for train_index, test_index in skf_group.split(group_X, group_Y):
train_groups_in_fold = unique[train_index]
test_groups_in_fold = unique[test_index]
train = np.in1d(groups, train_groups_in_fold).nonzero()[0]
test = np.in1d(groups, test_groups_in_fold).nonzero()[0]
result.append((train, test))
return result
答案 5 :(得分:0)
@ user0
例如,我想要
GroupKFold(n_splits=2, random_state=42) ('TRAIN:', array([0, 1]), 'TEST:', array([2, 3])) ('TRAIN:', array([2, 3]), 'TEST:', array([0, 1])) GroupKFold(n_splits=2, random_state=13) ('TRAIN:', array([0, 2]), 'TEST:', array([1, 3])) ('TRAIN:', array([1, 3]), 'TEST:', array([0, 2]))
第二次拆分会将一组分为训练集和测试集。这是GroupKFold应该避免的。例如,在第二个拆分中,来自训练组0和组1的元素(数据集中的索引0和1)分别作为索引0和1。
对于您给出的示例,进行分组2倍拆分的方法不止一种,因为您只有2组。
答案 6 :(得分:0)
GroupKFold
根据组标签显示确定性。所以解决方案是分配新标签。我通过改组唯一组标识符列表并从 0 到 n_groups - 1 分配新标签来解决这个问题。
import numpy as np
from sklearn.model_selection import GroupKFold
def get_random_labels(labels, random_state):
labels_shuffled = np.unique(labels)
# shuffle works in place
random_state.shuffle(labels_shuffled)
new_labels_mapping = {k: i for i, k in enumerate(labels_shuffled)}
new_labels = np.array([new_labels_mapping[label] for label in labels])
reverse_dict = {v: k for k, v in new_labels_mapping.items()}
return new_labels, reverse_dict
random_state = np.random.RandomState(41)
X = np.arange(20).reshape((10, 2))
y = np.arange(10)
groups = np.array([0, 0, 0, 1, 2, 3, 4, 5, 6, 7])
for _ in range(0, 5):
group_kfold = GroupKFold(n_splits=2)
new_labels, reverse_dict = get_random_labels(groups, random_state)
print(group_kfold)
for i, (train_index, test_index) in enumerate(group_kfold.split(X, y, new_labels)):
X_train, X_test = X[train_index], X[test_index]
y_train, y_test = y[train_index], y[test_index]
groups_train, groups_test = groups[train_index], groups[test_index]
print("Split no.", i + 1, "Training y:", y_train, "Testing y:", y_test)
print()
输出:
GroupKFold(n_splits=2)
Split no. 1 Training y: [3 4 5 6 8] Testing y: [0 1 2 7 9]
Split no. 2 Training y: [0 1 2 7 9] Testing y: [3 4 5 6 8]
GroupKFold(n_splits=2)
Split no. 1 Training y: [3 4 7 8 9] Testing y: [0 1 2 5 6]
Split no. 2 Training y: [0 1 2 5 6] Testing y: [3 4 7 8 9]
GroupKFold(n_splits=2)
Split no. 1 Training y: [3 6 7 8 9] Testing y: [0 1 2 4 5]
Split no. 2 Training y: [0 1 2 4 5] Testing y: [3 6 7 8 9]
GroupKFold(n_splits=2)
Split no. 1 Training y: [5 6 7 8 9] Testing y: [0 1 2 3 4]
Split no. 2 Training y: [0 1 2 3 4] Testing y: [5 6 7 8 9]
GroupKFold(n_splits=2)
Split no. 1 Training y: [3 4 6 7 9] Testing y: [0 1 2 5 8]
Split no. 2 Training y: [0 1 2 5 8] Testing y: [3 4 6 7 9]
在 10 个样本中,我让前三个属于第 0 组,其他每个都属于自己独特的组。结果就是每次迭代分裂都不一样。
reverse_dict
对象用于获取原始标签的身份。