Bagaimana cara menghapus variabel collinear secara sistematis di Python? [Tutup]

17

Sejauh ini, saya telah menghapus variabel linier sebagai bagian dari proses persiapan data dengan melihat tabel korelasi dan menghilangkan variabel yang berada di atas ambang batas tertentu. Apakah ada cara yang lebih diterima untuk melakukan ini? Selain itu, saya menyadari bahwa hanya melihat korelasi antara 2 variabel pada suatu waktu tidak ideal, pengukuran seperti VIF memperhitungkan potensi korelasi antar beberapa variabel. Bagaimana orang pergi secara sistematis memilih kombinasi variabel yang tidak menunjukkan multikolinieritas?

Saya memiliki data saya dalam bingkai data panda dan saya menggunakan model sklearn.

oranye1
sumber
3
Anda mungkin ingin mempertimbangkan Regresi Kotak Terkecil Sebagian atau Regresi Komponen Utama. Salah satunya mungkin didukung.
spdrnl
Saya melihat. Jadi jika saya mengerti dengan benar, menjalankan PCA kemudian akan memberi saya satu set komponen utama yang independen, yang kemudian dapat saya gunakan sebagai kovariat untuk model saya, karena masing-masing komponen utama tidak saling berkolaborasi dengan yang lain?
orange1
2
Persis. Beberapa komponen cenderung menjadi tidak relevan. Ini lebih mudah daripada menjatuhkan variabel.
spdrnl
Hm, jadi maksud saya terutama untuk menjalankan model untuk tujuan penjelasan dan bukan prediksi. Bagaimana cara menafsirkan model yang menggunakan komponen utama sebagai kovariat?
orange1
1
Dalam hal itu tidak membantu karena menafsirkan komponen agak seni gelap.
spdrnl

Jawaban:

13

Terima kasih SpanishBoy - Ini adalah kode yang bagus. @ilanman: Ini memeriksa nilai VIF dan kemudian menjatuhkan variabel yang VIF lebih dari 5. Dengan "kinerja", saya pikir maksudnya run time. Kode di atas membutuhkan waktu sekitar 3 jam untuk berjalan di sekitar 300 variabel, 5.000 baris.

Omong-omong, saya telah memodifikasinya untuk menghapus beberapa loop tambahan. Juga, saya membuatnya sedikit lebih bersih dan mengembalikan bingkai data dengan variabel yang dikurangi. Versi ini mengurangi waktu menjalankan saya hingga setengah! Kode saya di bawah- Semoga membantu.

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
sumber
Terima kasih. Sudahkah Anda membandingkan output dari kedua fungsi? Saya melihat fungsi R ( usdmmetode paket vifstep) untuk VIF dan run time sangat keren. Seperti yang saya katakan sebelumnya, varian di atas dan Anda (dioptimalkan setengah) sangat lambat dibandingkan dengan R. Ada ide lain bagaimana mengoptimalkan belum?
SpanishBoy
1
Saya punya pertanyaan tentang pendekatan ini. Katakanlah kita memiliki fitur A, B, dan C. A berkorelasi dengan C. Jika Anda mengulangi fitur, A dan C akan memiliki VIF> 5, maka mereka akan turun. Pada kenyataannya, sebaiknya Anda tidak menghitung ulang VIF setelah setiap kali Anda menjatuhkan fitur. Dalam contoh saya Anda akan dropb baik A dan C, tetapi jika Anda menghitung VIF (C) setelah A dijatuhkan, tidak akan menjadi> 5
Titus Pullo
3

Anda dapat mencoba menggunakan kode di bawah ini:

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

Itu berhasil, tapi saya tidak suka kinerja pendekatan itu

SpanishBoy
sumber
Apakah Anda ingin sedikit berkomentar tentang apa yang dilakukan pendekatan ini? Dan mengapa Anda tidak menyukai pertunjukannya?
ilanman
2

Saya mencoba jawaban SpanishBoy dan menemukan kesalahan serval ketika menjalankannya untuk data-frame. Berikut adalah solusi yang 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]]

Saya juga tidak memiliki masalah dengan kinerja, tetapi belum mengujinya secara ekstensif.

Braden Fineberg
sumber
ini bagus dan bekerja untuk saya. kecuali, ia mengembalikan peringatan yang menakutkan:RuntimeWarning: divide by zero encountered in double_scalars
user2205916