在pandas中从相关矩阵返回最高和最低的相关性

4

我有一大批股票数据,想要建立一个数据框架,从相关矩阵中选出排名前两个和后两个的股票以及它们的实际相关性。

假设这个矩阵corr长这样:

  A    B    C    D    E
A 1.00 0.65 0.31 0.94 0.55
B 0.87 1.00 0.96 0.67 0.41
C 0.95 0.88 1.00 0.72 0.69
D 0.64 0.84 0.99 1.00 0.78
E 0.71 0.62 0.89 0.32 1.00

我要做的是能够返回最佳的两只股票,且它们之间的相关性最小,对于股票A、B、C、D和E,同时排除每个股票与自身相关性为1.00的情况。
所得到的数据框或任何易于显示的形式应如下所示:
Stock 1st 1st_Val 2nd 2nd_Val Last Last_Val
A     D   0.94    B   0.65    C    0.31
B     C   0.96    A   0.87    E    0.41
C     A   0.95    B   0.88    E    0.69
D     C   0.99    B   0.84    A    0.64
E     C   0.89    A   0.71    D    0.32

到目前为止,我已经能够使用corr[stock].nlargest().index[0:].tolist()查看并返回相关的股票名称,并从每个列表中取出[1][2][-1],将它们放入字典中,然后再构建数据框架。但我无法返回相关系数值,而且我怀疑我的方法也不是最高效的。
非常感谢您的任何帮助,谢谢。

