【问题标题】:List Highest Correlation Pairs from a Large Correlation Matrix in Pandas?从 Pandas 的大相关矩阵中列出最高相关对?
【发布时间】:2013-07-20 15:30:17
【问题描述】:

如何在 Pandas 的相关矩阵中找到最高相关性?关于如何使用 R(Show correlations as an ordered list, not as a large matrixEfficient way to get highly correlated pairs from large data set in Python or R)执行此操作有很多答案,但我想知道如何使用 pandas 执行此操作?在我的情况下,矩阵是 4460x4460,所以不能直观地做到这一点。

【问题讨论】:

    标签: python pandas correlation


    【解决方案1】:

    您可以使用DataFrame.values 获取数据的numpy 数组,然后使用诸如argsort() 之类的NumPy 函数来获取最相关的对。

    但如果你想在 pandas 中这样做,你可以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
    

    【讨论】:

    • 对于 Pandas v 0.17.0 及更高版本,您应该使用 sort_values 而不是 order。如果你尝试使用 order 方法,你会得到一个错误。
    • 另外,为了得到高度相关的对,你需要使用sort_values(ascending=False)
    • "numpy 数据数组,然后使用 argsort() 等 NumPy 函数获取最相关的对。" - 你能举个例子吗?
    【解决方案2】:

    @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
    

    【讨论】:

    • 代替 get_redundant_pairs(df),你可以使用 "cor.loc[:,:] = np.tril(cor.values, k=-1)" 然后 "cor = cor[cor >0]"
    • 我的行 au_corr = au_corr.drop(labels=labels_to_drop).sort_values(ascending=False) 出错了:# -- partial selection or non-unique index
    【解决方案3】:

    没有冗余变量对的几行解决方案:

    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
    

    【讨论】:

    • 使用os 作为变量名可能是个坏主意,因为如果代码中可用,它会从import os 中屏蔽os
    • 感谢您的建议,我更改了这个不正确的变量名称。
    • 自 2018 年起使用 sort_values(ascending=False) 而不是 order
    • 如何循环“溶胶”??
    • @sirjay 我在上面回答了你的问题
    【解决方案4】:

    结合@HYRY 和@arun 答案的一些功能,您可以使用以下命令在一行中打印数据帧df 的最高相关性:

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

    注意:一个缺点是,如果您有 1.0 个相关性,而 不是 一个变量本身,drop_duplicates() 添加将删除它们

    【讨论】:

    • 不会drop_duplicates 删除所有相等的相关性吗?
    • @shadi 是的,你是对的。但是,我们假设唯一完全相同的相关性是 1.0 的相关性(即与自身的变量)。两个唯一变量对(即v1v2v3v4)的相关性可能不会完全相同
    • 绝对是我的最爱,简洁本身。在我的使用中,我首先过滤了高相关性
    【解决方案5】:

    使用下面的代码按降序查看相关性。

    # See the correlations in descending order
    
    corr = df.corr() # df is the pandas dataframe
    c1 = corr.abs().unstack()
    c1.sort_values(ascending = False)
    

    【讨论】:

    • 你的第二行应该是:c1 = core.abs().unstack()
    • 或第一行corr = df.corr()
    【解决方案6】:

    我最喜欢 Addison Klinke 的帖子,因为它是最简单的,但使用了 Wojciech Moszczyńsk 的过滤和图表建议,但扩展了过滤器以避免绝对值,所以给定一个大的相关矩阵,过滤它,绘制它,然后展平它:

    创建、过滤和图表

    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)
    

    跟进

    最终,我完善了功能

    # Returns correlation matrix
    def corrFilter(x: pd.DataFrame, bound: float):
        xCorr = x.corr()
        xFiltered = xCorr[((xCorr >= bound) | (xCorr <= -bound)) & (xCorr !=1.000)]
        return xFiltered
    
    # flattens correlation matrix with bounds
    def corrFilterFlattened(x: pd.DataFrame, bound: float):
        xFiltered = corrFilter(x, bound)
        xFlattened = xFiltered.unstack().sort_values().drop_duplicates()
        return xFlattened
    
    # Returns correlation for a variable from flattened correlation matrix
    def filterForLabels(df: pd.DataFrame, label):  
        try:
            sideLeft = df[label,]
        except:
            sideLeft = pd.DataFrame()
    
        try:
            sideRight = df[:,label]
        except:
            sideRight = pd.DataFrame()
    
        if sideLeft.empty and sideRight.empty:
            return pd.DataFrame()
        elif sideLeft.empty:        
            concat = sideRight.to_frame()
            concat.rename(columns={0:'Corr'},inplace=True)
            return concat
        elif sideRight.empty:
            concat = sideLeft.to_frame()
            concat.rename(columns={0:'Corr'},inplace=True)
            return concat
        else:
            concat = pd.concat([sideLeft,sideRight], axis=1)
            concat["Corr"] = concat[0].fillna(0) + concat[1].fillna(0)
            concat.drop(columns=[0,1], inplace=True)
            return concat
    

    【讨论】:

    • 如何删除最后一个? HofstederPowerDx 和 Hofsteder PowerDx 是同一个变量,对吧?
    • 可以在函数中使用 .dropna() 。我刚刚在 VS Code 中尝试过它并且它可以工作,我使用第一个方程来创建和过滤相关矩阵,并使用另一个来展平它。如果您使用它,您可能想尝试删除 .dropduplicates() 以查看是否需要 .dropna() 和 dropduplicates()。
    • 包含此代码和其他一些改进的笔记本在这里:github.com/JamesIgoe/GoogleFitAnalysis
    • 我相信代码在这里总结了两次r值,如果我错了,请纠正,
    • @Sidrah - 我做了一些基本的抽查,它似乎是准确的,但如果你尝试使用它并且它是你的两倍,请告诉我。
    【解决方案7】:

    您可以通过替换您的数据,根据这个简单的代码进行图形化操作。

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

    【讨论】:

    • 如果存在强负相关,我是否也需要类似 kot = corr[abs(corr) &gt;= 0.9] 的内容?
    【解决方案8】:

    这里有很多很好的答案。我发现的最简单的方法是结合上面的一些答案。

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

    【讨论】:

      【解决方案9】:

      将上面的大部分答案组合成一个简短的 sn-p:

      def top_entries(df):
          mat = df.corr().abs()
          
          # Remove duplicate and identity entries
          mat.loc[:,:] = np.tril(mat.values, k=-1)
          mat = mat[mat>0]
      
          # Unstack, sort ascending, and reset the index, so features are in columns
          # instead of indexes (allowing e.g. a pretty print in Jupyter).
          # Also rename these it for good measure.
          return (mat.unstack()
                   .sort_values(ascending=False)
                   .reset_index()
                   .rename(columns={
                       "level_0": "feature_a",
                       "level_1": "feature_b",
                       0: "correlation"
                   }))
      

      【讨论】:

        【解决方案10】:

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

        【讨论】:

        • 虽然此代码 sn-p 可能是解决方案,但 including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
        【解决方案11】:

        我不想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()
        • 好吧,OP 没有指定相关形状。正如我所提到的,我不想拆散,所以我只是带来了一种不同的方法。在我建议的代码中,每个相关对由 2 行表示。但是感谢您的有用评论!
        【解决方案12】:

        我在这里尝试了一些解决方案,但实际上我想出了自己的解决方案。我希望这可能对下一个有用,所以我在这里分享它:

        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)
        

        【讨论】:

          【解决方案13】:

          这是来自@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)
          

          【讨论】:

            【解决方案14】:

            下面的函数应该可以解决问题。这个实现

            • 消除自相关
            • 删除重复项
            • 允许选择前 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
            
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-06-30
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多