从 pandas DataFrame 制作热图

Posted

技术标签:

【中文标题】从 pandas DataFrame 制作热图【英文标题】:Making heatmap from pandas DataFrame 【发布时间】:2012-08-30 11:28:24 【问题描述】:

我有一个从 Python 的 Pandas 包生成的数据框。如何使用 pandas 包中的 DataFrame 生成热图。

import numpy as np 
from pandas import *

Index= ['aaa','bbb','ccc','ddd','eee']
Cols = ['A', 'B', 'C','D']
df = DataFrame(abs(np.random.randn(5, 4)), index= Index, columns=Cols)

>>> df
          A         B         C         D
aaa  2.431645  1.248688  0.267648  0.613826
bbb  0.809296  1.671020  1.564420  0.347662
ccc  1.501939  1.126518  0.702019  1.596048
ddd  0.137160  0.147368  1.504663  0.202822
eee  0.134540  3.708104  0.309097  1.641090
>>> 

【问题讨论】:

您在创建热图或研究方面有哪些尝试?在不了解更多信息的情况下,我建议您转换您的数据and using this method @joelostblom 这不是答案,是评论,但问题是我没有足够的声誉来发表评论。我有点困惑,因为矩阵和原始数组的输出值完全不同。我想在热图中打印真实值,而不是一些不同。有人可以解释一下为什么会这样。例如: * 原始索引数据:aaa/A = 2.431645 * 热图中的打印值:aaa/A = 1.06192 @Monitotier 请提出一个新问题,并附上您尝试过的完整代码示例。这是让某人帮助您找出问题所在的最佳方法!如果您认为相关,可以链接到此问题。 【参考方案1】:

惊讶地发现没有人提到更强大、更互动和更易于使用的替代方案。

A)你可以使用情节:

    只需两行即可:

    交互性,

    平滑的刻度,

    颜色基于整个数据框而不是单个列,

    轴上的列名和行索引,

    放大,

    平移,

    内置一键保存为PNG格式,

    自动缩放,

    悬停比较,

    显示值的气泡,因此热图看起来仍然不错,您可以看到 任何你想要的值:

import plotly.express as px
fig = px.imshow(df.corr())
fig.show()

B) 你也可以使用散景:

所有相同的功能都有一点麻烦。但是,如果您不想选择加入 plotly 并且仍然想要所有这些东西,那么仍然值得:

from bokeh.plotting import figure, show, output_notebook
from bokeh.models import ColumnDataSource, LinearColorMapper
from bokeh.transform import transform
output_notebook()
colors = ['#d7191c', '#fdae61', '#ffffbf', '#a6d96a', '#1a9641']
TOOLS = "hover,save,pan,box_zoom,reset,wheel_zoom"
data = df.corr().stack().rename("value").reset_index()
p = figure(x_range=list(df.columns), y_range=list(df.index), tools=TOOLS, toolbar_location='below',
           tooltips=[('Row, Column', '@level_0 x @level_1'), ('value', '@value')], height = 500, width = 500)

p.rect(x="level_1", y="level_0", width=1, height=1,
       source=data,
       fill_color='field': 'value', 'transform': LinearColorMapper(palette=colors, low=data.value.min(), high=data.value.max()),
       line_color=None)
color_bar = ColorBar(color_mapper=LinearColorMapper(palette=colors, low=data.value.min(), high=data.value.max()), major_label_text_font_size="7px",
                     ticker=BasicTicker(desired_num_ticks=len(colors)),
                     formatter=PrintfTickFormatter(format="%f"),
                     label_standoff=6, border_line_color=None, location=(0, 0))
p.add_layout(color_bar, 'right')

show(p)

【讨论】:

【参考方案2】:

你想要matplotlib.pcolor:

import numpy as np 
from pandas import DataFrame
import matplotlib.pyplot as plt

index = ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
columns = ['A', 'B', 'C', 'D']
df = DataFrame(abs(np.random.randn(5, 4)), index=index, columns=columns)

