Перечислить самые высокие корреляционные пары из большой корреляционной матрицы в пандах?

97

Как найти верхние корреляции в корреляционной матрице с Pandas? Есть много ответов о том, как это сделать с R ( Показать корреляции в виде упорядоченного списка, а не в виде большой матрицы или Эффективный способ получить высококоррелированные пары из большого набора данных в Python или R ), но мне интересно, как это сделать с пандами? В моем случае матрица 4460х4460, так что визуально сделать не могу.

Кайл Брандт
источник

Ответы:

93

Вы можете использовать DataFrame.valuesдля получения массива данных numpy, а затем использовать функции NumPy, например, argsort()для получения наиболее коррелированных пар.

Но если вы хотите сделать это в пандах, вы можете unstackотсортировать DataFrame:

import pandas as pd
import numpy as np

shape = (50, 4460)

data = np.random.normal(size=shape)

data[:, 1000] += data[:, 2000]

df = pd.DataFrame(data)

c = df.corr().abs()

s = c.unstack()
so = s.sort_values(kind="quicksort")

print so[-4470:-4460]

Вот результат:

2192  1522    0.636198
1522  2192    0.636198
3677  2027    0.641817
2027  3677    0.641817
242   130     0.646760
130   242     0.646760
1171  2733    0.670048
2733  1171    0.670048
1000  2000    0.742340
2000  1000    0.742340
dtype: float64
HYRY
источник
10
В Pandas v 0.17.0 и выше вы должны использовать sort_values ​​вместо order. Вы получите сообщение об ошибке, если попытаетесь использовать метод заказа.
Friendm1 05
46

Ответ @HYRY идеален. Просто опирайтесь на этот ответ, добавив немного больше логики, чтобы избежать дублирования и самокорреляции и правильной сортировки:

import pandas as pd
d = {'x1': [1, 4, 4, 5, 6], 
     'x2': [0, 0, 8, 2, 4], 
     'x3': [2, 8, 8, 10, 12], 
     'x4': [-1, -4, -4, -4, -5]}
df = pd.DataFrame(data = d)
print("Data Frame")
print(df)
print()

print("Correlation Matrix")
print(df.corr())
print()

def get_redundant_pairs(df):
    '''Get diagonal and lower triangular pairs of correlation matrix'''
    pairs_to_drop = set()
    cols = df.columns
    for i in range(0, df.shape[1]):
        for j in range(0, i+1):
            pairs_to_drop.add((cols[i], cols[j]))
    return pairs_to_drop

def get_top_abs_correlations(df, n=5):
    au_corr = df.corr().abs().unstack()
    labels_to_drop = get_redundant_pairs(df)
    au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False)
    return au_corr[0:n]

print("Top Absolute Correlations")
print(get_top_abs_correlations(df, 3))

Это дает следующий результат:

Data Frame
   x1  x2  x3  x4
0   1   0   2  -1
1   4   0   8  -4
2   4   8   8  -4
3   5   2  10  -4
4   6   4  12  -5

Correlation Matrix
          x1        x2        x3        x4
x1  1.000000  0.399298  1.000000 -0.969248
x2  0.399298  1.000000  0.399298 -0.472866
x3  1.000000  0.399298  1.000000 -0.969248
x4 -0.969248 -0.472866 -0.969248  1.000000

Top Absolute Correlations
x1  x3    1.000000
x3  x4    0.969248
x1  x4    0.969248
dtype: float64
Арун
источник
3
вместо get_redundant_pairs (df) вы можете использовать "cor.loc [:,:] = np.tril (cor.values, k = -1)", а затем "cor = cor [cor> 0]"
Сара
2
Я получаю ошибку для линии au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False):# -- partial selection or non-unique index
stallingOne
41

Решение в несколько строк без избыточных пар переменных:

corr_matrix = df.corr().abs()

#the matrix is symmetric so we need to extract upper triangle matrix without diagonal (k = 1)

sol = (corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
                  .stack()
                  .sort_values(ascending=False))

#first element of sol series is the pair with the biggest correlation

Затем вы можете перебирать имена пар переменных (которые являются мультииндексами pandas.Series) и их значения следующим образом:

for index, value in sol.items():
  # do some staff
MiFi
источник
3
вероятно, плохая идея использовать osв качестве имени переменной, потому что оно маскирует osот, import osесли оно доступно в коде
шади
Спасибо за ваше предложение, я изменил это неправильное имя переменной.
MiFi
1
с 2018 года используйте sort_values ​​(ascending = False) вместо order
Serafins
1
как зациклить 'sol' ??
sirjay
2
@sirjay Я разместил ответ на ваш вопрос выше
MiFi
13

