Як систематично видаляти колінеарні змінні в Python? [зачинено]


18

Поки що я видалив колінеарні змінні як частину процесу підготовки даних, переглянувши таблиці кореляції та усунувши змінні, що перевищують певний поріг. Чи є більш прийнятий спосіб зробити це? Крім того, я усвідомлюю, що лише перегляд кореляції між двома змінними одночасно не є ідеальним, вимірювання типу VIF враховують потенційну кореляцію у кількох змінних. Як би можна було систематично вибирати змінні комбінації, які не виявляють мультиколінеарності?

Я маю свої дані в межах даних панди і використовую моделі sklearn.


3
Ви можете розглянути питання про часткову регресію найменших квадратів або регресію основних компонентів. Одне з них, ймовірно, підтримується.
spdrnl

Я бачу. Отже, якщо я правильно розумію, запуск PCA надав би мені набір незалежних основних компонентів, які я можу потім використовувати як коваріати для своєї моделі, оскільки кожен з основних компонентів не співпадає з іншими?
помаранчевий1

2
Саме так. Деякі компоненти, ймовірно, виявляться неактуальними. Це простіше, ніж викидати змінні.
spdrnl

Гм, тому мій намір полягає в першу чергу запустити модель для пояснювальних, а не прогностичних цілей. Як можна було б інтерпретувати модель, яка використовувала основні компоненти як коваріати?
помаранчевий1

1
У цьому випадку це не допомагає, оскільки інтерпретація компонентів є дещо темним мистецтвом.
spdrnl

Відповіді:


13

Спасибі SpanishBoy - це хороший фрагмент коду. @ilanman: Це перевіряє значення VIF, а потім відміняє змінні, VIF яких перевищує 5. Під "продуктивністю" я думаю, що він означає час виконання. Вищеописаний код знадобився мені близько 3 годин, щоб працювати на 300 змінних, 5000 рядків.

До речі, я його змінив, щоб видалити кілька зайвих циклів. Крім того, я зробив це трохи більш чистим і повернути кадр даних зі зменшеними змінними. Ця версія скоротила мій час роботи вдвічі! Мій код нижче - сподіваюся, що це допомагає.

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]

Дякую. Чи порівняли ви результати обох функцій? Я побачив функцію R (пакетний usdmметод vifstep) для VIF, і час роботи був дуже класним. Як я вже говорив раніше, варіант вище та ваш (оптимізований наполовину) настільки повільний у порівнянні з Р. Будь-які інші ідеї, як оптимізувати ще?
SpanishBoy

1
У мене є питання щодо такого підходу. Скажімо, ми маємо особливості A, B і C. A співвідноситься з C. Якщо ви перейдете через функції, A і C матимуть VIF> 5, отже, вони будуть скинуті. Насправді, чи не слід повторно обчислювати VIF після кожного виходу функції. У моєму прикладі ви б опустили і A, і C, але якщо ви обчислите VIF (C) після того, як A буде скинуто, це не буде> 5
Titus Pullo

3

Ви можете спробувати використовувати код нижче:

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

Це працює, але мені не подобається виконання такого підходу


Ви хочете трохи прокоментувати те, що робить цей підхід? І чому ви не любите виступ?
іланман

2

Я спробував відповідь SpanishBoy і виявив помилки сервалу, коли запускав його для кадру даних. Ось налагоджене рішення.

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

У мене також не було проблем з продуктивністю, але не перевіряв її широко.


це приємно і працює для мене. окрім того, воно повертає зловісне попередження:RuntimeWarning: divide by zero encountered in double_scalars
user2205916
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.