Come rimuovere sistematicamente variabili collineari in Python? [chiuso]


17

Finora ho rimosso le variabili collineari come parte del processo di preparazione dei dati guardando le tabelle di correlazione ed eliminando le variabili che si trovano al di sopra di una certa soglia. Esiste un modo più accettato di farlo? Inoltre, sono consapevole che guardare solo la correlazione tra 2 variabili alla volta non è l'ideale, misurazioni come VIF tengono conto della potenziale correlazione tra più variabili. Come si potrebbe scegliere sistematicamente combinazioni variabili che non presentano multicollinearità?

Ho i miei dati all'interno di un frame di dati Panda e sto usando i modelli di sklearn.


3
Si consiglia di considerare la regressione dei minimi quadrati parziali o la regressione dei componenti principali. Uno di questi è probabilmente supportato.
spdrnl,

Vedo. Quindi, se ho capito bene, l'esecuzione di PCA mi darebbe quindi un insieme di componenti principali indipendenti, che potrei quindi utilizzare come covariate per il mio modello, dal momento che ciascuno dei componenti principali non è coerente con gli altri?
orange1

2
Esattamente. È probabile che alcuni dei componenti risultino irrilevanti. Questo è più facile che eliminare le variabili.
spdrnl,

Hm, quindi la mia intenzione è principalmente quella di eseguire il modello per scopi esplicativi piuttosto che predittivi. Come si potrebbe interpretare un modello che utilizzava i componenti principali come covariate?
orange1

1
In quel caso non aiuta poiché l'interpretazione dei componenti è in qualche modo un'arte oscura.
spdrnl,

Risposte:


13

Grazie SpanishBoy - È un buon pezzo di codice. @ilanman: controlla i valori VIF e quindi elimina le variabili il cui VIF è superiore a 5. Per "performance", penso che significhi runtime. Il codice sopra mi ha richiesto circa 3 ore per funzionare su circa 300 variabili, 5000 righe.

A proposito, l'ho modificato per rimuovere alcuni loop extra. Inoltre, l'ho reso un po 'più pulito e restituito il frame di dati con variabili ridotte. Questa versione ha dimezzato il mio tempo di esecuzione! Il mio codice è sotto - Spero che sia d'aiuto.

from statsmodels.stats.outliers_influence import variance_inflation_factor    

def calculate_vif_(X, thresh=5.0):
    variables = list(range(X.shape[1]))
    dropped = True
    while dropped:
        dropped = False
        vif = [variance_inflation_factor(X.iloc[:, variables].values, ix)
               for ix in range(X.iloc[:, variables].shape[1])]

        maxloc = vif.index(max(vif))
        if max(vif) > thresh:
            print('dropping \'' + X.iloc[:, variables].columns[maxloc] +
                  '\' at index: ' + str(maxloc))
            del variables[maxloc]
            dropped = True

    print('Remaining variables:')
    print(X.columns[variables])
    return X.iloc[:, variables]

Grazie. Hai confrontato gli output di entrambe le funzioni? Ho visto una funzione R ( usdmmetodo del pacchetto vifstep) per VIF e il tempo di esecuzione è stato davvero fantastico. Come ho detto prima, la variante sopra e la tua (ottimizzata della metà) sono così lente nel confronto con la R. Qualche altra idea su come ottimizzare ancora?
SpanishBoy,

1
Ho una domanda su questo approccio. Diciamo che abbiamo le funzionalità A, B e C. A è correlato a C. Se si passa in rassegna le funzionalità, A e C avranno VIF> 5, quindi verranno eliminate. In realtà, non dovresti ricalcolare il VIF dopo ogni rilascio di una funzione. Nel mio esempio elimineresti sia A che C, ma se calcoli VIF (C) dopo che A è stato rilasciato, non sarà> 5
Titus Pullo,

3

Puoi provare a usare il codice seguente:

from statsmodels.stats.outliers_influence import variance_inflation_factor

def calculate_vif_(X):

    '''X - pandas dataframe'''
    thresh = 5.0
    variables = range(X.shape[1])

    for i in np.arange(0, len(variables)):
        vif = [variance_inflation_factor(X[variables].values, ix) for ix in range(X[variables].shape[1])]
        print(vif)
        maxloc = vif.index(max(vif))
        if max(vif) > thresh:
            print('dropping \'' + X[variables].columns[maxloc] + '\' at index: ' + str(maxloc))
            del variables[maxloc]

    print('Remaining variables:')
    print(X.columns[variables])
    return X

Funziona, ma non mi piace l'esecuzione di questo approccio


Vuoi commentare un po 'di più su ciò che fa questo approccio? E perché non ti piace la performance?
ilanman,

2

Ho provato la risposta di SpanishBoy e ho trovato errori serval durante l'esecuzione per un frame di dati. Ecco una soluzione di debug.

from statsmodels.stats.outliers_influence import variance_inflation_factor    

def calculate_vif_(X, thresh=100):
cols = X.columns
variables = np.arange(X.shape[1])
dropped=True
while dropped:
    dropped=False
    c = X[cols[variables]].values
    vif = [variance_inflation_factor(c, ix) for ix in np.arange(c.shape[1])]

    maxloc = vif.index(max(vif))
    if max(vif) > thresh:
        print('dropping \'' + X[cols[variables]].columns[maxloc] + '\' at index: ' + str(maxloc))
        variables = np.delete(variables, maxloc)
        dropped=True

print('Remaining variables:')
print(X.columns[variables])
return X[cols[variables]]

Inoltre non ho avuto problemi con le prestazioni, ma non l'ho testato ampiamente.


questo è carino e funziona per me. tranne, restituisce l'avvertimento ominious:RuntimeWarning: divide by zero encountered in double_scalars
user2205916
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.