Creazione di una mappa di calore da panda DataFrame


112

Ho un dataframe generato dal pacchetto Pandas di Python. Come posso generare una mappa di calore utilizzando DataFrame dal pacchetto 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
>>> 

Cosa hai provato in termini di creazione di una mappa di calore o di ricerca? Senza saperne di più, consiglierei di convertire i tuoi dati e di utilizzare questo metodo
studente il

@joelostblom Questa non è una risposta, è un commento, ma il problema è che non ho abbastanza reputazione per poter fare un commento. Sono un po 'sconcertato perché il valore di output della matrice e dell'array originale sono completamente diversi. Vorrei stampare nella mappa termica i valori reali, non alcuni diversi. Qualcuno può spiegarmi perché sta succedendo questo. Ad esempio: * dati indicizzati originali: aaa / A = 2.431645 * valori stampati nella mappa termica: aaa / A = 1.06192
Monitotier

@Monitotier Poni una nuova domanda e includi un esempio di codice completo di ciò che hai provato. Questo è il modo migliore per convincere qualcuno ad aiutarti a capire cosa c'è che non va! Puoi collegarti a questa domanda se ritieni che sia rilevante.
joelostblom

Risposte:


82

Vuoi 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()

Questo da:

Esempio di output


5
C'è qualche discussione interessante qui su pcolorvs. imshow.
LondonRob

1
... e inoltre pcolormesh, che è ottimizzato per questo tipo di grafica.
Eric O Lebigot

180

Per le persone che guardano questo oggi, consiglierei il Seaborn heatmap()come documentato qui .

L'esempio sopra sarebbe fatto come segue:

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)

Dov'è %matplotlibuna funzione magica IPython per chi non lo conosce.


Perché non dovresti usare i panda?
tommy.carstensen

9
Seaborn e Panda funzionano bene insieme, quindi useresti comunque Panda per ottenere i tuoi dati nella forma giusta. Seaborn è specializzato in grafici statici e rende semplice la creazione di una mappa di calore da un Pandas DataFrame.
Brideau

Sembra che questo collegamento sia morto; potresti aggiornarlo !? Inoltre, come dovrei eseguire il codice sopra con import matplotlib.pyplot as plt?
Cleb

Ehi @ Cleb, ho dovuto aggiornarlo alla pagina archiviata perché non sembra essere in alto da nessuna parte. Dai un'occhiata ai loro documenti per l'utilizzo con pyplot: stanford.edu/~mwaskom/software/seaborn-dev/tutorial/…
Brideau

Usa import matplotlib.pyplot as pltinvece di %matplotlib inlinee finisci con plt.show()per vedere effettivamente la trama.
tsveti_iko

83

Se non hai bisogno di una trama per dire, e sei semplicemente interessato ad aggiungere colore per rappresentare i valori in un formato tabella, puoi utilizzare il style.background_gradient()metodo del frame di dati panda. Questo metodo colora la tabella HTML visualizzata durante la visualizzazione dei frame di dati dei panda, ad esempio nel JupyterLab Notebook e il risultato è simile all'utilizzo della "formattazione condizionale" nel software per fogli di calcolo:

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

inserisci qui la descrizione dell'immagine

Per un utilizzo dettagliato, vedere la risposta più elaborata che ho fornito in precedenza sullo stesso argomento e la sezione sullo stile della documentazione dei panda .


4
Dannazione, questa risposta è in realtà quella che stavo cercando. IMO, dovrebbe essere più alto (+1).
ponadto

7
Questa risposta non è una soluzione valida alla domanda pubblicata. La colorazione del gradiente di sfondo di Pandas prende in considerazione ogni riga o ogni colonna separatamente mentre la colorazione pcolor o pcolormesh di matplotlib tiene conto dell'intera matrice. Prendiamo ad esempio il seguente codice che pd.DataFrame([[1, 1], [0, 3]]).style.background_gradient(cmap='summer') risulta in una tabella con due, ciascuno con un colore diverso.
Toni Penya-Alba

4
@ ToniPenya-Alba La domanda riguarda come generare una mappa di calore da un dataframe panda, non come replicare il comportamento di pcolor o pcolormesh. Se sei interessato a quest'ultimo per i tuoi scopi, puoi usare axis=None(da panda 0.24.0).
joelostblom

2
@joelostblom Non intendevo il mio commento come in "riproduci uno strumento o un altro comportamento" ma come in "di solito si vogliono che tutti gli elementi nella matrice seguano la stessa scala invece di avere scale diverse per ogni riga / colonna". Come fai notare, ci axis=Noneriesce e, a mio parere, dovrebbe far parte della tua risposta (soprattutto perché non sembra essere documentato 0 )
Toni Penya-Alba

2
@ ToniPenya-Alba Ho già fatto axis=Noneparte della risposta dettagliata che linko sopra, insieme ad alcune altre opzioni perché sono d'accordo con te sul fatto che alcune di queste opzioni abilitano il comportamento comunemente desiderato. Ho anche notato la mancanza di documentazione ieri e ho aperto un PR .
joelostblom

17

L' sns.heatmapAPI utile è qui . Controlla i parametri, ce ne sono un buon numero. Esempio:

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)

inserisci qui la descrizione dell'immagine


4

Se vuoi una mappa termica interattiva da un Pandas DataFrame e stai usando un notebook Jupyter, puoi provare il Widget Clustergrammer-Widget interattivo, guarda il taccuino interattivo su NBViewer qui , documentazione qui

inserisci qui la descrizione dell'immagine

E per set di dati più grandi puoi provare il widget WebGL Clustergrammer2 in sviluppo (esempio di notebook qui )


1
wow questo è molto carino! bello vedere alcuni bei pacchetti in arrivo su python - stanco di dover usare R magics
Sos

2

Si prega di notare che gli autori seabornsolo vogliono seaborn.heatmap di lavorare con dataframes categoriali. Non è generale.

Se il tuo indice e le colonne sono valori numerici e / o datetime, questo codice ti servirà bene.

La funzione di mappatura termica di Matplotlib pcolormeshrichiede contenitori invece di indici , quindi c'è del codice elaborato per creare contenitori dai tuoi indici di dataframe (anche se il tuo indice non è equidistante!).

Il resto è semplicemente 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)

Chiamalo usando heatmap(df)e guardalo usando plt.show().

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.