Skip to article frontmatterSkip to article content

06 - Wizualizacja z seaborn

W tym rozdziale

  • Wprowadzenie do seaborn.
  • Zastosowanie seaborn w praktyce:
    • Wykresy jednowymiarowe (histogramy).
    • Dwuwymiarowe wykresy ciągłe (scatterplots i wykresy liniowe).
    • Dwuwymiarowe wykresy kategoryczne (wykresy słupkowe, wykresy pudełkowe i wykresy paskowe).

Wprowadzenie do seaborn

Czym jest seaborn?

seaborn jest pakietem do wizualizacji danych opartym na matplotlib.

  • Ogólnie rzecz biorąc, łatwiej jest tworzyć ładnie wyglądające wykresy z seaborn.
  • Kompromisem jest to, że matplotlib oferuje większą elastyczność.
import seaborn as sns ### ładowanie seaborn
import pandas as pd
import matplotlib.pyplot as plt ## gdyby był potrzebny
import numpy as np
%matplotlib inline 
%config InlineBackend.figure_format = 'retina'

Hierarchia typów wykresów w seaborn

W tym rozdziale (i w następnym) dowiemy się więcej o tym, co dokładnie oznacza ta hierarchia.

title

Przykładowe dane

Tutaj zaczerpniemy z Gapminder.

  • Gapminder to niezależna szwedzka fundacja zajmująca się publikowaniem i analizowaniem danych w celu korygowania błędnych przekonań na temat świata.
  • W latach 1952-2007 posiadała dane na temat life_exp, gdp_cap i population.
df_gapminder = pd.read_csv("data/viz/gapminder_full.csv")
df_gapminder.head(2)
Loading...
df_gapminder.shape
(1704, 6)

Wykresy jednowymiarowe

Wykres jednowymiarowy jest wizualizacją tylko jednej zmiennej, tj. jej rozkładu.

title

Histogramy z sns.histplot

  • Poprzednio rysowaliśmy histogramy z plt.hist.
  • Z seaborn, mozemy uzyć sns.histplot(...).

Zamiast df['col_name'], wykorzystujemy składnię:

sns.histplot(data = dane, x = nazwa_zmiennej)

Stanie się to jeszcze bardziej przydatne, gdy zaczniemy tworzyć wykresy dwuwymiarowe.

# Histogram oczekiwanej długości zycia
sns.histplot(df_gapminder['life_exp']);
<Figure size 640x480 with 1 Axes>

Modyfikowanie liczby przedziałów

Podobnie jak w przypadku plt.hist, możemy modyfikować liczbę przedziałów.

# Mniej przedziałów
sns.histplot(data = df_gapminder, x = 'life_exp', bins = 10, alpha = .6);
<Figure size 640x480 with 1 Axes>
# Więcej przedziałów!
sns.histplot(data = df_gapminder, x = 'life_exp', bins = 100, alpha = .6);
<Figure size 640x480 with 1 Axes>

Modyfikacje osi-y z stat

Domyślnie, sns.histplot wykreśli liczebność każdej kategorii. Możemy to jednak zmienić za pomocą parametru stat:

  • probability: normalizuje tak, że wysokości słupków sumują się do 1.
  • percent: normalizuje tak, że wysokości słupków sumują się do 100.
  • density: normalizuje tak, że całkowita area sumuje się do 1.
# Zwróć uwagę na zmodyfikowaną oś y!
sns.histplot(data = df_gapminder, x = 'life_exp', stat = "probability", alpha = .6);
<Figure size 640x480 with 1 Axes>

Sprawdź się!

Jak stworzyć histogram pokazujący rozkład wartości population w samym roku 2007?

  • Zmodyfikuj ten wykres, aby pokazywał „prawdopodobieństwo”, a nie „liczbę”.
  • Co widzimy na tym wykresie i jak mógł(a)byś go zmienić?
### Twój kod tutaj

Ciągłe wykresy dwuwymiarowe

Wykres zmiennych ciągłych wizualizuje związek między dwoma zmiennymi ciągłymi.

title

Wykresy rozrzutu z sns.scatterplot

Wykres rozrzutu wizualizuje związek między dwiema zmiennymi ciągłymi.

  • Każda obserwacja jest wykreślana jako pojedyncza kropka/znak.
  • Pozycja na osiach (x, y) odzwierciedla wartość tych zmiennych.

Jednym ze sposobów utworzenia scatterplot w seaborn jest użycie sns.scatterplot.

Zależność gdp_cap z life_exp

Czego dowiadujemy się o zmiennej gdp_cap?

