Wymień najwyższe pary korelacji z dużej macierzy korelacji w pandach?


104

Jak znaleźć najlepsze korelacje w macierzy korelacji z pandami? Jest wiele odpowiedzi, jak to zrobić za pomocą R ( Pokaż korelacje jako uporządkowaną listę, a nie jako dużą macierz lub Wydajny sposób na uzyskanie silnie skorelowanych par z dużego zestawu danych w Pythonie lub R ), ale zastanawiam się, jak to zrobić z pandami? W moim przypadku matryca ma wymiary 4460x4460, więc nie mogę tego zrobić wizualnie.

Odpowiedzi:


100

Możesz użyć, DataFrame.valuesaby uzyskać tablicę numpy danych, a następnie użyć funkcji NumPy, takich jak argsort()uzyskanie najbardziej skorelowanych par.

Ale jeśli chcesz to zrobić w pandach, możesz unstackposortować 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]

Oto wynik:

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

11
W przypadku Pand w wersji 0.17.0 i nowszych powinieneś używać wartości sort_values ​​zamiast kolejności. Jeśli spróbujesz użyć metody zamówienia, pojawi się błąd.
Friendm1

Ponadto, aby uzyskać wysoce skorelowane pary, musisz użyć sort_values(ascending=False).
sotmot

49

Odpowiedź @ HYRY'ego jest doskonała. Po prostu opierając się na tej odpowiedzi, dodając nieco więcej logiki, aby uniknąć duplikatów i korelacji własnych oraz właściwego sortowania:

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

To daje następujący wynik:

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
zamiast get_redundant_pairs (df) możesz użyć „cor.loc [:,:] = np.tril (cor.values, k = -1)”, a następnie „cor = cor [cor> 0]”
Sarah

2
Dostaję błąd dla linii au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False):# -- partial selection or non-unique index
przeciąganie 1

43

Rozwiązanie kilku linii bez zbędnych par zmiennych:

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

Następnie możesz iterować po nazwach par zmiennych (czyli pandas.Series multi-indexes) i ich wartościach w następujący sposób:

for index, value in sol.items():
  # do some staff

3
prawdopodobnie zły pomysł na użycie osjako nazwy zmiennej, ponieważ maskuje osprzed, import osjeśli jest dostępny w kodzie
shadi

Dzięki za sugestię, zmieniłem tę niewłaściwą nazwę var.
MiFi

1
od 2018 użyj sort_values ​​(ascending = False) zamiast kolejności
Serafins

1
jak zapętlić 'sol' ??
sirjay

2
@sirjay Powyżej umieściłem odpowiedź na twoje pytanie
MiFi

14

Łącząc niektóre cechy odpowiedzi @HYRY i @ arun, możesz wydrukować najważniejsze korelacje dla ramki danych dfw jednej linii, używając:

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

Uwaga: jedyną wadą jest to, że jeśli masz korelacje 1.0, które nie są dla siebie jedną zmienną, drop_duplicates()dodanie spowoduje ich usunięcie


1
Czy nie drop_duplicatesporzuciłby wszystkich równych korelacji?
shadi

@shadi tak, masz rację. Zakładamy jednak, że jedynymi korelacjami, które będą identycznie równe, są korelacje 1,0 (czyli zmienna ze sobą). Są szanse, że korelacja dla dwóch unikalnych par zmiennych (tj. v1Do v2i v3do v4) nie byłaby dokładnie taka sama
Addison Klinke

Zdecydowanie moja ulubiona, sama prostota. w moim użyciu najpierw filtrowałem pod kątem wysokich korelacji
James Igoe

10

Użyj poniższego kodu, aby wyświetlić korelacje w porządku malejącym.

# See the correlations in descending order

corr = df.corr() # df is the pandas dataframe
c1 = corr.abs().unstack()
c1.sort_values(ascending = False)

1
Twoja druga linia powinna wyglądać następująco: c1 = core.abs (). Unstack ()
Jack Fleeting

lub pierwsza liniacorr = df.corr()
vizyourdata

6

Możesz to zrobić graficznie zgodnie z tym prostym kodem, zastępując swoje dane.

