¿Enumerar los pares de correlación más altos de una matriz de correlación grande en pandas?

Respuestas:

93

Puede usar DataFrame.valuespara obtener una matriz numerosa de los datos y luego usar funciones NumPy como argsort()para obtener los pares más correlacionados.

Pero si desea hacer esto en pandas, puede unstackordenar el 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]

Aquí está el resultado:

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
fuente
10
Con Pandas v 0.17.0 y superior, debe usar sort_values ​​en lugar de order. Obtendrá un error si intenta utilizar el método de pedido.
Friendm1
46

La respuesta de @ HYRY es perfecta. Simplemente construyendo sobre esa respuesta agregando un poco más de lógica para evitar duplicaciones y autocorrelaciones y una clasificación adecuada:

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

Eso da el siguiente resultado:

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
fuente
3
en lugar de get_redundant_pairs (df), puede usar "cor.loc [:,:] = np.tril (cor.values, k = -1)" y luego "cor = cor [cor> 0]"
Sarah
2
Recibo un error para la línea au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False):# -- partial selection or non-unique index
stallingOne
41

Solución de pocas líneas sin pares de variables redundantes:

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

Luego, puede iterar a través de los nombres de los pares de variables (que son múltiples índices de pandas.Series) y sus valores como este:

for index, value in sol.items():
  # do some staff
MiFi
fuente
3
probablemente sea una mala idea usarlo oscomo nombre de variable porque enmascara el osdesde import ossi está disponible en el código
shadi
Gracias por tu sugerencia, cambié este nombre var incorrecto.
MiFi
1
a partir de 2018 use sort_values ​​(ascendente = Falso) en lugar de order
Serafins
1
cómo hacer un bucle 'sol'?
sirjay
2
@sirjay Puse una respuesta a su pregunta anterior
MiFi
13

Combinando algunas características de las respuestas de @HYRY y @ arun, puede imprimir las correlaciones principales para el marco de datos dfen una sola línea usando:

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

Nota: la única desventaja es que si tiene correlaciones 1.0 que no son una variable en sí misma, la drop_duplicates()adición las eliminaría

Addison Klinke
fuente
1
¿No drop_duplicateseliminaría todas las correlaciones que son iguales?
shadi
@shadi sí, tienes razón. Sin embargo, asumimos que las únicas correlaciones que serán idénticamente iguales son correlaciones de 1.0 (es decir, una variable consigo misma). Lo más probable es que la correlación de dos pares de variables únicas (es decir, v1a v2y v3a v4) no sería exactamente la misma
Addison Klinke
Definitivamente mi favoritismo, la simplicidad misma. en mi uso, filtré primero para correcciones altas
James Igoe
9

Utilice el siguiente código para ver las correlaciones en orden descendente.

# See the correlations in descending order

corr = df.corr() # df is the pandas dataframe
c1 = corr.abs().unstack()
c1.sort_values(ascending = False)
prashanth
fuente
1
Su segunda línea debería ser: c1 = core.abs (). Unstack ()
Jack Fleeting
o primera líneacorr = df.corr()
vizyourdata
4

Puede hacerlo gráficamente de acuerdo con este sencillo código sustituyendo sus datos.

corr = df.corr()

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

ingrese la descripción de la imagen aquí

Wojciech Moszczyński
fuente
2

Muchas buenas respuestas aquí. La forma más fácil que encontré fue una combinación de algunas de las respuestas anteriores.

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
fuente
2

Úselo itertools.combinationspara obtener todas las correlaciones únicas de la propia matriz de correlación de los pandas .corr(), generar una lista de listas y retroalimentarla en un DataFrame para usar '.sort_values'. Conjuntoascending = True para mostrar las correlaciones más bajas en la parte superior

corranktoma un DataFrame como argumento porque requiere .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
fuente
3
Si bien este fragmento de código puede ser la solución, incluir una explicación realmente ayuda a mejorar la calidad de su publicación. Recuerde que está respondiendo a la pregunta para los lectores en el futuro, y es posible que esas personas no conozcan los motivos de su sugerencia de código.
haindl
1

Yo no queria unstack complicar demasiado este problema, ya que solo quería eliminar algunas funciones altamente correlacionadas como parte de una fase de selección de funciones.

Así que terminé con la siguiente solución simplificada:

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

En este caso, si desea eliminar características correlacionadas, puede mapear a través de la corr_colsmatriz filtrada y eliminar las indexadas impares (o indexadas pares).

falsarella
fuente
Esto solo da un índice (característica) y no algo como feature1 feature2 0.98. Cambiar línea corr_cols = corr.max().sort_values(ascending=False)a corr_cols = corr.unstack()
aunsid
Bueno, el OP no especificó una forma de correlación. Como mencioné, no quería desapilar, así que solo traje un enfoque diferente. Cada par de correlación está representado por 2 filas, en mi código sugerido. ¡Pero gracias por el comentario útil!
falsarella
1

Me gustó más la publicación de Addison Klinke, por ser la más simple, pero usé la sugerencia de Wojciech Moszczyńsk para filtrar y trazar gráficos, pero extendí el filtro para evitar valores absolutos, así que dada una matriz de correlación grande, fíltrala, grafica y luego aplana:

Creado, filtrado y graficado

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

mapa de calor filtrado

Función

Al final, creé una pequeña función para crear la matriz de correlación, filtrarla y luego aplanarla. Como idea, podría extenderse fácilmente, por ejemplo, límites superior e inferior asimétricos, etc.

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)

ingrese la descripción de la imagen aquí

James Igoe
fuente
¿Cómo quitar el último? HofstederPowerDx y Hofsteder PowerDx son las mismas variables, ¿verdad?
Luc
se puede usar .dropna () en las funciones. Lo probé en VS Code y funciona, donde uso la primera ecuación para crear y filtrar la matriz de correlación, y otra para aplanarla. Si usa eso, es posible que desee experimentar con la eliminación de .dropduplicates () para ver si necesita tanto .dropna () como dropduplicates ().
James Igoe
Un cuaderno que incluye este código y algunas otras mejoras está aquí: github.com/JamesIgoe/GoogleFitAnalysis
James Igoe
0

Estaba probando algunas de las soluciones aquí, pero luego se me ocurrió la mía propia. Espero que esto pueda ser útil para el próximo, así que lo comparto aquí:

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

Este es un código mejorado de @MiFi. Este orden en abs pero sin excluir los valores negativos.

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

La siguiente función debería funcionar. Esta implementación

  • Elimina las autocorrelaciones
  • Elimina duplicados
  • Permite la selección de las N características más correlacionadas

y también es configurable para que pueda mantener tanto las autocorrelaciones como los duplicados. También puede informar sobre tantos pares de características como desee.


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
fuente