sns.scatterplot(data = df_gapminder, x = 'gdp_cap', y = 'life_exp', alpha = .3);
<Figure size 640x480 with 1 Axes>

Zależność gdp_cap_log z life_exp

## Obliczamy i zapisujemy zmienną Log GDP
df_gapminder['gdp_cap_log'] = np.log10(df_gapminder['gdp_cap']) 
## Pokaż log GDP z life exp
sns.scatterplot(data = df_gapminder, x = 'gdp_cap_log', y = 'life_exp', alpha = .3);
<Figure size 640x480 with 1 Axes>

Dodajemy hue - odcień

  • Co jeśli chcemy dodać trzeci komponent, który jest kategoryczny, jak continent?
  • seaborn pozwala nam to zrobić z hue - dodać odcienie.
## Log GDP
df_gapminder['gdp_cap_log'] = np.log10(df_gapminder['gdp_cap']) 
## Pokaz log GDP z life exp
sns.scatterplot(data = df_gapminder[df_gapminder['year'] == 2007],
               x = 'gdp_cap_log', y = 'life_exp', hue = "continent", alpha = .7);
<Figure size 640x480 with 1 Axes>

Dodajemy size

  • Co jeśli chcemy dodać czwarty komponent, który jest ciągły, jak population?
  • seaborn pozwala nam to zrobić z size - powstanie wykres bąbelkowy!
## Log GDP
df_gapminder['gdp_cap_log'] = np.log10(df_gapminder['gdp_cap']) 
## Pokaz log GDP z life exp
sns.scatterplot(data = df_gapminder[df_gapminder['year'] == 2007],
               x = 'gdp_cap_log', y = 'life_exp',
                hue = "continent", size = 'population', alpha = .7);
<Figure size 640x480 with 1 Axes>

Zmiany w pozycji legendy

## Pokaz log GDP z life exp
sns.scatterplot(data = df_gapminder[df_gapminder['year'] == 2007],
               x = 'gdp_cap_log', y = 'life_exp',
                hue = "continent", size = 'population', alpha = .7)

plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0);
<Figure size 640x480 with 1 Axes>

Wykres liniowy z sns.lineplot

Wykres liniowy równiez wizualizuje związek między dwiema zmiennymi ciągłymi.

  • Zazwyczaj pozycja linii na osi y odzwierciedla średnią zmiennej na osi y dla tej wartości x.
  • Często używany do wykreślania zmian w czasie.

Jednym ze sposobów na stworzenie wykresu liniowego w seaborn jest użycie sns.lineplot.

Wykres life_exp oraz year

Jaki ogólny trend zauważamy?

sns.lineplot(data = df_gapminder,
             x = 'year',
             y = 'life_exp');
<Figure size 640x480 with 1 Axes>

Modyfikowanie sposobu wyświetlania błędów/niepewności

  • Domyślnie, seaborn.lineplot rysuje cieniowanie wokół linii reprezentującej przedział ufności.
  • Możemy to zmienić za pomocą errstyle.
sns.lineplot(data = df_gapminder,
             x = 'year',
             y = 'life_exp',
            err_style = "bars");
<Figure size 640x480 with 1 Axes>

Dodawanie hue

  • Moglibyśmy również pokazać to według kontynentów.
  • Istnieje (na szczęście) pozytywna linia trendu dla każdego kontynentu.
sns.lineplot(data = df_gapminder,
             x = 'year',
             y = 'life_exp',
            hue = "continent")
plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0);
<Figure size 640x480 with 1 Axes>

Sprawdź się!

Jak wykreślić zależność między year i gdp_cap tylko dla krajów w obu Amerykach?

### Twój kod tutaj

Heteroskedastyczność w gdp_cap według roku

  • Heteroskedastyczność to sytuacja, w której zmienność jednej zmiennej (np. gdp_cap) zmienia się w funkcji innej zmiennej (np. roku).
  • Jak myślisz, dlaczego tak jest w tym przypadku?

Rysowanie według kraju

  • Jest zbyt wiele krajów, aby wyraźnie wyświetlić je w legendzie.
  • Ale dwie górne linie to „Stany Zjednoczone” i „Kanada”.
    • Oznacza to, że dwa kraje stały się znacznie bogatsze w przeliczeniu na mieszkańca, podczas gdy inne nie odnotowały takiego samego wzrostu gospodarczego.
sns.lineplot(data = df_gapminder[df_gapminder['continent']=="Americas"],
             x = 'year', y = 'gdp_cap', hue = "country", legend = None);
<Figure size 640x480 with 1 Axes>

