Créer une carte thermique à partir de pandas DataFrame

112

J'ai un dataframe généré à partir du package Pandas de Python. Comment puis-je générer une carte thermique en utilisant DataFrame à partir du package 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
>>> 
Curieuse
la source
Qu'avez-vous essayé en termes de création d'une carte thermique ou de recherche? Sans en savoir plus, je vous recommande de convertir vos données et d'utiliser cette méthode
apprenant le
@joelostblom Ce n'est pas une réponse, c'est un commentaire, mais le problème est que je n'ai pas assez de réputation pour pouvoir faire un commentaire. Je suis un peu déconcerté car la valeur de sortie de la matrice et le tableau d'origine sont totalement différents. Je voudrais imprimer dans la carte thermique les valeurs réelles, pas certaines différentes. Quelqu'un peut-il m'expliquer pourquoi cela se produit. Par exemple: * données d'origine indexées: aaa / A = 2.431645 * valeurs imprimées dans la carte thermique: aaa / A = 1.06192
Monitotier
@Monitotier Veuillez poser une nouvelle question et inclure un exemple de code complet de ce que vous avez essayé. C'est la meilleure façon de demander à quelqu'un de vous aider à comprendre ce qui ne va pas! Vous pouvez créer un lien vers cette question si vous pensez qu'elle est pertinente.
joelostblom

Réponses:

82

Vous voulez 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()

Cela donne:

Exemple de sortie

chthonicdaemon
la source
5
Il y a une discussion intéressante ici sur pcolorvs imshow..
LondonRob
1
… Et aussi pcolormesh, qui est optimisé pour ce type de graphisme.
Eric O Lebigot
180

Pour les personnes qui regardent cela aujourd'hui, je recommanderais le Seaborn heatmap()tel que documenté ici .

L'exemple ci-dessus serait fait comme suit:

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)

Où se %matplotlibtrouve une fonction magique IPython pour ceux qui ne sont pas familiers.

Brideau
la source
Pourquoi n'utiliseriez-vous pas des pandas?
tommy.carstensen
9
Seaborn et Pandas fonctionnent bien ensemble, vous utiliseriez donc toujours Pandas pour mettre vos données sous la bonne forme. Seaborn se spécialise dans les graphiques statiques et simplifie la création d'une carte thermique à partir d'un Pandas DataFrame.
Brideau
Il semble que ce lien est mort; pourriez-vous le mettre à jour !? De plus, comment exécuter le code ci-dessus avec import matplotlib.pyplot as plt?
Cleb
Hé @Cleb, j'ai dû le mettre à jour vers la page archivée car elle ne semble pas être visible nulle part. Jetez un œil à leur documentation pour l'utiliser avec pyplot: stanford.edu/~mwaskom/software/seaborn-dev/tutorial/…
Brideau
Utilisez import matplotlib.pyplot as pltau lieu de %matplotlib inlineet terminez par plt.show()pour voir réellement l'intrigue.
tsveti_iko
83

Si vous n'avez pas besoin d'un tracé en soi, et que vous êtes simplement intéressé par l'ajout de couleur pour représenter les valeurs dans un format de tableau, vous pouvez utiliser la style.background_gradient()méthode du bloc de données pandas. Cette méthode colorise le tableau HTML qui est affiché lors de l'affichage des cadres de données pandas dans, par exemple, le bloc-notes JupyterLab et le résultat est similaire à l'utilisation de la "mise en forme conditionnelle" dans un tableur:

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

entrez la description de l'image ici

Pour une utilisation détaillée, veuillez consulter la réponse plus élaborée j'ai fournie sur le même sujet précédemment et la section de style de la documentation pandas .

joelostblom
la source
4
Merde, cette réponse est en fait celle que je cherchais. IMO, devrait être plus élevé (+1).
ponadto
7
Cette réponse n'est pas une solution valable à la question posée. La coloration des dégradés de fond Pandas prend en compte soit chaque ligne, soit chaque colonne séparément tandis que la coloration pcolor ou pcolormesh de matplotlib prend en compte l'ensemble de la matrice. Prenons par exemple le code suivant pd.DataFrame([[1, 1], [0, 3]]).style.background_gradient(cmap='summer') donne un tableau avec deux, chacun d'eux avec une couleur différente.
Toni Penya-Alba
4
@ ToniPenya-Alba La question est de savoir comment générer une carte thermique à partir d'un dataframe pandas, pas comment reproduire le comportement de pcolor ou pcolormesh. Si vous êtes intéressé par ce dernier pour vos propres besoins, vous pouvez utiliser axis=None(depuis pandas 0.24.0).
joelostblom
2
@joelostblom Je ne voulais pas dire mon commentaire comme dans "reproduire un outil ou un autre comportement" mais comme dans "généralement on veut que tous les éléments de la matrice suivent la même échelle au lieu d'avoir des échelles différentes pour chaque ligne / colonne". Comme vous le faites remarquer, y axis=Noneparvient et, à mon avis, cela devrait faire partie de votre réponse (d'autant plus que cela ne semble pas être documenté 0 )
Toni Penya-Alba
2
@ ToniPenya-Alba J'ai déjà fait une axis=Nonepartie de la réponse détaillée à laquelle je renvoie ci- dessus, ainsi que quelques autres options car je suis d'accord avec vous que certaines de ces options permettent un comportement généralement souhaité. J'ai également remarqué le manque de documentation hier et j'ai ouvert un PR .
joelostblom
17

L' sns.heatmapAPI utile est ici . Vérifiez les paramètres, il y en a un bon nombre. Exemple:

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)

entrez la description de l'image ici

Brad Solomon
la source
4

Si vous voulez une carte thermique interactive à partir d'un Pandas DataFrame et que vous exécutez un notebook Jupyter, vous pouvez essayer le widget interactif Clustergrammer-Widget , voir le notebook interactif sur NBViewer ici , documentation ici

entrez la description de l'image ici

Et pour des ensembles de données plus volumineux, vous pouvez essayer le widget WebGL Clustergrammer2 en développement (exemple de notebook ici )

Nick Fernandez
la source
1
wow c'est très chouette! bon de voir de jolis paquets arriver sur python - fatigué de devoir utiliser R magics
Sos
2

Veuillez noter que les auteurs de seabornne veulent que seaborn.heatmap travailler qu'avec des dataframes catégoriques. Ce n'est pas général.

Si votre index et vos colonnes sont des valeurs numériques et / ou datetime, ce code vous sera très utile.

La fonction de cartographie thermique de Matplotlib pcolormeshnécessite des bins au lieu d' index , il existe donc du code sophistiqué pour créer des bins à partir de vos index de dataframe (même si votre index n'est pas uniformément espacé!).

Le reste est simplement np.meshgridet 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)

Appelez-le en utilisant heatmap(df), et voyez-le en utilisant plt.show().

entrez la description de l'image ici

OrangeSorbet
la source