Liste der höchsten Korrelationspaare aus einer großen Korrelationsmatrix in Pandas?

85

Wie finden Sie die Top-Korrelationen in einer Korrelationsmatrix mit Pandas? Es gibt viele Antworten, wie dies mit R gemacht werden kann ( Korrelationen als geordnete Liste anzeigen, nicht als große Matrix oder effiziente Methode, um stark korrelierte Paare aus großen Datenmengen in Python oder R zu erhalten ), aber ich frage mich, wie das geht mit Pandas? In meinem Fall ist die Matrix 4460 x 4460, kann es also nicht visuell machen.

Kyle Brandt
quelle

Antworten:

83

Sie können verwenden DataFrame.values, um ein numpy-Array der Daten abzurufen, und dann NumPy-Funktionen verwenden argsort(), um beispielsweise die am meisten korrelierten Paare abzurufen .

Wenn Sie dies jedoch in Pandas tun möchten, können Sie unstackden DataFrame sortieren:

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]

Hier ist die Ausgabe:

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
quelle
10
Mit Pandas v 0.17.0 und höher sollten Sie sort_values ​​anstelle von order verwenden. Sie erhalten eine Fehlermeldung, wenn Sie versuchen, die Bestellmethode zu verwenden.
Friendm1
42

@ HYRYs Antwort ist perfekt. Bauen Sie einfach auf dieser Antwort auf, indem Sie etwas mehr Logik hinzufügen, um Doppel- und Selbstkorrelationen sowie die richtige Sortierung zu vermeiden:

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

Das ergibt folgende Ausgabe:

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
arun
quelle
3
Anstelle von get_redundant_pairs (df) können Sie "cor.loc [:,:] = np.tril (cor.values, k = -1)" und dann "cor = cor [cor> 0]" verwenden
Sarah
2
Ich bekomme Fehler für die Leitung au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False):# -- partial selection or non-unique index
StallingOne
38

Lösung mit wenigen Zeilen ohne redundante Variablenpaare:

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

Dann können Sie die Namen der Variablenpaare (die pandas.Series multi-indexes sind) und deren Werte wie folgt durchlaufen:

for index, value in sol.items():
  # do some staff
MiFi
quelle
3
wahrscheinlich eine schlechte Idee, um osals Variablenname zu verwenden, weil es die osvon maskiert, import oswenn im Code verfügbar
Shadi
Vielen Dank für Ihren Vorschlag, ich habe diesen nicht ordnungsgemäßen Variablennamen geändert.
MiFi
1
Ab 2018 verwenden Sie sort_values ​​(aufsteigend = False) anstelle von order
Serafins
wie man 'sol' schleift ??
Sirjay
1
@sirjay Ich habe oben eine Antwort auf Ihre Frage gegeben
MiFi
12

Wenn Sie einige Funktionen der Antworten von @HYRY und @ arun kombinieren, können Sie die wichtigsten Korrelationen für den Datenrahmen dfin einer einzigen Zeile drucken, indem Sie Folgendes verwenden:

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

Hinweis: Der einzige Nachteil ist, dass durch Hinzufügen von 1.0-Korrelationen, die keine Variable für sich sind, diese durch drop_duplicates()Hinzufügen hinzugefügt werden

Addison Klinke
quelle
1
Würden nicht drop_duplicatesalle Korrelationen fallen gelassen, die gleich sind?
Shadi
@shadi ja, du bist richtig. Wir gehen jedoch davon aus, dass die einzigen Korrelationen, die identisch sind, Korrelationen von 1,0 sind (dh eine Variable mit sich selbst). Es besteht die Möglichkeit, dass die Korrelation für zwei eindeutige Variablenpaare (dh v1zu v2und v3zu v4) nicht genau gleich ist
Addison Klinke
Auf jeden Fall mein Favorit, Einfachheit selbst. In meiner Verwendung habe ich zuerst nach hohen Korrelationen gefiltert
James Igoe
6

Verwenden Sie den folgenden Code, um die Korrelationen in absteigender Reihenfolge anzuzeigen.

# See the correlations in descending order