Wykorzystanie relplot

  • relplot pozwala na tworzenie wykresów liniowych lub wykresów rozproszonych przy użyciu kind.
  • relplot ułatwia również facet (który omówimy za chwilę).
sns.relplot(data = df_gapminder, x = "year", y = "life_exp", kind = "line");
<Figure size 500x500 with 1 Axes>

Grupowanie grafik w wiersze i kolumny

Możemy również wykreślić tę samą relację w wielu „oknach” lub facetach, dodając parametr rows/cols.

sns.relplot(data = df_gapminder, x = "year", y = "life_exp", kind = "line", col = "continent");
<Figure size 2500x500 with 5 Axes>

Dwuwymiarowe wykresy kategoryczne

Dwuwymiarowy wykres kategoryczny przedstawia (ewentualny) związek pomiędzy jedną zmienną kategoryczną (jakościową) a jedną zmienną ciągłą (ilościową).

title

Przykładowe dane

W tym miejscu powrócimy do naszego zbioru danych Pokemon, który zawiera więcej przykładów zmiennych kategorialnych.

df_pokemon = pd.read_csv("data/pokemon.csv")

Wykresy słupkowe sns.barplot

Wykres słupkowy wizualizuje związek pomiędzy jedną zmienną ciągłą a zmienną kategorialną.

  • Wysokość każdego słupka zazwyczaj wskazuje średnią zmiennej ciągłej.
  • Każdy słupek reprezentuje inny poziom zmiennej kategorialnej.

Z seaborn, możemy użyć funkcji sns.barplot.

Średni Attack według statusu Legendary

sns.barplot(data = df_pokemon,
           x = "Legendary", y = "Attack");
<Figure size 640x480 with 1 Axes>

Średni Attack według Type 1

Zauważ, że rysunek jest większy, aby upewnić się, że wszystkie etykiety pasują.

plt.figure(figsize=(15,4))
sns.barplot(data = df_pokemon,
           x = "Type 1", y = "Attack");
<Figure size 1500x400 with 1 Axes>

Sprawdź się

Jak wykreślić HP według Type 1?

### Twój kod tutaj

Modyfikowanie hue

Podobnie jak w przypadku wykresu rozrzutu i liniowego, możemy zmienić hue, aby uzyskać większą przejrzystość.

  • Na przykład, HP przez Type 1, dalej podzielone przez status Legendary.
plt.figure(figsize=(15,4))
sns.barplot(data = df_pokemon,
           x = "Type 1", y = "HP", hue = "Legendary");
<Figure size 1500x400 with 1 Axes>

Wykorzystanie catplot

seaborn.catplot jest wygodną funkcją do wykreślania dwuwymiarowych danych kategorycznych przy użyciu szeregu typów wykresów (bar, box, strip).

sns.catplot(data = df_pokemon, x = "Legendary", 
             y = "Attack", kind = "bar");
<Figure size 511.111x500 with 1 Axes>

Wykresy paskowe

Wykres paskowy pokazuje każdy pojedynczy punkt (jak scatterplot), podzielony przez etykietę kategorii.

sns.catplot(data = df_pokemon, x = "Legendary", 
             y = "Attack", kind = "strip", alpha = .5);
<Figure size 511.111x500 with 1 Axes>

Dodanie średniej do wykresu paskowego

Możemy wykreślić dwa wykresy w tym samym czasie, pokazując zarówno poszczególne punkty, jak i średnie.

sns.catplot(data = df_pokemon, x = "Legendary", 
             y = "Attack", kind = "strip", alpha = .1);
sns.pointplot(data = df_pokemon, x = "Legendary", 
             y = "Attack", hue = "Legendary");
<Figure size 511.111x500 with 1 Axes>

Wykresy pudełkowe

Wykres pudełkowy w teorii pokazuje zakres międzykwartylowy (środkowe 50% danych), medianę wraz z minimum i maksimum.

Typowy boxplot zawiera kilka komponentów, które są częścią jego anatomii:

  • Mediana: Jest to środkowa wartość danych, reprezentowana przez linię w ramce.
  • Ramki: Reprezentują one zakres międzykwartylowy danych (IQR), który reprezentuje zakres między Q1 i Q3. Dolna i górna krawędź reprezentują odpowiednio Q1 i Q3.
  • Wąsy: Są to pionowe linie, które rozciągają się od obu końców pudełka, aby reprezentować wartości minimalne i maksymalne, z wyłączeniem wartości odstających.
  • Wartości odstające: Są to punkty poza wąsami uważane za nietypowe lub skrajne w porównaniu z resztą danych.
  • Ograniczniki: Są to poziome linie na końcach wąsów, reprezentujące wartości minimalne i maksymalne, w tym wszelkie wartości odstające.

