Python 如何分割测试和训练数据,使每个类中至少有一个类

Python 如何分割测试和训练数据,使每个类中至少有一个类,python,pandas,machine-learning,scikit-learn,classification,Python,Pandas,Machine Learning,Scikit Learn,Classification,我有一些相当不平衡的数据,我正试图分类。 然而,它的分类相当好 为了准确评估效果,我必须将数据分成训练和测试子集 现在,我通过非常简单的方法来实现这一点: import numpy as np corpus = pandas.DataFrame(..., columns=["data","label"]) # My data, simplified train_index = np.random.rand(len(corpus))>0.2 training_data = corpus[tr

我有一些相当不平衡的数据,我正试图分类。 然而,它的分类相当好

为了准确评估效果,我必须将数据分成训练和测试子集

现在,我通过非常简单的方法来实现这一点:

import numpy as np
corpus = pandas.DataFrame(..., columns=["data","label"]) # My data, simplified
train_index = np.random.rand(len(corpus))>0.2
training_data = corpus[train_index]
test_data = corpus[np.logical_not(train_index)]
这很简单,但有些类很少出现: 在50000多个病例的语料库中,约有15个病例每次发生不到100次,其中两个仅发生一次

我希望将我的数据集划分为测试和培训子集,以便:

  • 如果一个类出现的次数少于两次,则它将从这两个类中排除
  • 在测试和培训中,每节课至少进行一次
  • 分为测试和培训是随机的
我可以做点什么, (最简单的方法可能是移除发生次数少于2次的东西),然后重新取样,直到唾液两边都有),但我想知道是否有一种干净的方法已经存在


我认为这样做不行,但它的存在表明sklearn可能具有这种功能。

以下内容满足将数据划分为测试和培训的3个条件:

#get rid of items with fewer than 2 occurrences.
corpus=corpus[corpus.groupby('label').label.transform(len)>1]

from sklearn.cross_validation import StratifiedShuffleSplit
sss=StratifiedShuffleSplit(corpus['label'].tolist(), 1, test_size=0.5, random_state=None)

train_index, test_index =list(*sss)
training_data=corpus.iloc[train_index]
test_data=corpus.iloc[test_index]
我使用以下虚构的数据帧测试了上述代码:

#create random data with labels 0 to 39, then add 2 label case and one label case.     
corpus=pd.DataFrame({'data':np.random.randn(49998),'label':np.random.randint(40,size=49998)})
corpus.loc[49998]=[random.random(),40]
corpus.loc[49999]=[random.random(),40]
corpus.loc[50000]=[random.random(),41]
它在测试代码时生成以下输出:

test_data[test_data['label']==40]
Out[110]: 
           data  label
49999  0.231547     40

training_data[training_data['label']==40]
Out[111]: 
           data  label
49998  0.253789     40

test_data[test_data['label']==41]
Out[112]: 
Empty DataFrame
Columns: [data, label]
Index: []

training_data[training_data['label']==41]
Out[113]: 
Empty DataFrame
Columns: [data, label]
Index: []

而forloop不应该:它应该是
train\u索引,test\u index=list(*splitter);train_data=common_corpus.iloc[train_index,:];test_data=common_corpus.iloc[test_index,:]
你说得对@oxiabox这是一种更干净的方法。如果对数据进行多次拆分,则循环对于
StratifiedShuffleSplit()
中大于1的
n\u iter
值非常有用。我将使用您建议的替换项修改答案。它不应该是
iloc
而不是
loc
,因此如果索引不是一个简单的范围,它就可以正常工作?
iloc
是更好的答案,我修改了答案以反映这一点。谢谢