2015-12-02 10 views
7

Sto cercando di utilizzare Patsy (con sklearn, panda) per creare un modello di regressione semplice. La creazione della formula in stile R è una grande attrazione.Patsy: nuovi livelli nei campi categoriali nei dati di test

miei dati contiene un campo denominato 'ship_city' che può avere qualsiasi città dall'India. Dato che sto partizionando i dati in set di treni e test, ci sono diverse città che appaiono solo in uno dei set. Un frammento di codice è il seguente:

df_train_Y, df_train_X = dmatrices(formula, data=df_train, return_type='dataframe') 
df_train_Y_design_info, df_train_X_design_info = df_train_Y.design_info, df_train_X.design_info 
df_test_Y, df_test_X = build_design_matrices([df_train_Y_design_info.builder, df_train_X_design_info.builder], df_test, return_type='dataframe') 

L'ultima riga lancia il seguente errore:

patsy.PatsyError: Error converting data to categorical: observation with value 'Kolkata' does not match any of the expected levels

Credo che questo sia un caso d'uso molto comune in cui i dati di allenamento non avranno tutti i livelli di tutti i campi categoriali . Sklearn's DictVectorizer gestisce questo abbastanza bene.

C'è un modo per farlo funzionare con Patsy?

risposta

0

Mi sono imbattuto in un problema simile e ho creato le matrici di progetto prima di dividere i dati.

df_Y, df_X = dmatrices(formula, data=df, return_type='dataframe') 
df_train_X, df_test_X, df_train_Y, df_test_Y = \ 
    train_test_split(df_X, df_Y, test_size=test_size) 

Poi come esempio di applicazione di una misura:

model = smf.OLS(df_train_Y, df_train_X) 
model2 = model.fit() 
predicted = model2.predict(df_test_X) 

Tecnicamente non hanno costruito un banco di prova, ma non hanno eseguito nell'errore Error converting data to categorical nuovamente dato attuazione sopra.

+0

Sì, è possibile una soluzione alternativa. Ma il problema con questo approccio è che ora ci sono perdite dal set di prova al set di allenamento. Idealmente, al momento della formazione, non dovremmo utilizzare alcuna informazione dai dati del test che non fa già parte dei dati di allenamento. In questo modo simuliamo nei nostri test cosa accadrà in realtà nella produzione. Per fare un esempio dalla mia domanda precedente, se ci sono città che conoscerò solo in produzione, non sarà corretto (in realtà nemmeno possibile) includere tali città come colonne nei miei dati usati per addestrare il modello. Spero che sia chiaro. – DaSarfyCode

+0

Vedo la tua preoccupazione. Detto questo, sono a conoscenza del fatto che la mia risposta non perderà informazioni nel senso di fornire ulteriori informazioni durante l'allenamento. Rende semplicemente il modello compatibile con altri elementi nel set di dati. In R, ciò equivale a regolare i livelli senza modificare i dati. Se la presenza di città non disponibili è alta nel modello, allora forse la combinazione di città per formare un modello più inclusivo sarebbe la strada da seguire; ma questo tende al design del modello, separato dalla tua domanda sulla compatibilità del test e del set di allenamento. – timctran

+0

Ad esempio, supponiamo di avere dati su tre città A, B, C.E in produzione ci sarà una quarta città D e una quinta città E. Quindi in questo caso forse l'approccio sarebbe fittizio codificare su A, B, C, così che non essere A, B o C è un'altra città. Tuttavia, non potremmo aspettarci che il modello funzioni in modo ottimale poiché raggrupperebbe tutte le città invisibili. Potremmo invece progettare variabili come city_population (numerica o categoriale: sm, med, lg), city_density, ecc. E mappare ogni città alle sue caratteristiche. Il modello può quindi essere applicato a città non presenti nel set di dati originale. – timctran

3

Il problema, naturalmente, è che se si dà un semplice elenco di valori, non ha modo di sapere che ci sono altri valori che potrebbero potenzialmente accadere. Devi in ​​qualche modo dirgli quale sia l'insieme completo di valori possibili.

Un modo è quello di utilizzare l'argomento levels= a C(...), come:

# If you have a data frame with all the data before splitting: 
all_cities = sorted(df_all["Cities"].unique()) 
# Alternative approach: 
all_cities = sorted(set(df_train["Cities"]).union(set(df_test["Cities"]))) 

dmatrices("y ~ C(Cities, levels=all_cities)", data=df_train) 

Un'altra opzione se si sta utilizzando per i panda predefinito categorical support è quello di record the set of possible values when you set up your data frame; se patsy rileva che l'oggetto che hai passato è un categorico panda, allora utilizza automaticamente l'attributo delle categorie panda invece di cercare di indovinare quali sono le possibili categorie guardando i dati.

+1

Apprezzo la risposta, ma si imbatte nello stesso problema affrontato dalla risposta di timctran. Prima di mettere in produzione, non conosceremo tutti i possibili livelli che incontreremo. Il numero di città e città in India è semplicemente troppo grande per includere un modello. Prima di tutto non esiste un elenco completo di questi luoghi. E che ci crediate o no, quelli nuovi continuano a spuntare. E _cities_ è solo uno di questi esempi comunque. – DaSarfyCode

+0

Beh, cosa vuoi che succeda in questo caso? Hai lasciato a Patsy una matrice che ha fatto crescere nuove colonne rispetto alla matrice originale? Cosa farai con loro? –

+0

Come ho accennato nella domanda, ritengo che Dictectector di sklearn lo gestisca bene. Non genera un errore. Dice solo al modello che "ecco un disco che non corrisponde a nessun valore della città che abbia mai visto prima". Segna solo tutte le colonne esistenti come 0. Ho appena pensato che Patsy sia una libreria matura, gestisce anche questo caso d'uso molto comune. Ma a quanto pare non è così. – DaSarfyCode