Fazendo mapa de calor de pandas DataFrame

112

Eu tenho um dataframe gerado a partir do pacote Pandas do Python. Como posso gerar mapa de calor usando DataFrame do pacote pandas.

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
>>> 
Curioso
fonte
O que você tentou em termos de criação de um mapa de calor ou pesquisa? Sem saber mais, eu recomendo converter seus dados e usar este método
aluno de
@joelostblom Esta não é uma resposta, é um comentário, mas o problema é que não tenho reputação suficiente para poder fazer um comentário. Estou um pouco perplexo porque o valor de saída da matriz e a matriz original são totalmente diferentes. Gostaria de imprimir no mapa de calor os valores reais, não alguns diferentes. Alguém pode me explicar por que isso está acontecendo. Por exemplo: * dados indexados originais: aaa / A = 2,431645 * valores impressos no mapa de calor: aaa / A = 1,06192
Monitotier
@Monitotier Faça uma nova pergunta e inclua um exemplo de código completo do que você tentou. Esta é a melhor maneira de conseguir que alguém o ajude a descobrir o que está errado! Você pode criar um link para esta pergunta se achar relevante.
joelostblom

Respostas:

82

Você quer 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()

Isto dá:

Amostra de saída

ctônico-demônio
fonte
5
Há alguma discussão interessante aqui sobre pcolorvs. imshow.
LondonRob
1
… E também pcolormesh, que é otimizado para este tipo de gráfico.
Eric O Lebigot
180

Para as pessoas que estão olhando para isso hoje, eu recomendaria o Seaborn heatmap()conforme documentado aqui .

O exemplo acima seria feito da seguinte maneira:

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)

Onde %matplotlibestá uma função mágica do IPython para quem não conhece.

Brideau
fonte
Por que você não usaria pandas?
tommy.carstensen
9
Seaborn e Pandas funcionam bem juntos, então você ainda usaria o Pandas para colocar seus dados na forma certa. A Seaborn é especializada em gráficos estáticos e torna a criação de um mapa de calor a partir de um DataFrame Pandas muito simples.
Brideau de
Parece que este link está morto; você poderia atualizá-lo !? Além disso, como devo executar o código acima com import matplotlib.pyplot as plt?
Cleb
Ei @Cleb, eu tive que atualizá-lo para a página arquivada porque não parece que está em lugar nenhum. Dê uma olhada em seus documentos para usá-lo com pyplot: stanford.edu/~mwaskom/software/seaborn-dev/tutorial/…
Brideau
Use em import matplotlib.pyplot as pltvez de %matplotlib inlinee termine com plt.show()para realmente ver o enredo.
tsveti_iko
83

Se você não precisa de um gráfico por palavra, e está simplesmente interessado em adicionar cores para representar os valores em um formato de tabela, você pode usar o style.background_gradient()método do quadro de dados do pandas. Este método coloriza a tabela HTML que é exibida ao visualizar os quadros de dados do pandas, por exemplo, no JupyterLab Notebook e o resultado é semelhante ao uso de "formatação condicional" no software de planilha:

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

insira a descrição da imagem aqui

Para um uso detalhado, por favor, veja a resposta mais elaborada que forneci no mesmo tópico anteriormente e a seção de estilo da documentação do pandas .

joelostblom
fonte
4
Droga, essa resposta é realmente a que eu estava procurando. IMO, deve ser maior (+1).
Ponadto de
7
Esta resposta não é uma solução válida para a pergunta postada. A coloração gradiente de fundo do Pandas leva em conta cada linha ou cada coluna separadamente, enquanto a coloração pcolor ou pcolormesh de matplotlib leva em consideração toda a matriz. Tome por exemplo os seguintes pd.DataFrame([[1, 1], [0, 3]]).style.background_gradient(cmap='summer') resultados de código em uma tabela com duas unidades, cada uma com uma cor diferente.
Toni Penya-Alba
4
@ ToniPenya-Alba A questão é sobre como gerar um mapa de calor a partir de um dataframe do pandas, não como replicar o comportamento de pcolor ou pcolormesh. Se você estiver interessado no último para seus próprios fins, você pode usar axis=None(desde o pandas 0.24.0).
joelostblom
2
@joelostblom Eu não quis dizer meu comentário como em "reproduzir uma ferramenta ou outro comportamento", mas como em "geralmente se quer todos os elementos da matriz seguindo a mesma escala em vez de ter escalas diferentes para cada linha / coluna". Como você apontou, axis=Noneconsegue isso e, na minha opinião, deveria fazer parte de sua resposta (especialmente porque não parece estar documentado 0 )
Toni Penya-Alba
2
@ ToniPenya-Alba Eu já fiz axis=Noneparte da resposta detalhada que indiquei acima, junto com algumas outras opções porque concordo com você que algumas dessas opções permitem o comportamento comumente desejado. Também notei a falta de documentação ontem e abri um PR .
joelostblom
17

A sns.heatmapAPI útil está aqui . Confira os parâmetros, há um bom número deles. Exemplo:

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)

insira a descrição da imagem aqui

Brad Solomon
fonte
4

Se você deseja um mapa de calor interativo de um Pandas DataFrame e está executando um bloco de notas Jupyter, pode experimentar o Widget interativo Clustergrammer-Widget , consulte o bloco de notas interativo no NBViewer aqui , a documentação aqui

insira a descrição da imagem aqui

E para conjuntos de dados maiores, você pode tentar o widget Clustergrammer2 WebGL em desenvolvimento (bloco de notas de exemplo aqui )

Nick Fernandez
fonte
1
uau, isso é muito legal! bom ver alguns pacotes legais chegando ao python - cansado de ter que usar R magics
Sos
2

Por favor, note que os autores da seabornúnica quer seaborn.heatmap para trabalhar com dataframes categóricas. Não é geral.

Se seu índice e colunas forem valores numéricos e / ou de data e hora, este código será útil para você.

A função de mapeamento de calor Matplotlib pcolormeshrequer bins em vez de índices , então existe algum código sofisticado para construir bins a partir de seus índices de dataframe (mesmo se seu índice não estiver uniformemente espaçado!).

O resto é simplesmente np.meshgride plt.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)

Chame-o de usando heatmap(df)e veja-o usando plt.show().

insira a descrição da imagem aqui

OrangeSherbet
fonte