Как выбрать пары признаков, корреляция которых превышает пороговое значение в панд?

#python #python-3.x #pandas

Вопрос:

У меня есть correlation matrix pandas фрейм данных, который выглядит следующим образом:

 import pandas as pd
foo = pd.DataFrame({'vars': ['col_a', 'col_b', 'col_c', 'col_d'],
                   'col_a': [1, 0.9, 0.04, 0.03],
                   'col_b': [0.9,1,0.05,0.03],
                   'col_c': [0.04, 0.05, 1, -0.04],
                   'col_d': [0.03, 0.03, -0.04,1]})
 

Я хотел бы получить все уникальные «пары», которые по абсолютному значению имеют корреляцию выше определенной threshold и исключают самокорреляцию

Итак, если порог есть 0.8 , я должен получить что-то вроде этого:

 [('col_a', 'col_b')]
 

Есть идеи, как я мог бы это сделать ?

Комментарии:

1. вы хотите иметь уникальные пары? а самокорреляция?

2. Возможны ли ожидаемые изменения в будущем? Потому что принятое решение не совпадает.

3. Хорошо, тогда супер. Счастливого кодирования.

4. Да, теперь я вижу вашу правку 🙂

5. удалено решение, лучше в будущем не менять вопрос, потому что ответы не совпадают. Лучше всего опубликовать новый вопрос, если он быстро изменится, как здесь.

Ответ №1:

Вы можете установить ‘vars’ в качестве индекса stack и использовать выходные данные для нарезки:

 pairs = foo.set_index('vars').stack()
pairs[pairs.abs().gt(0.8)]
 

выход:

 vars        
col_a  col_a    1.0
       col_b    0.9
col_b  col_a    0.9
       col_b    1.0
col_c  col_c    1.0
col_d  col_d    1.0
 

Как список:

 pairs = foo.set_index('vars').stack()
list(pairs[pairs.gt(0.8)].index)
 
 [('col_a', 'col_a'), ('col_a', 'col_b'), ('col_b', 'col_a'), ('col_b', 'col_b'), ('col_c', 'col_c'), ('col_d', 'col_d')]
 

Если вы хотите получить только уникальные пары (например, B vs A == A vs B) и отказаться от самокорреляции (например, A vs A), используйте эту альтернативу.

np.triu позволяет сохранить только один из треугольников в корреляционной матрице, а k параметр позволяет сдвинуть диагональ ( k=0 сохраняет диагональ, k=1 удаляет диагональ, таким образом, если вы хотите сохранить самокорреляцию, используйте k=0 )

 import numpy as np
foo = foo.set_index('vars')
pairs = foo.where(np.triu(foo, k=1).astype(bool)).stack()
list(pairs[pairs.abs().gt(0.8)].index)
 

выход:

 [('col_a', 'col_b')]
 

Комментарии:

1. для решения без самокорреляции foo = foo.set_index('vars') необходимо добавить после импорта numpy или заменить foo на foo.set_index('vars')

2. Да, спасибо @quant, я, видимо, забыл его вставить 😉

Ответ №2:

Вы можете использовать петлю. Попробуй это. Во-первых, отбросьте столбец vars и возьмите корреляции.

 foo = foo.drop('vars', axis = 1).corr()
 

Затем с помощью этого цикла возьмите корреляции между условиями. 0,8 и 0,99 (чтобы избежать самого себя)

 a = []
b = []
for i in foo.columns:
    for ii in range(len(foo.columns)):
        if (foo[i].iloc[ii] > 0.8) and (foo[i].iloc[ii] < 0.99):
            a.append(i)
            b.append(foo[i].iloc[ii])
 

Вы можете просмотреть функции и исправления со списком a и b.

Тогда, если вы хотите визуализировать;

 df = (foo > 0.95 ) amp; (foo < 1) 
df.applymap(lambda x: True if x else np.nan).dropna(how = 'all', axis = 1).dropna(how = 'all').fillna('-')