Комбинируя некоторые особенности ответов @HYRY и @arun, вы можете распечатать основные корреляции для фрейма данных dfв одной строке, используя:

df.corr().unstack().sort_values().drop_duplicates()

Примечание: одним недостатком является то, что если у вас есть корреляции 1.0, которые не являются одной переменной для себя, drop_duplicates()добавление удалит их

Эддисон Клинке
источник
1
Не отбросили бы drop_duplicatesвсе равные корреляции?
Шади
@shadi да, ты прав. Однако мы предполагаем, что единственные корреляции, которые будут одинаково равны, - это корреляции 1.0 (т.е. переменная сама с собой). Скорее всего, корреляция для двух уникальных пар переменных (то есть « v1к» v2и « v3к» v4) не будет в точности одинаковой,
Эддисон Клинке,
Определенно мой фаворит, сама простота. в моем использовании я сначала отфильтровал высокие корреляции
Джеймс Айго
9

Используйте приведенный ниже код для просмотра корреляций в порядке убывания.

# See the correlations in descending order

corr = df.corr() # df is the pandas dataframe
c1 = corr.abs().unstack()
c1.sort_values(ascending = False)
прашант
источник
1
Ваша вторая строка должна быть: c1 = core.abs (). Unstack ()
Jack Fleeting
или первая строкаcorr = df.corr()
vizyourdata
4

Вы можете делать это графически в соответствии с этим простым кодом, подставляя свои данные.

corr = df.corr()

kot = corr[corr>=.9]
plt.figure(figsize=(12,8))
sns.heatmap(kot, cmap="Greens")

введите описание изображения здесь

Войцех Мощинский
источник
2

Здесь много хороших ответов. Самый простой способ, который я нашел, - это комбинация некоторых из приведенных выше ответов.

corr = corr.where(np.triu(np.ones(corr.shape), k=1).astype(np.bool))
corr = corr.unstack().transpose()\
    .sort_values(by='column', ascending=False)\
    .dropna()
Рич Ванделл
источник
2

Используется itertools.combinationsдля получения всех уникальных корреляций из собственной матрицы корреляции pandas .corr(), создания списка списков и передачи его обратно в DataFrame для использования '.sort_values'. Установите ascending = Trueотображение самых низких корреляций вверху

corrankпринимает DataFrame в качестве аргумента, потому что для этого требуется .corr().

  def corrank(X: pandas.DataFrame):
        import itertools
        df = pd.DataFrame([[(i,j),X.corr().loc[i,j]] for i,j in list(itertools.combinations(X.corr(), 2))],columns=['pairs','corr'])    
        print(df.sort_values(by='corr',ascending=False))

  corrank(X) # prints a descending list of correlation pair (Max on top)
Фредерик Майнертсен
источник
3
Хотя этот фрагмент кода может быть решением, включение объяснения действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причины вашего предложения кода.
haindl
1

Я не хотел unstackили слишком усложнять эту проблему, так как я просто хотел отказаться от некоторых сильно коррелированных функций как часть фазы выбора функций.

В итоге я получил следующее упрощенное решение:

# map features to their absolute correlation values
corr = features.corr().abs()

# set equality (self correlation) as zero
corr[corr == 1] = 0

# of each feature, find the max correlation
# and sort the resulting array in ascending order
corr_cols = corr.max().sort_values(ascending=False)

# display the highly correlated features
display(corr_cols[corr_cols > 0.8])

В этом случае, если вы хотите отбросить коррелированные объекты, вы можете сопоставить отфильтрованный corr_colsмассив и удалить нечетно-индексированные (или даже-индексированные).

фальсарелла
источник
Это просто дает один индекс (функцию), а не что-то вроде feature1 feature2 0.98. Изменить строку corr_cols = corr.max().sort_values(ascending=False)на corr_cols = corr.unstack()
aunsid 08
Ну, OP не указал форму корреляции. Как я уже упоминал, я не хотел распаковывать стек, поэтому просто предложил другой подход. В предлагаемом мной коде каждая корреляционная пара представлена ​​двумя строками. Но спасибо за полезный комментарий!
falsarella
1

Мне больше всего понравился пост Аддисона Клинке, как самый простой, но я использовал предложение Войцеха Мощинска для фильтрации и построения диаграмм, но расширил фильтр, чтобы избежать абсолютных значений, поэтому, учитывая большую матрицу корреляции, отфильтруйте ее, нанесите на диаграмму и затем сгладьте:

Создано, отфильтровано и нанесено на диаграммы

