Pandas相关性分组

46
假设我有一个类似下面的数据框,我该如何获取两个特定列之间的相关性,然后按“ID”列进行分组?我相信Pandas的'corr'方法可以找到所有列之间的相关性。如果可能,我还想知道如何使用.agg函数找到“groupby”相关性(即np.correlate)。

我有以下内容:

ID  Val1    Val2    OtherData   OtherData
A   5       4       x           x
A   4       5       x           x
A   6       6       x           x
B   4       1       x           x
B   8       2       x           x
B   7       9       x           x
C   4       8       x           x
C   5       5       x           x
C   2       1       x           x

我需要什么:

ID  Correlation_Val1_Val2
A   0.12
B   0.22
C   0.05
6个回答

65

你已经基本上理解所有的部分,只需要将它们组合起来:

>>> df.groupby('ID')[['Val1','Val2']].corr()

             Val1      Val2
ID                         
A  Val1  1.000000  0.500000
   Val2  0.500000  1.000000
B  Val1  1.000000  0.385727
   Val2  0.385727  1.000000

根据您的情况,为每个ID打印一个2x2矩阵过于冗长。我没有看到可以打印标量相关性而不是整个矩阵的选项,但如果您只有两个变量,您可以做一些简单的事情,例如:

>>> df.groupby('ID')[['Val1','Val2']].corr().iloc[0::2,-1]

ID       
A   Val1    0.500000
B   Val1    0.385727

对于三个或更多变量的情况

对于三个或更多变量,要创建简洁的输出并不容易,但您可以采取如下方法:

groups = list('Val1', 'Val2', 'Val3', 'Val4')
df2 = pd.DataFrame()
for i in range( len(groups)-1): 
    df2 = df2.append( df.groupby('ID')[groups].corr().stack()
                        .loc[:,groups[i],groups[i+1]:].reset_index() )

df2.columns = ['ID', 'v1', 'v2', 'corr']
df2.set_index(['ID','v1','v2']).sort_index()
请注意,如果我们没有 groupby 元素,那么使用 numpy 中的上三角形或下三角形函数就很容易。但是由于该元素存在,据我所知,以更优雅的方式产生简明输出并不容易。

1
我应该如何更改这个函数为'rolling_corr()',以便每10天计算一次滚动相关性? - Gohawks
12
这是一个很好的回答。事实上,要处理这么简单的东西却需要使用.iloc来搞弄,这正是让我对pandas感到沮丧的原因之一;如果我想为科学数据设置一个大型处理管道,最终感觉就像一切都是用牙膏黏在一起的。 - Cai

14

另外还有一个简单的解决方案:

df.groupby('ID')[['Val1','Val2']].corr().unstack().iloc[:,1]

6
在上面的答案中,由于ix已被弃用,请改用iloc并进行一些其他小的更改:
df.groupby('ID')[['Val1','Val2']].corr().iloc[0::2][['Val2']] # to get pandas DataFrame

或者

df.groupby('ID')[['Val1','Val2']].corr().iloc[0::2]['Val2'] # to get pandas Series

1

结合他人的答案,创建一个不依赖于隐式索引的内容。

按组获取相关性相对简单:

corr_df = op_data\
    .groupby('ID')[['Val1', 'Val2']]\
    .corr().unstack()[[('Val1', 'Val2')]]\
    .reset_index()

  ID      Val1
          Val2
0  A  0.500000
1  B  0.385727
2  C  0.714575

现在,为了获得所需的扁平列结构,我们可以使用一些技巧

corr_df.columns = corr_df.columns.map(lambda x: '_'.join(a for a in x if len(a)>0))

  ID  Val1_Val2
0  A   0.500000
1  B   0.385727
2  C   0.714575

附言:解析操作者的数据:

for rep in range(10):
    data_str = data_str.replace('  ', ' ')
op_data = pd.read_csv(io.StringIO(data_str), sep=' ', engine='python')

0
如果您还需要保留数据框的结构,这是我想出来的方法:
假设您从以下数据框开始:

enter image description here

corr_df = x.groupby('ID')[['Val1','Val2']].corr().unstack()
corr_df.columns = ['Correlation_Val1_Val1', 'Correlation_Val1_Val2', 'Correlation_Val2_Val1', 'Correlation_Val2_Val2']
corr_df = corr_df.reset_index().drop(columns=['Correlation_Val1_Val1', 'Correlation_Val2_Val2', 'Correlation_Val2_Val1']) 'v2v1cor', 'v2v2cor'])

这将导致:

enter image description here


0

有趣的是,这也可以工作,并产生优美的输出

    df.groupby('ID')['Val1'].corr(df['Val2'])

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接