Como remover sistematicamente variáveis ​​colineares em Python? [fechadas]

17

Até o momento, removi variáveis ​​colineares como parte do processo de preparação de dados, observando as tabelas de correlação e eliminando as variáveis ​​que estão acima de um determinado limite. Existe uma maneira mais aceita de fazer isso? Além disso, estou ciente de que apenas analisar a correlação entre duas variáveis ​​por vez não é o ideal, medições como o VIF levam em consideração a correlação potencial entre várias variáveis. Como alguém escolheria sistematicamente combinações de variáveis ​​que não exibem multicolinearidade?

Eu tenho meus dados dentro de um quadro de dados do pandas e estou usando os modelos do sklearn.

orange1
fonte
3
Você pode considerar a regressão de mínimos quadrados parciais ou a regressão de componentes principais. Um deles provavelmente é suportado.
Spdrnl
Entendo. Portanto, se eu entendi direito, a execução do PCA me forneceria um conjunto de componentes principais independentes, que eu poderia usar como covariáveis ​​para o meu modelo, já que cada um dos componentes principais não é colinear com os outros?
#
2
Exatamente. É provável que alguns dos componentes se tornem irrelevantes. Isso é mais fácil do que eliminar variáveis.
Spdnl #
Hum, então minha intenção é principalmente executar o modelo para fins explicativos, e não preditivos. Como interpretar um modelo que usasse componentes principais como covariáveis?
#
1
Nesse caso, não ajuda, pois a interpretação de componentes é uma arte sombria.
Spdnl #

Respostas:

13

Obrigado SpanishBoy - É um bom pedaço de código. @ilanman: Isso verifica os valores VIF e descarta variáveis ​​cujo VIF é maior que 5. Por "desempenho", acho que ele quer dizer tempo de execução. O código acima levou cerca de 3 horas para executar em cerca de 300 variáveis, 5000 linhas.

A propósito, eu o modifiquei para remover alguns loops extras. Além disso, eu o tornei um pouco mais limpo e retornei o quadro de dados com variáveis ​​reduzidas. Esta versão reduziu meu tempo de execução pela metade! Meu código está abaixo - Espero que ajude.

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]
Prashant
fonte
Obrigado. Você comparou as saídas de ambas as funções? Eu vi uma função R ( usdmmétodo de pacote vifstep) para VIF e o tempo de execução foi muito legal. Como eu disse antes, a variante acima e a sua (otimizada pela metade) são tão lentas em comparação com a R. Alguma outra idéia de como otimizar ainda?
precisa saber é o seguinte
1
Eu tenho uma pergunta sobre essa abordagem. Digamos que temos recursos A, B e C. A está correlacionado com C. Se você percorrer os recursos, A e C terão VIF> 5, portanto, eles serão descartados. Na realidade, você não deveria recalcular o VIF depois de cada vez que solta um recurso. No meu exemplo você dropb ambos A e C, mas se você calcular VIF (C) após um cair, não vai ser> 5
Titus Pullo
3

Você pode tentar usar o código abaixo:

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

Funciona, mas não gosto do desempenho dessa abordagem

Espanhol
fonte
Deseja comentar um pouco mais sobre o que essa abordagem faz? E por que você não gosta da performance?
ilanman
2

Tentei a resposta do SpanishBoy e encontrei erros de serval ao executá-lo para um quadro de dados. Aqui está uma solução depurada.

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

Também não tive problemas com o desempenho, mas não o testei extensivamente.

Braden Fineberg
fonte
isso é legal e funciona para mim. exceto que ele retorna o aviso RuntimeWarning: divide by zero encountered in double_scalars
ameaçador