2013-05-08 8 views
6

Esiste un modo integrato per far sì che lo scikit impari a eseguire una convalida incrociata di k-fold stratificata mescolata? Questo è uno dei metodi CV più comuni e sono sorpreso di non riuscire a trovare un metodo integrato per farlo.Convalida incrociata stratificata k-fold randomizzata in scikit-learn?

Ho visto che cross_validation.KFold() ha una bandiera mescolata, ma non è stratificata. Sfortunatamente cross_validation.StratifiedKFold() non ha questa opzione e cross_validation.StratifiedShuffleSplit() non produce pieghe disgiunte.

mi sto perdendo qualcosa? È pianificato?

(ovviamente posso realizzare questo da me)

risposta

-3

Per quanto ne so, questo è in realtà implementato in scikit-learn.

""" stratificato ShuffleSplit validazione incrociata iteratore

Fornisce indici treno/test per dividere i dati in set di test treni.

Questo oggetto convalida incrociata è una fusione di StratifiedKFold e ShuffleSplit, che restituisce pieghe stratificate e randomizzate: le pieghe vengono conservate mantenendo la percentuale di campioni per ogni classe

Nota: come la strategia ShuffleSplit, le suddivisioni casuali stratificate non garantiscono che tutte le piegature siano diverse, sebbene questo sia ancora molto probabile per i set di dati di dimensioni considerevoli. """

+0

Come ho scritto nella mia interrogazione, StratifiedShuffleSplit() non fa una versione mescolata di StratifiedKFold(), ovvero mischiare prima di StratifiedKFold(). Questo è anche menzionato nell'ultima frase della tua risposta. KFold CV richiede che non ci sia intersezione tra le pieghe e che la loro unione sia l'intero set di dati. – Bitwise

+0

Ah, sì, le pieghe non sono garantite. Scusa per non aver letto fino alla fine della tua domanda .. – rd108

+0

Dovresti cancellare la tua risposta! Per favore... – Merlin

2

ho pensato di postare la mia soluzione nel caso in cui è utile a chiunque altro

from collections import defaultdict 
import random 
def strat_map(y): 
    """ 
    Returns permuted indices that maintain class 
    """ 
    smap = defaultdict(list) 
    for i,v in enumerate(y): 
     smap[v].append(i) 
    for values in smap.values(): 
     random.shuffle(values) 
    y_map = np.zeros_like(y) 
    for i,v in enumerate(y): 
     y_map[i] = smap[v].pop() 
    return y_map 

########## 
#Example Use 
########## 
skf = StratifiedKFold(y, nfolds) 
sm = strat_map(y) 
for test, train in skf: 
    test,train = sm[test], sm[train] 
    #then cv as usual 


####### 
#tests# 
####### 
import numpy.random as rnd 
for _ in range(100): 
    y = np.array([0]*10 + [1]*20 + [3] * 10) 
    rnd.shuffle(y) 
    sm = strat_map(y) 
    shuffled = y[sm] 
    assert (sm != range(len(y))).any() , "did not shuffle" 
    assert (shuffled == y).all(), "classes not in right position" 
    assert (set(sm) == set(range(len(y)))), "missing indices" 


for _ in range(100): 
    nfolds = 10 
    skf = StratifiedKFold(y, nfolds) 
    sm = strat_map(y) 
    for test, train in skf: 
     assert (sm[test] != test).any(), "did not shuffle" 
     assert (y[sm[test]] == y[test]).all(), "classes not in right position" 
1

Qui è la mia realizzazione di stratificato diviso riordino in formazione e testing set:

import numpy as np 

def get_train_test_inds(y,train_proportion=0.7): 
    '''Generates indices, making random stratified split into training set and testing sets 
    with proportions train_proportion and (1-train_proportion) of initial sample. 
    y is any iterable indicating classes of each observation in the sample. 
    Initial proportions of classes inside training and 
    test sets are preserved (stratified sampling). 
    ''' 

    y=np.array(y) 
    train_inds = np.zeros(len(y),dtype=bool) 
    test_inds = np.zeros(len(y),dtype=bool) 
    values = np.unique(y) 
    for value in values: 
     value_inds = np.nonzero(y==value)[0] 
     np.random.shuffle(value_inds) 
     n = int(train_proportion*len(value_inds)) 

     train_inds[value_inds[:n]]=True 
     test_inds[value_inds[n:]]=True 

    return train_inds,test_inds 


y = np.array([1,1,2,2,3,3]) 
train_inds,test_inds = get_train_test_inds(y,train_proportion=0.5) 
print y[train_inds] 
print y[test_inds] 

Questo uscite di codice:

[1 2 3] 
[1 2 3]