dfCorr = df.corr()
filteredDf = dfCorr[((dfCorr >= .5) | (dfCorr <= -.5)) & (dfCorr !=1.000)]
plt.figure(figsize=(30,10))
sn.heatmap(filteredDf, annot=True, cmap="Reds")
plt.show()

отфильтрованная тепловая карта

Функция

В конце концов, я создал небольшую функцию для создания корреляционной матрицы, фильтрации ее и затем сглаживания. По идее, его можно было бы легко расширить, например, путем асимметричных оценок сверху и снизу и т. Д.

def corrFilter(x: pd.DataFrame, bound: float):
    xCorr = x.corr()
    xFiltered = xCorr[((xCorr >= bound) | (xCorr <= -bound)) & (xCorr !=1.000)]
    xFlattened = xFiltered.unstack().sort_values().drop_duplicates()
    return xFlattened

corrFilter(df, .7)

введите описание изображения здесь

Джеймс Айго
источник
как удалить самую последнюю? HofstederPowerDx и Hofsteder PowerDx - это одни и те же переменные, верно?
Люк
можно использовать .dropna () в функциях. Я просто попробовал это в VS Code, и он работает, где я использую первое уравнение для создания и фильтрации корреляционной матрицы, а другое - для ее выравнивания. Если вы используете это, вы можете поэкспериментировать с удалением .dropduplicates (), чтобы узнать, нужны ли вам и .dropna (), и dropduplicates ().
Джеймс Айго,
Блокнот с этим кодом и некоторыми другими улучшениями находится здесь: github.com/JamesIgoe/GoogleFitAnalysis
Джеймс Айго,
0

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

def sort_correlation_matrix(correlation_matrix):
    cor = correlation_matrix.abs()
    top_col = cor[cor.columns[0]][1:]
    top_col = top_col.sort_values(ascending=False)
    ordered_columns = [cor.columns[0]] + top_col.index.tolist()
    return correlation_matrix[ordered_columns].reindex(ordered_columns)
KIC
источник
0

Это улучшенный код от @MiFi. Это один порядок в абс, но не исключая отрицательные значения.

   def top_correlation (df,n):
    corr_matrix = df.corr()
    correlation = (corr_matrix.where(np.triu(np.ones(corr_matrix.shape), k=1).astype(np.bool))
                 .stack()
                 .sort_values(ascending=False))
    correlation = pd.DataFrame(correlation).reset_index()
    correlation.columns=["Variable_1","Variable_2","Correlacion"]
    correlation = correlation.reindex(correlation.Correlacion.abs().sort_values(ascending=False).index).reset_index().drop(["index"],axis=1)
    return correlation.head(n)

top_correlation(ANYDATA,10)
Айблой
источник
0

Следующая функция должна помочь. Эта реализация

  • Удаляет самокорреляции
  • Удаляет дубликаты
  • Позволяет выбрать N верхних коррелированных функций

и его также можно настроить так, чтобы вы могли сохранить как самокорреляцию, так и дубликаты. Вы также можете сообщить о любом количестве пар функций.


def get_feature_correlation(df, top_n=None, corr_method='spearman',
                            remove_duplicates=True, remove_self_correlations=True):
    """
    Compute the feature correlation and sort feature pairs based on their correlation

    :param df: The dataframe with the predictor variables
    :type df: pandas.core.frame.DataFrame
    :param top_n: Top N feature pairs to be reported (if None, all of the pairs will be returned)
    :param corr_method: Correlation compuation method
    :type corr_method: str
    :param remove_duplicates: Indicates whether duplicate features must be removed
    :type remove_duplicates: bool
    :param remove_self_correlations: Indicates whether self correlations will be removed
    :type remove_self_correlations: bool

    :return: pandas.core.frame.DataFrame
    """
    corr_matrix_abs = df.corr(method=corr_method).abs()
    corr_matrix_abs_us = corr_matrix_abs.unstack()
    sorted_correlated_features = corr_matrix_abs_us \
        .sort_values(kind="quicksort", ascending=False) \
        .reset_index()

    # Remove comparisons of the same feature
    if remove_self_correlations:
        sorted_correlated_features = sorted_correlated_features[
            (sorted_correlated_features.level_0 != sorted_correlated_features.level_1)
        ]

    # Remove duplicates
    if remove_duplicates:
        sorted_correlated_features = sorted_correlated_features.iloc[:-2:2]

    # Create meaningful names for the columns
    sorted_correlated_features.columns = ['Feature 1', 'Feature 2', 'Correlation (abs)']

    if top_n:
        return sorted_correlated_features[:top_n]

    return sorted_correlated_features

Giorgos Myrianthous
источник