corr = df.corr() # df is the pandas dataframe
c1 = corr.abs().unstack()
c1.sort_values(ascending = False)
Prashanth
quelle
1
Ihre 2. Zeile sollte lauten: c1 = core.abs (). Unstack ()
Jack Fleeting
oder erste Zeilecorr = df.corr()
vizyourdata
3

Sie können dies grafisch anhand dieses einfachen Codes tun, indem Sie Ihre Daten ersetzen.

corr = df.corr()

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

Geben Sie hier die Bildbeschreibung ein

Wojciech Moszczyński
quelle
2

Viele gute Antworten hier. Der einfachste Weg, den ich gefunden habe, war eine Kombination einiger der obigen Antworten.

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()
Rich Wandell
quelle
2

Verwenden Sie diese Option itertools.combinations, um alle eindeutigen Korrelationen aus der eigenen Korrelationsmatrix von pandas .corr()abzurufen, eine Liste von Listen zu erstellen und diese in einen DataFrame zurückzugeben, um '.sort_values' zu verwenden. Stellen Sie ein ascending = True, dass oben die niedrigsten Korrelationen angezeigt werden

corrankNimmt einen DataFrame als Argument, weil es erforderlich ist .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)
Frederik Meinertsen
quelle
3
Während dieses Code-Snippet die Lösung sein kann, hilft das Hinzufügen einer Erklärung wirklich, die Qualität Ihres Beitrags zu verbessern. Denken Sie daran, dass Sie die Frage für Leser in Zukunft beantworten und diese Personen möglicherweise die Gründe für Ihren Codevorschlag nicht kennen.
haindl
1

Ich wollte unstackdieses Problem nicht oder zu kompliziert machen, da ich nur einige stark korrelierte Features als Teil einer Feature-Auswahlphase löschen wollte.

So kam ich zu der folgenden vereinfachten Lösung:

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

Wenn Sie in diesem Fall korrelierte Features löschen möchten, können Sie das gefilterte corr_colsArray zuordnen und die ungeradzahligen (oder geradzahligen) Features entfernen.

Falsarella
quelle
Dies ergibt nur einen Index (Feature) und nicht so etwas wie Feature1 Feature2 0.98. Ändern Sie die Zeile corr_cols = corr.max().sort_values(ascending=False)zu corr_cols = corr.unstack()
aunsid
Nun, das OP hat keine Korrelationsform angegeben. Wie ich bereits erwähnte, wollte ich mich nicht lösen, also habe ich einfach einen anderen Ansatz gewählt. Jedes Korrelationspaar wird in meinem vorgeschlagenen Code durch 2 Zeilen dargestellt. Aber danke für den hilfreichen Kommentar!
Falsarella
0

Ich habe hier einige der Lösungen ausprobiert, aber dann habe ich mir tatsächlich eine eigene ausgedacht. Ich hoffe, dass dies für den nächsten nützlich sein könnte, also teile ich es hier:

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
quelle
0

Dies ist ein Verbesserungscode von @MiFi. Diese eine Reihenfolge in abs, aber ohne die negativen Werte auszuschließen.

   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)
Aibloy
quelle
0

Die folgende Funktion sollte den Trick machen. Diese Implementierung

  • Entfernt Selbstkorrelationen
  • Entfernt Duplikate
  • Ermöglicht die Auswahl der Top N der am höchsten korrelierten Features

und es ist auch konfigurierbar, so dass Sie sowohl die Selbstkorrelationen als auch die Duplikate behalten können. Sie können auch beliebig viele Feature-Paare melden.


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
quelle
0

Ich mochte den Beitrag von Addison Klinke am meisten, da er der einfachste war, verwendete aber den Vorschlag von Wojciech Moszczyńsk zum Filtern und Diagrammieren, erweiterte den Filter jedoch, um absolute Werte zu vermeiden.

Erstellt, gefiltert und grafisch dargestellt

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

gefilterte Wärmekarte

Funktion

Am Ende habe ich eine kleine Funktion erstellt, um die Korrelationsmatrix zu erstellen, zu filtern und dann zu reduzieren. Als Idee könnte es leicht erweitert werden, z. B. asymmetrische Ober- und Untergrenzen usw.

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)

Geben Sie hier die Bildbeschreibung ein

James Igoe
quelle