Jak systematycznie usuwać zmienne współliniowe w Pythonie? [Zamknięte]


18

Do tej pory usunąłem zmienne współliniowe w ramach procesu przygotowania danych, patrząc na tabele korelacji i eliminując zmienne, które przekraczają pewien próg. Czy istnieje bardziej akceptowany sposób na zrobienie tego? Ponadto jestem świadomy, że patrzenie tylko na korelację między 2 zmiennymi jednocześnie nie jest idealne, pomiary takie jak VIF uwzględniają potencjalną korelację między kilkoma zmiennymi. Jak można systematycznie wybierać kombinacje zmiennych, które nie wykazują wielokoliniowości?

Mam swoje dane w ramce danych pand i używam modeli sklearn.


3
Warto rozważyć regresję częściowych najmniejszych kwadratów lub regresję głównych składników. Jeden z nich jest prawdopodobnie obsługiwany.
— spdrnl

Widzę. Więc jeśli dobrze rozumiem, uruchomienie PCA dałoby mi wtedy zestaw niezależnych głównych komponentów, których mógłbym następnie użyć jako zmiennych towarzyszących dla mojego modelu, ponieważ każdy z głównych komponentów nie jest współliniowy z innymi?
— orange1

2
Dokładnie. Niektóre elementy mogą okazać się nieistotne. Jest to łatwiejsze niż usuwanie zmiennych.
— spdrnl

Hm, więc moim zamiarem jest przede wszystkim uruchomienie modelu w celach wyjaśniających niż przewidywalnych. Jak zająłby się interpretacja modelu, w którym główne komponenty byłyby zmiennymi towarzyszącymi?
— orange1

1
W takim przypadku nie pomaga, ponieważ interpretacja komponentów jest poniekąd czarną sztuką.
— spdrnl

Odpowiedzi:


13

Dzięki SpanishBoy - To dobry kawałek kodu. @ilanman: Sprawdza wartości VIF, a następnie upuszcza zmienne, których VIF jest większy niż 5. Przez „wydajność” myślę, że ma na myśli czas działania. Powyższy kod zajął mi około 3 godzin, aby uruchomić na około 300 zmiennych, 5000 wierszy.

Nawiasem mówiąc, zmodyfikowałem go, aby usunąć dodatkowe pętle. Poza tym sprawiłem, że jest trochę czystszy i zwracam ramkę danych ze zredukowanymi zmiennymi. Ta wersja skróciła mój czas działania o połowę! Mój kod jest poniżej - Mam nadzieję, że to pomaga.

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]

Dziękuję Ci. Czy porównałeś wyniki obu funkcji? Widziałem funkcję R ( usdmmetoda pakietowa vifstep) dla VIF, a czas działania był naprawdę fajny. Jak powiedziałem wcześniej, powyższy wariant i twój (zoptymalizowany o połowę) są tak powolni w porównaniu z R. Czy są jeszcze inne pomysły na optymalizację?
— SpanishBoy

1
Mam pytanie dotyczące tego podejścia. Powiedzmy, że mamy funkcje A, B i C. A jest skorelowane z C. Jeśli przejdziesz przez funkcje, A i C będą miały VIF> 5, a zatem zostaną upuszczone. W rzeczywistości nie powinieneś ponownie obliczać VIF po każdym upuszczeniu funkcji. W moim przykładzie spadłbyś zarówno A, jak i C, ale jeśli obliczysz VIF (C) po upuszczeniu A, to nie będzie> 5
— Titus Pullo

3

Możesz spróbować użyć poniższego kodu:

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

Działa, ale nie podoba mi się wydajność tego podejścia


Czy chcesz komentować nieco więcej na temat tego, co robi to podejście? A dlaczego nie lubisz występu?
— ilanman

2

Próbowałem odpowiedzi SpanishBoy i znalazłem serwal błędy, uruchamiając ją dla ramki danych. Oto debugowane rozwiązanie.

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]]

Nie miałem również problemów z wydajnością, ale nie przetestowałem go dokładnie.


to jest miłe i działa dla mnie. z wyjątkiem, że zwraca złowieszcze ostrzeżenie:RuntimeWarning: divide by zero encountered in double_scalars
— user2205916
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.