相关性热力图

90
我想用热力图来表示相关矩阵。在R中有一个叫做correlogram的东西,但我不认为Python中有这样的功能。
我该如何做到这一点?值的范围从-1到1,例如:
[[ 1.          0.00279981  0.95173379  0.02486161 -0.00324926 -0.00432099]
 [ 0.00279981  1.          0.17728303  0.64425774  0.30735071  0.37379443]
 [ 0.95173379  0.17728303  1.          0.27072266  0.02549031  0.03324756]
 [ 0.02486161  0.64425774  0.27072266  1.          0.18336236  0.18913512]
 [-0.00324926  0.30735071  0.02549031  0.18336236  1.          0.77678274]
 [-0.00432099  0.37379443  0.03324756  0.18913512  0.77678274  1.        ]]

我能根据另一个问题生成以下热力图,但问题是我的值在0处被“截断”,所以我希望有一张从蓝色(-1)到红色(1)的地图,或者类似的东西,但这里的负值没有以适当的方式呈现。

enter image description here

这是那段代码:
plt.imshow(correlation_matrix,cmap='hot',interpolation='nearest')

我已经编辑了问题,你可以检查一下。 - Kobe-Wan Kenobi
7个回答

113
另一种选择是使用seaborn中的热力图函数来绘制协方差。这个例子使用了seaborn中的'mpg'数据集。
import seaborn as sns
%matplotlib inline

# load the Auto dataset
auto_df = sns.load_dataset('mpg')

# calculate the correlation matrix on the numeric columns
corr = auto_df.select_dtypes('number').corr()

# plot the heatmap
sns.heatmap(corr)

enter image description here

如果你想更加高级一些,你可以使用Pandas Style,例如:
cmap = sns.diverging_palette(5, 250, as_cmap=True)

def magnify():
    return [dict(selector="th",
                 props=[("font-size", "7pt")]),
            dict(selector="td",
                 props=[('padding', "0em 0em")]),
            dict(selector="th:hover",
                 props=[("font-size", "12pt")]),
            dict(selector="tr:hover td:hover",
                 props=[('max-width', '200px'),
                        ('font-size', '12pt')])
]

corr.style.background_gradient(cmap, axis=1)\
    .format(precision=3)\
    .set_properties(**{'max-width': '80px', 'font-size': '10pt'})\
    .set_caption("Hover to magify")\
    .set_table_styles(magnify())

enter image description here


2
我尝试使用这个,结果遇到了一个问题,请参见这个新的SO问题 - Alison K
2
仔细观察可以发现,这个问题所涉及的问题会影响到这个解决方案。请仔细查看accelerationyearorigin的系数,0.29、0.21和0.18在两个出现位置上的颜色不同。 - Alison K
3
首行中的rpy已被弃用: No module named 'pandas.rpy'. 如何修复这个热力图的错误? - develarist
这段代码无法运行,会出现错误:ModuleNotFoundError: No module named 'pandas.rpy'。显然,没有pandas.rpy2模块。rpy2是一个单独的Python库。 - Yustina Ivanova

52

这个怎么样?

import seaborn as sb
corr = df.corr()
sb.heatmap(corr, cmap="Blues", annot=True)

绘图结果


30
如果您的数据在Pandas DataFrame中,您可以使用Seaborn的heatmap函数创建所需的图表。

如果您的数据在Pandas DataFrame中,您可以使用Seaborn的heatmap函数创建所需的图表。

import seaborn as sns

Var_Corr = df.corr()
# plot the heatmap and annotation on it
sns.heatmap(Var_Corr, xticklabels=Var_Corr.columns, yticklabels=Var_Corr.columns, annot=True)

相关性图

从问题中来看,数据似乎是以NumPy数组的形式存在。如果该数组名称为numpy_data,在使用上述步骤之前,您需要使用以下方法将其转换为Pandas DataFrame:

import pandas as pd
df = pd.DataFrame(numpy_data)

3
欢迎来到Stack Overflow并感谢您的贡献!请看一下我如何编辑您的答案以了解如何使用代码语法(在每行前添加4个空格)。此外,最佳实践是在函数调用后添加逗号后的空格,这样更容易进行视觉解析。 - Steven C. Howell

12

以下代码将生成这个图形:

输入图像描述

import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np

# A list with your data slightly edited
l = [1.0,0.00279981,0.95173379,0.02486161,-0.00324926,-0.00432099,
0.00279981,1.0,0.17728303,0.64425774,0.30735071,0.37379443,
0.95173379,0.17728303,1.0,0.27072266,0.02549031,0.03324756,
0.02486161,0.64425774,0.27072266,1.0,0.18336236,0.18913512,
-0.00324926,0.30735071,0.02549031,0.18336236,1.0,0.77678274,
-0.00432099,0.37379443,0.03324756,0.18913512,0.77678274,1.00]

# Split list
n = 6
data = [l[i:i + n] for i in range(0, len(l), n)]

# A dataframe
df = pd.DataFrame(data)