1
相关矩阵不应该是对称的吗?还是你给出的例子只是一个示例矩阵? - TYZ
相关矩阵可以是非对称的,在金融数据中相当常见。 - CAPSLOCK
@Gio 相关矩阵永远不可能是非对称的。来自 维基百科因为第 i 个随机变量与第 j 个随机变量的协方差就是第 j 个随机变量与第 i 个随机变量的协方差,每个协方差矩阵都是对称的。我知道这是针对协方差矩阵的,但同样适用于相关矩阵。 - pault
@pault 找不到我想要的文件,但这里有其他人的工作(相当引用,因此我认为值得信赖)[paper1](https://www0.gsb.columbia.edu/faculty/aang/papers/corr.pdf),[paper2](https://link.springer.com/article/10.1140/epjb/e2012-30085-3)。另一个例子是价格波动与价格变动的相关性。对于给定的价格变化(P),如果P的符号为负,则波动性会上升更多。(即,如果某只股票的价值为`X`,如果该股票下跌了10美元,它将比同一只股票上涨10美元更增加波动性) - CAPSLOCK
4个回答

5

您的条件难以概括成一个命令,但这里有一种方法可以采用。

去除对角线

import numpy as np
np.fill_diagonal(corr.values, np.nan)
print(corr)
#      A     B     C     D     E
#A   NaN  0.65  0.31  0.94  0.55
#B  0.87   NaN  0.96  0.67  0.41
#C  0.95  0.88   NaN  0.72  0.69
#D  0.64  0.84  0.99   NaN  0.78
#E  0.71  0.62  0.89  0.32   NaN

查找最高的 2 列和最低的列名称

您可以使用在寻找每个 Pandas 数据帧行中前 n 个最高值列的名称问题上给出的答案,以获取每行(股票)的前 2 个和最后一个值。

order_top2 = np.argsort(-corr.values, axis=1)[:, :2]
order_bottom = np.argsort(corr.values, axis=1)[:, :1]

result_top2 = pd.DataFrame(
    corr.columns[order_top2], 
    columns=['1st', '2nd'],
    index=corr.index
)

result_bottom = pd.DataFrame(
    corr.columns[order_bottom], 
    columns=['Last'],
    index=corr.index
)

result = result_top2.join(result_bottom)
#  1st 2nd Last
#A   D   B    C
#B   C   A    E
#C   A   B    E
#D   C   B    A
#E   C   A    D

现在使用pandas.DataFrame.lookup函数,获取result中每一列对应的corr列的值。
for x in result.columns:
    result[x+"_Val"] = corr.lookup(corr.index, result[x])
print(result)
#  1st 2nd Last  1st_Val  2nd_Val  Last_Val
#A   D   B    C     0.94     0.65      0.31
#B   C   A    E     0.96     0.87      0.41
#C   A   B    E     0.95     0.88      0.69
#D   C   B    A     0.99     0.84      0.64
#E   C   A    D     0.89     0.71      0.32

重新排序列(可选)

print(result[['1st', '1st_Val', '2nd', '2nd_Val', 'Last', 'Last_Val']])
#  1st  1st_Val 2nd  2nd_Val Last  Last_Val
#A   D     0.94   B     0.65    C      0.31
#B   C     0.96   A     0.87    E      0.41
#C   A     0.95   B     0.88    E      0.69
#D   C     0.99   B     0.84    A      0.64
#E   C     0.89   A     0.71    D      0.32

1
如果您需要可视化结果,但实际上不需要获取和处理实际相关值,为什么不使用一个非常简单的 热力图呢?您还可以调整图形以在每个方块上显示数字。
import seaborn as sns
import pandas as pd

 dict = {'Date':['2018-01-01','2018-01-02','2018-01-03','2018-01-04','2018-01-05'],'Col1':[1,2,3,4,5],'Col2':[1.1,1.2,1.3,1.4,1.5],'Col3':[0.33,0.98,1.54,0.01,0.99],'Col4':[8,9.98,6,0.01,0.1],'Col1':[19,42,3,0.4,51]}
df = pd.DataFrame(dict, columns=dict.keys())
sns.heatmap(df.corr())

heatmap


嗨,伙计,抱歉问个问题,sns.heatmap(df.corr()) 对我没有任何作用,因为我不使用jypiter,我只是在pycharm上,我需要做.show()或其他什么吗?我就是看不到热图,谢谢。 - top bantz
@topbantz 很可能你可以在这里找到解决方案。 - CAPSLOCK
一直在尝试使用sns.plt.show(),结果发现我只需要plt.show()。谢谢伙计。 - top bantz

1

另一种依赖于现代熊猫风格的答案。我没有找到第二大相关性的好解决方案。如果我找到了,我会编辑答案。

### Create an example df
df = pd.DataFrame(data = {"A":pd.np.random.randn(10),
                    "B":pd.np.random.randn(10),
                    "C":pd.np.random.randn(10),
                    "D":pd.np.random.randn(10),
                        }
                )


# Solution
(
df.corr() #correlation matrix
  .replace(1, pd.np.nan) # replace the matrix with nans
  .assign(  # assign new variables
            First = lambda x: x.loc[["A","B","C","D"], ["A","B","C","D"]].idxmax(axis = 1), # Biggest correlation idx
            First_value = lambda x: x.loc[["A","B","C","D"], ["A","B","C","D"]].max(axis = 1), # Biggest correlation
            Last = lambda x: x.loc[["A","B","C","D"],["A","B","C","D"]].idxmin(axis = 1), # Smallest correlation idx
            Last_value = lambda x: x.loc[["A","B","C","D"],["A","B","C","D"]].idxmin(axis = 1), # Smallest correlation
              )
)


我使用.loc[["A","B","C","D"],["A","B","C","D"]],以便操作仅在未修改的数据帧上进行。
          A         B         C         D First  First_value Last Last_value
A       NaN -0.085776 -0.203110 -0.003450     D    -0.003450    C          C
B -0.085776       NaN -0.110402  0.687283     D     0.687283    C          C
C -0.203110 -0.110402       NaN  0.017644     D     0.017644    A          A
D -0.003450  0.687283  0.017644       NaN     B     0.687283    A          A

你在 Last_value 中有一个拼写错误。如何扩展以获取第二高的值?此外,replace(1, np.nan) 假定没有两个变量是100%相关的(即假定没有非对角线1)。 - pault

0

corr.unstack().min() -> 用于查找最小值

corr.unstack().idxmin() -> 用于查找索引


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