plt.pcolor(df)
plt.yticks(np.arange(0.5, len(df.index), 1), df.index)
plt.xticks(np.arange(0.5, len(df.columns), 1), df.columns)
plt.show()

这给出了:

【讨论】:

有一些关于pcolorimshow 的有趣讨论here。 ……还有pcolormesh,它针对这种图形进行了优化。【参考方案3】:

如果您不需要一个图,并且您只是对添加颜色以表示表格格式的值感兴趣,您可以使用 pandas 数据框的 style.background_gradient() 方法。此方法对在例如查看 pandas 数据帧时显示的 html 表进行着色。 JupyterLab Notebook,结果类似于在电子表格软件中使用“条件格式”:

import numpy as np 
import pandas as pd


index= ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
cols = ['A', 'B', 'C', 'D']
df = pd.DataFrame(abs(np.random.randn(5, 4)), index=index, columns=cols)
df.style.background_gradient(cmap='Blues')

详细用法请看我之前提供的同主题的the more elaborate answer和styling section of the pandas documentation。

【讨论】:

该死的,这个答案实际上是我要找的答案。 IMO,应该更高(+1)。 此答案不是已发布问题的有效解决方案。 Pandas 背景渐变着色分别考虑每一行或每一列,而 matplotlib 的 pcolor 或 pcolormesh 着色考虑整个矩阵。以下面的代码pd.DataFrame([[1, 1], [0, 3]]).style.background_gradient(cmap='summer') 为例,结果是一个包含两个表的表,每个表都有不同的颜色。 @ToniPenya-Alba 问题是关于如何从 pandas 数据框生成热图,而不是如何复制 pcolor 或 pcolormesh 的行为。如果您出于自己的目的对后者感兴趣,可以使用axis=None(自pandas 0.24.0 起)。 @joelostblom 我并不是说我的评论是“重现一种工具或另一种行为”,而是“通常人们希望矩阵中的所有元素都遵循相同的比例而不是具有不同的比例每行/列”。正如您所指出的,axis=None 实现了这一点,并且在我看来,它应该成为您答案的一部分(特别是因为它似乎没有记录在 0) @ToniPenya-Alba 我已经将axis=None 作为我上面链接到的详细答案的一部分,以及其他一些选项,因为我同意你的观点,其中一些选项可以实现通常需要的行为。我还注意到昨天缺少文档和opened a PR。【参考方案4】:

请注意seaborn 的作者仅want seaborn.heatmap 可以处理分类数据框。这不是一般的。

如果您的索引和列是数字和/或日期时间值,则此代码将为您提供良好的服务。

