Tworzenie mapy cieplnej z pand DataFrame

112

Mam ramkę danych wygenerowaną z pakietu Pandas Pythona. Jak mogę wygenerować mapę cieplną za pomocą DataFrame z pakietu pandy.

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
>>> 
Ciekawy
źródło
Czego próbowałeś w zakresie tworzenia mapy popularności lub badań? Nie wiedząc więcej, zalecałbym konwersję danych i użycie tej metody
uczeń
@joelostblom To nie jest odpowiedź, to komentarz, ale problem polega na tym, że nie mam wystarczającej reputacji, aby móc komentować. Jestem trochę zaskoczony, ponieważ wartość wyjściowa macierzy i oryginalna tablica są zupełnie inne. Chciałbym wydrukować na mapie ciepła wartości rzeczywiste, a nie inne. Czy ktoś może mi wyjaśnić, dlaczego tak się dzieje. Na przykład: * oryginalne zindeksowane dane: aaa / A = 2,431645 * wydrukowane wartości na mapie cieplnej: aaa / A = 1,06192
Monitotier
@Monitotier Proszę zadać nowe pytanie i dołączyć pełny przykład kodu tego, co wypróbowałeś. To najlepszy sposób, aby ktoś pomógł Ci dowiedzieć się, co jest nie tak! Możesz podać link do tego pytania, jeśli uważasz, że jest ono istotne.
joelostblom

Odpowiedzi:

82

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

To daje:

Próbka wyjściowa

chthonicdaemon
źródło
5
Jest jakaś interesująca dyskusja tu o pcolorporównaniu imshow.
LondonRob
1
… A także pcolormeshzoptymalizowany pod kątem tego rodzaju grafiki.
Eric O Lebigot
180

Osobom, które patrzą na to dzisiaj, poleciłbym Seaborn heatmap()zgodnie z dokumentacją tutaj .

Powyższy przykład zostałby wykonany w następujący sposób:

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)

Gdzie %matplotlibjest magiczna funkcja IPythona dla nieznanych osób.

Brideau
źródło
Dlaczego nie użyłbyś pand?
tommy.carstensen
9
Morski i pandy dobrze ze sobą współpracują, więc nadal będziesz używać pand, aby nadać swoim danym właściwy kształt. Seaborn specjalizuje się jednak w statycznych wykresach i sprawia, że ​​tworzenie mapy cieplnej z Pandas DataFrame jest proste.
Brideau
Wygląda na to, że ten link nie działa; czy mógłbyś to zaktualizować !? Co więcej, jak mógłbym uruchomić powyższy kod z import matplotlib.pyplot as plt?
Cleb
Hej @Cleb, musiałem zaktualizować go do zarchiwizowanej strony, ponieważ nigdzie nie wygląda na to, że jest na górze. Spójrz na ich dokumenty dotyczące używania go z pyplot: stanford.edu/~mwaskom/software/seaborn-dev/tutorial/…
Brideau
Użyj import matplotlib.pyplot as pltzamiast %matplotlib inlinei zakończ plt.show(), aby zobaczyć fabułę.
tsveti_iko
83

Jeśli nie potrzebujesz wykresu na powiedzenie, a jesteś po prostu zainteresowany dodaniem koloru do reprezentowania wartości w formacie tabeli, możesz użyć style.background_gradient()metody ramki danych pandy. Ta metoda koloruje tabelę HTML, która jest wyświetlana podczas przeglądania ramek danych pandy w np. JupyterLab Notebook, a wynik jest podobny do użycia „formatowania warunkowego” w oprogramowaniu do obsługi arkuszy kalkulacyjnych:

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

wprowadź opis obrazu tutaj

Aby uzyskać szczegółowe informacje, zapoznaj się z bardziej szczegółową odpowiedzią, której udzieliłem wcześniej na ten sam temat, oraz sekcją dotyczącą stylizacji w dokumentacji pand .

joelostblom
źródło
4
Cholera, ta odpowiedź jest właśnie tą, której szukałem. IMO, powinno być wyższe (+1).
ponadto
7
Ta odpowiedź nie jest prawidłowym rozwiązaniem opublikowanego pytania. Kolorowanie gradientowe tła pandy uwzględnia osobno każdy wiersz lub każdą kolumnę, podczas gdy kolorystyka pcolor lub pcolormesh programu matplotlib bierze pod uwagę całą macierz. Weźmy na przykład poniższy kod pd.DataFrame([[1, 1], [0, 3]]).style.background_gradient(cmap='summer') w tabeli zawierającej dwa jedynki, każdy w innym kolorze.
Toni Penya-Alba,
4
@ ToniPenya-Alba Pytanie dotyczy tego, jak wygenerować mapę cieplną z pandy dataframe, a nie jak odtworzyć zachowanie pcolor lub pcolormesh. Jeśli jesteś zainteresowany tym drugim do własnych celów, możesz użyć axis=None(od pandy 0.24.0).
joelostblom
2
@joelostblom Nie miałem na myśli mojego komentarza, ponieważ w "odtwarzaj jedno narzędzie lub inne zachowanie", ale tak jak w przypadku "zwykle chce się, aby wszystkie elementy w macierzy miały tę samą skalę, zamiast mieć różne skale dla każdego wiersza / kolumny". Jak zauważyłeś, axis=Noneosiąga to i, moim zdaniem, powinno to być częścią twojej odpowiedzi (zwłaszcza, że ​​nie wydaje się być udokumentowane 0 )
Toni Penya-Alba
2
@ ToniPenya-Alba Przedstawiłem już axis=Noneczęść szczegółowej odpowiedzi, do której odsyłam powyżej, wraz z kilkoma innymi opcjami, ponieważ zgadzam się z tobą, że niektóre z tych opcji umożliwiają powszechnie pożądane zachowanie. Zauważyłem też wczoraj brak dokumentacji i otworzyłem PR .
joelostblom
17

Przydatne sns.heatmapAPI jest tutaj . Sprawdź parametry, jest ich sporo. Przykład:

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)

wprowadź opis obrazu tutaj

Brad Solomon
źródło
4

Jeśli potrzebujesz interaktywnej mapy cieplnej z Pandas DataFrame i korzystasz z notatnika Jupyter, możesz wypróbować interaktywny widżet Clustergrammer-Widget , zobacz interaktywny notatnik w NBViewer tutaj , dokumentacja tutaj

wprowadź opis obrazu tutaj

W przypadku większych zbiorów danych możesz wypróbować rozwijany widget Clustergrammer2 WebGL (przykładowy notatnik tutaj )

Nick Fernandez
źródło
1
wow, to jest bardzo fajne! dobrze widzieć kilka fajnych pakietów przychodzących do Pythona - zmęczony koniecznością używania magii R
Sos
2

Należy pamiętać, że autorzy seaborntylko chcą seaborn.heatmap pracować z kategorycznych dataframes. To nie jest ogólne.

Jeśli twój indeks i kolumny są wartościami liczbowymi i / lub datetime, ten kod będzie ci dobrze służył.

Funkcja mapowania ciepła Matplotlib pcolormeshwymaga pojemników zamiast indeksów , więc istnieje jakiś fantazyjny kod do tworzenia pojemników z indeksów ramek danych (nawet jeśli indeks nie jest równomiernie rozmieszczony!).

Reszta jest po prostu np.meshgridi 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)

Nazwij to używając heatmap(df)i zobacz, jak to działa plt.show().

wprowadź opis obrazu tutaj

OrangeSherbet
źródło