Czy wąsy pokazują minimum i maksimum?

Z punktu widzenia statystyki - końcówki wąsów nie są więc min oraz max - ponieważ nie zawierają części nietypowych wartości.

Standardowe zasady:

  • Wartości odstające (outliers): Są to punkty znajdujące się poza zakresem wąsów. Wartości te są uznawane za nietypowe w porównaniu do reszty danych.
  • Zakres wąsów: Wąsy rozciągają się do wartości, które mieszczą się w granicach:
    • Dolny wąs: Q11.5IQRQ1 - 1.5 * IQR
    • Górny wąs: Q3+1.5IQRQ3 + 1.5 * IQR
  • Ekstremalne wartości odstające: Jeśli wartości znajdują się znacznie dalej poza wąsami (np. Q13IQRQ1 - 3 * IQR lub Q3+3IQRQ3 + 3 * IQR), mogą być uznane za ekstremalne odstające.

Wartości odstające są zazwyczaj wyświetlane jako pojedyncze punkty na wykresie pudełkowym, co pozwala na ich łatwą identyfikację.

Dlaczego wartości odstające są ważne?

  • Mogą wskazywać na błędy w danych (np. literówki, błędy pomiarowe).
  • Mogą reprezentować rzeczywiste, ale rzadkie zdarzenia, które warto zbadać.
  • Wartości odstające mogą znacząco wpływać na statystyki opisowe, takie jak średnia, dlatego ich identyfikacja jest kluczowa w analizie danych.

Dlaczego 1,5 × IQR?

1,51,5 × IQRIQR to standardowa wartość używana do identyfikacji umiarkowanych wartości odstających.

Rozstęp międzykwartylowy (IQR) to różnica między trzecim kwartylem (Q3) a pierwszym kwartylem (Q1), czyli zakres, w którym znajduje się środkowe 50% danych.

Wartości, które znajdują się poza zakresem:

  • Dolny próg: Q1Q1 - 1.5 × IQRIQR
  • Górny próg: Q3Q3 + 1.5 × IQRIQR są uznawane za wartości odstające.

Wartość 1,51,5 została wybrana empirycznie jako rozsądny kompromis między wykrywaniem wartości odstających a ignorowaniem naturalnych fluktuacji w danych.

Dlaczego 3 × IQR?

3 × IQRIQR jest używane do identyfikacji wartości ekstremalnych odstających, które są znacznie bardziej odległe od reszty danych.

Wartości poza zakresem:

  • Dolny próg: Q1Q1 - 3 × IQRIQR
  • Górny próg: Q3Q3 + 3 × IQRIQR są uznawane za ekstremalne wartości odstające.

Wartość 3 × IQRIQR jest bardziej rygorystyczna i pozwala na identyfikację punktów, które są bardzo nietypowe i mogą wskazywać na błędy w danych lub rzadkie zdarzenia.

sns.catplot(data = df_pokemon, x = "Legendary", 
             y = "Attack", kind = "box");
<Figure size 511.111x500 with 1 Axes>

Mozna łatwo oczywiście wykreślić jedną zmienną i jej wykres pudełkowy:

titanic = pd.read_csv('data/titanic.csv')
titanic.head()
Loading...
sns.boxplot(x=titanic["age"]);
<Figure size 640x480 with 1 Axes>

Pogrupujemy teraz boxplot według zmiennej kategorialnej, odwołując się do kolumn w ramce danych:

sns.boxplot(data=titanic, x="age", y="class");
sns.violinplot(data=titanic, x="age", y="class", alpha=0.5 );
<Figure size 640x480 with 1 Axes>

Narysujmy pionowy wykres pudełkowy z zagnieżdżonym grupowaniem według dwóch zmiennych:

sns.boxplot(data=titanic, x="class", y="age", hue="alive");
<Figure size 640x480 with 1 Axes>

Zobacz takze, jak narysować wykresy wiolinowe, wykresy tzw. roju (podobne do paskowego) - więcej informacji tutaj.

Podsumowanie

Były to dwa rozdziały o wizualizacji danych na początek - absolutne minimum, aby zacząć wykonywać eksploracyjną analizę danych.

W szczególności, w tym rozdziale było to wprowadzenie do:

  • Pakietu seaborn.
  • Wykreślania danych jednowymiarowych i różnowymiarowych.
  • Tworzenia wykresów z wieloma warstwami.