corr = df.corr()

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

wprowadź opis obrazu tutaj


3

Najbardziej podobał mi się post Addisona Klinke, jako najprostszy, ale wykorzystałem sugestię Wojciecha Moszczyńska do filtrowania i tworzenia wykresów, ale rozszerzyłem filtr, aby uniknąć wartości bezwzględnych, więc mając dużą macierz korelacji, przefiltruj, wykreśl, a następnie spłaszcz:

Utworzono, przefiltrowano i przedstawiono na wykresie

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()

filtrowana mapa cieplna

Funkcjonować

Na koniec stworzyłem małą funkcję do tworzenia macierzy korelacji, przefiltrowania jej, a następnie spłaszczenia. Jako pomysł można go łatwo rozszerzyć, np. Asymetryczne górne i dolne granice itp.

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)

wprowadź opis obrazu tutaj


jak usunąć ostatnią? HofstederPowerDx i Hofsteder PowerDx to te same zmienne, prawda?
Luc

w funkcjach można użyć .dropna (). Właśnie wypróbowałem to w VS Code i działa, gdzie używam pierwszego równania do tworzenia i filtrowania macierzy korelacji, a drugiego do jej spłaszczania. Jeśli tego używasz, możesz poeksperymentować z usuwaniem .dropduplicates (), aby sprawdzić, czy potrzebujesz zarówno .dropna (), jak i dropduplicates ().
James Igoe

Notatnik zawierający ten kod i kilka innych ulepszeń jest tutaj: github.com/JamesIgoe/GoogleFitAnalysis
James Igoe

2

Tutaj jest dużo dobrych odpowiedzi. Najłatwiejszy sposób, jaki znalazłem, to połączenie niektórych z powyższych odpowiedzi.

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

Użyj, itertools.combinationsaby uzyskać wszystkie unikalne korelacje z własnej macierzy korelacji pandy .corr(), wygenerować listę list i przesłać ją z powrotem do ramki DataFrame w celu użycia „.sort_values”. Ustaw, ascending = Trueaby wyświetlać najniższe korelacje na górze

corrankprzyjmuje jako argument DataFrame, ponieważ wymaga .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
Chociaż ten fragment kodu może być rozwiązaniem, dołączenie wyjaśnienia naprawdę pomaga poprawić jakość Twojego posta. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
haindl

1

Nie chciałem zbytnio unstackkomplikować tego problemu, ponieważ chciałem po prostu usunąć niektóre wysoce skorelowane funkcje w ramach fazy wyboru funkcji.

W rezultacie otrzymałem następujące uproszczone rozwiązanie:

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

W takim przypadku, jeśli chcesz usunąć skorelowane funkcje, możesz zmapować filtrowaną corr_colstablicę i usunąć nieparzyste (lub parzyste) elementy.


To daje tylko jeden indeks (cechę), a nie coś w rodzaju feature1 feature2 0.98. Zmień linię corr_cols = corr.max().sort_values(ascending=False)na corr_cols = corr.unstack()
aunsid

Cóż, PO nie określił kształtu korelacji. Jak wspomniałem, nie chciałem zdejmować stosu, więc po prostu zastosowałem inne podejście. Każda para korelacji jest reprezentowana przez 2 wiersze w moim sugerowanym kodzie. Ale dzięki za pomocny komentarz!
falsarella

0

Próbowałem tutaj niektórych rozwiązań, ale potem wymyśliłem własne. Mam nadzieję, że przyda się to przy następnym, więc udostępniam to tutaj:

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)

0

To jest ulepszony kod z @MiFi. To jedno zamówienie w abs, ale nie wykluczając wartości ujemnych.

   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

Poniższa funkcja powinna załatwić sprawę. Ta realizacja

  • Usuwa korelacje własne
  • Usuwa duplikaty
  • Umożliwia wybór najwyższych N najbardziej skorelowanych funkcji

i jest również konfigurowalny, dzięki czemu można zachować zarówno własne korelacje, jak i duplikaty. Możesz również zgłosić dowolną liczbę par funkcji.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.