Matplotlib 热映射函数 pcolormesh 需要 bins 而不是 indices,因此有一些花哨的代码可以从您的数据帧索引构建 bin(即使您的索引是'不均匀间隔!)。

剩下的就是np.meshgridplt.pcolormesh

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

def conv_index_to_bins(index):
    """Calculate bins to contain the index values.
    The start and end bin boundaries are linearly extrapolated from 
    the two first and last values. The middle bin boundaries are 
    midpoints.

    Example 1: [0, 1] -> [-0.5, 0.5, 1.5]
    Example 2: [0, 1, 4] -> [-0.5, 0.5, 2.5, 5.5]
    Example 3: [4, 1, 0] -> [5.5, 2.5, 0.5, -0.5]"""
    assert index.is_monotonic_increasing or index.is_monotonic_decreasing

    # the beginning and end values are guessed from first and last two
    start = index[0] - (index[1]-index[0])/2
    end = index[-1] + (index[-1]-index[-2])/2

    # the middle values are the midpoints
    middle = pd.DataFrame('m1': index[:-1], 'p1': index[1:])
    middle = middle['m1'] + (middle['p1']-middle['m1'])/2

    if isinstance(index, pd.DatetimeIndex):
        idx = pd.DatetimeIndex(middle).union([start,end])
    elif isinstance(index, (pd.Float64Index,pd.RangeIndex,pd.Int64Index)):
        idx = pd.Float64Index(middle).union([start,end])
    else:
        print('Warning: guessing what to do with index type %s' % 
              type(index))
        idx = pd.Float64Index(middle).union([start,end])

    return idx.sort_values(ascending=index.is_monotonic_increasing)

def calc_df_mesh(df):
    """Calculate the two-dimensional bins to hold the index and 
    column values."""
    return np.meshgrid(conv_index_to_bins(df.index),
                       conv_index_to_bins(df.columns))

def heatmap(df):
    """Plot a heatmap of the dataframe values using the index and 
    columns"""
    X,Y = calc_df_mesh(df)
    c = plt.pcolormesh(X, Y, df.values.T)
    plt.colorbar(c)

使用heatmap(df)调用它,使用plt.show()查看它。

【讨论】:

你能用虚拟数据显示吗?我的索引出现了一些断言错误。 @jonboy 如果这是我断言索引已排序的断言错误(表示assert index.is_monotonic_increasing or ...lexsorted 的行),这意味着您需要在将数据帧的索引和列传递到此之前对其进行排序功能。有时间我会做一些虚拟数据,抱歉,现在真的很忙。【参考方案5】:

如果您想要来自 Pandas DataFrame 的交互式热图并且您正在运行 Jupyter 笔记本,您可以尝试交互式小部件Clustergrammer-Widget,请参阅 NBViewer 上的交互式笔记本here,文档here

对于更大的数据集,您可以尝试开发中的 Clustergrammer2 WebGL 小部件(示例笔记本 here)

【讨论】:

哇,这非常整洁!很高兴看到一些不错的包来到 python - 厌倦了不得不使用 R 魔法 你知道如何在这个函数中使用 Pd.Dataframe 吗?当我将 df 传递给 net.load 时,Python 抛出错误 你可以使用'net.load_df(df); net.widget();'你可以在这个笔记本上试试这个colab.research.google.com/drive/…【参考方案6】:

对于今天看到这个的人,我会推荐 Seaborn heatmap() 记录在 here。

上面的示例将按如下方式完成:

import numpy as np 
from pandas import DataFrame
import seaborn as sns
%matplotlib inline

Index= ['aaa', 'bbb', 'ccc', 'ddd', 'eee']
Cols = ['A', 'B', 'C', 'D']
df = DataFrame(abs(np.random.randn(5, 4)), index=Index, columns=Cols)

sns.heatmap(df, annot=True)

%matplotlib 对于不熟悉的人来说是一个 IPython 魔术函数。

【讨论】:

为什么不用熊猫? Seaborn 和 Pandas 可以很好地协同工作,因此您仍然可以使用 Pandas 将数据转换为正确的形状。不过,Seaborn 专注于静态图表,并且使从 Pandas DataFrame 制作热图变得非常简单。 这个链接好像失效了;你能更新吗!?此外,我将如何使用import matplotlib.pyplot as plt 运行上述代码? 嘿@Cleb,我不得不将它更新到存档页面,因为它看起来不像它在任何地方。查看他们的文档以将其与 pyplot 一起使用:stanford.edu/~mwaskom/software/seaborn-dev/tutorial/… 使用import matplotlib.pyplot as plt 代替%matplotlib inline 并以plt.show() 结束,以便真正看到情节。【参考方案7】:

有用的sns.heatmap api 是here。查看参数,其中有很多。示例:

import seaborn as sns
%matplotlib inline

idx= ['aaa','bbb','ccc','ddd','eee']
cols = list('ABCD')
df = DataFrame(abs(np.random.randn(5,4)), index=idx, columns=cols)

# _r reverses the normal order of the color map 'RdYlGn'
sns.heatmap(df, cmap='RdYlGn_r', linewidths=0.5, annot=True)

【讨论】:

以上是关于从 pandas DataFrame 制作热图的主要内容,如果未能解决你的问题,请参考以下文章

Pandas:从 DataFrame 列制作字典的最有效方法

如何制作从大型 xlsx 文件加载 pandas DataFrame 的进度条?

如何从pandas DataFrame中制作字典列表?

Pandas DataFrame 到 Seaborn

将熊猫数据框可视化为热图时出现类型错误

使用 Pandas 数据框中的值注释热图