def CorrMtx(df, dropDuplicates = True):

    # Your dataset is already a correlation matrix.
    # If you have a dateset where you need to include the calculation
    # of a correlation matrix, just uncomment the line below:
    # df = df.corr()

    # Exclude duplicate correlations by masking uper right values
    if dropDuplicates:    
        mask = np.zeros_like(df, dtype=np.bool)
        mask[np.triu_indices_from(mask)] = True

    # Set background color / chart style
    sns.set_style(style = 'white')

    # Set up  matplotlib figure
    f, ax = plt.subplots(figsize=(11, 9))

    # Add diverging colormap from red to blue
    cmap = sns.diverging_palette(250, 10, as_cmap=True)

    # Draw correlation plot with or without duplicates
    if dropDuplicates:
        sns.heatmap(df, mask=mask, cmap=cmap, 
                square=True,
                linewidth=.5, cbar_kws={"shrink": .5}, ax=ax)
    else:
        sns.heatmap(df, cmap=cmap, 
                square=True,
                linewidth=.5, cbar_kws={"shrink": .5}, ax=ax)


CorrMtx(df, dropDuplicates = False)

在宣布杰出的seaborn corrplot将被弃用后,我做了这个东西。上面的片段基于seaborn heatmap制作了一个相似的相关性图。你还可以指定颜色范围,并选择是否删除重复的相关性。请注意,我使用了与你相同的数字,但是我将它们放在了pandas dataframe中。关于颜色选择,你可以查看sns.diverging_palette的文档。你要求使用蓝色,但在这个特定的颜色比例尺范围内不适用于你的样本数据。对于两个观察值0.95173379,尝试更改为-0.95173379,你会得到以下结果:

enter image description here


1
我喜欢你的方法,因为与其他答案不同,得到的颜色映射在0.0处是白色。 - AlvaroP
1
@AlvaroP 谢谢!这就是正确的方式。 - vestland
1
很好。对于新版本的numpy(1.24.2),它将是dtype=bool而不是dtype=np.bool。另外,不确定为什么我的0.0不是白色的。 - FullMetalScientist
1
@FullMetalScientist 编辑:我使用了热力图的 norm 选项,按照链接将0.0设置为白色。 - FullMetalScientist

4
import seaborn as sns
# label to make it neater
labels = {
's1':'vibration sensor',  
'temp':'outer temperature', 
'actPump':'flow rate', 
'pressIn':'input pressure', 
'pressOut':'output pressure', 
'DrvActual':'acutal RPM',
'DrvSetPoint':'desired RPM',
'DrvVolt':'input voltage',
'DrvTemp':'inside temperature',
'DrvTorque':'motor torque'}

corr = corr.rename(labels)

# remove the top right triange - duplicate information
mask = np.zeros_like(corr, dtype=np.bool)
mask[np.triu_indices_from(mask)] = True

# Colors
cmap = sns.diverging_palette(500, 10, as_cmap=True)

# uncomment this if you want only the lower triangle matrix 
# ans=sns.heatmap(corr, mask=mask,  linewidths=1, cmap=cmap, center=0)

ans=sns.heatmap(corr,  linewidths=1, cmap=cmap, center=0)

#save image 
figure = ans.get_figure()    
figure.savefig('correlations.png', dpi=800)

3

这些都是合理的答案,看起来问题大多已经解决了,但我想补充一个不使用matplotlib/seaborn的解决方案。特别地,这个解决方案使用的是altair,它基于图形语法(对于从ggplot来的人可能更加熟悉)。

# import libraries
import pandas as pd
import altair as alt

# download dataset and create correlation
df = pd.read_json("https://raw.githubusercontent.com/vega/vega-datasets/master/data/penguins.json")
corr_df = df.corr()

# data preparation
pivot_cols = list(corr_df.columns)
corr_df['cat'] = corr_df.index

# actual chart
alt.Chart(corr_df).mark_rect(tooltip=True)\
   .transform_fold(pivot_cols)\
   .encode(
       x="cat:N", 
       y='key:N', 
       color=alt.Color("value:Q", scale=alt.Scale(scheme="redyellowblue"))
   )


这将导致:

enter image description here

如果您需要在这些单元格中添加标签,只需将#实际图表部分替换为类似以下内容的内容。
base = alt.Chart(corr_df).transform_fold(pivot_cols).encode(x="cat:N",  y='key:N').properties(height=300, width=300)
boxes = base.mark_rect().encode(color=alt.Color("value:Q", scale=alt.Scale(scheme="redyellowblue")))
labels = base.mark_text(size=30, color="white").encode(text=alt.Text("value:Q", format="0.1f"))
boxes + labels

enter image description here


2

你能否给我一个例子?我对Python不是很熟悉,所以在这方面遇到了问题。在你提供的例子中,他们使用X,Y = np.meshgrid(x,y),但我没有这个? - Kobe-Wan Kenobi
meshgrid 的作用只是为每个点分配一个坐标对,以便将其绘制为热图。 - ypnos
但是链接是另一个SO答案。可以将其视为重复处理。 - ypnos

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