Wizualizacja danych w Python#

Wstęp#

Cykl życia projektów Data Science składa się z różnych elementów. Jednym z nich jest etap Exploratory Data Analysis , a więc Eksploracyjna Analiza Danych. Jego celem jest przeprowadzenie zaawansowanej analizy statystycznej opierając sie nie tylko na statystykach opisowych, ale również na dobrze dobranych wizualizacjach. Stąd przygotowanie dobrej analizy nie jest możliwe bez umiejętności wizualizacji danych oraz prawidłowej ich interpretacji.

Istnieje wiele rodzajów wizualizacji danych. Wszystko zależy od tego jakiego rodzaju dane posiadamy - kategoryczne, numeryczne, a może dane zależne od czasu. Każda z metod wizualizacji odpowie nam na inne pytanie, dlatego dobranie odpowiedniej do naszego problemu jest kluczowe w kontekście zrozumienia danych przez nas, jak i naszych kolegów z zespołu czy kierownictwo.

Poniższy Tutorial opiera się na trzech najczęściej wykorzystywanych bibliotekach do wizualizacji danych w Python: matplotlib, seaborn oraz plotly. Są to najczęściej wykorzystywane przez nas biblioteki w trakcie trwania projektu. Ich opanowanie jest często kluczowe w kontekście przygotowania dobrej jakości analizy. W naszym odczuciu opanowanie przynajmniej podstaw każdej z tych bibiliotek może zapewnić zbudowanie ciekawej analizy, która odpowie nam na postawione przez nas pytanie. Oczywiście musicie mieć na uwadze, że nie wyczerpują one pełnej gamy dostępnych bibliotek czy metod wizualizacjii danych.

Wnioski:
  1. Wizualizacja danych jako niezbędny element Eksploracyjnej Analizy Danych.

  2. Dobra wizualizacja to klucz do sukcesu i prawidłowego zrozumienia danych.

Biblioteki#

Do poniższego Tutorialu niezbędne będzie zainstalowanie poniższych bibliotek. Wersję każdych z nich wypisane są w pliku viz_requirements.txt.

python pip install -r viz_requirements.txt

# Pobranie przykladowych danych
from sklearn.datasets import fetch_california_housing

# Data wrangling 
import pandas as pd
import numpy as np

# Data visualization
import seaborn as sns
from matplotlib import pyplot as plt
from plotly import express as px

# Inne
import datetime as dt

Przygotowanie danych#

Do przygotowania wizualizacji posłużą nam dane dostępne w sklearn.datasets oraz seaborn.datasets.

Housing#

Opis: Zestaw danych California Housing zawiera informacje ze spisu powszechnego w Kalifornii z 1990 roku.

Dane nie są w żaden sposób wyczyszcone, stąd posłużą jako dobry materiał do eksploracyjnej analizy danych.

# Funkcja do przygotowania ramki danych
def data_preparation():
    """Przygotowanie danych na potrzeby notatnika."""
    
    # Load data
    housing = fetch_california_housing()
    
    # Data Array
    df_array = housing.data.copy()
    target = housing.target.copy()
    target = target.reshape(len(target), 1)
    
    df_array = np.concatenate([df_array, target], axis=1)
    
    # Colnames
    colnames = housing.feature_names.copy()
    colnames.append(housing.target_names[0])
    
    # Data Frame
    df = pd.DataFrame(df_array, columns=colnames)
    
    return df
# Pobranie danych

# Housing
housing = data_preparation()

print(f'Wymiar ramki danych: {housing.shape}')
print(f'Nazwy kolumn: {housing.columns.values}')
Wymiar ramki danych: (20640, 9)
Nazwy kolumn: ['MedInc' 'HouseAge' 'AveRooms' 'AveBedrms' 'Population' 'AveOccup'
 'Latitude' 'Longitude' 'MedHouseVal']
# Wyswietlenie pierwszych 5 obserwacji
housing.head()
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude MedHouseVal
0 8.3252 41.0 6.984127 1.023810 322.0 2.555556 37.88 -122.23 4.526
1 8.3014 21.0 6.238137 0.971880 2401.0 2.109842 37.86 -122.22 3.585
2 7.2574 52.0 8.288136 1.073446 496.0 2.802260 37.85 -122.24 3.521
3 5.6431 52.0 5.817352 1.073059 558.0 2.547945 37.85 -122.25 3.413
4 3.8462 52.0 6.281853 1.081081 565.0 2.181467 37.85 -122.25 3.422

Niektóre z tych zmiennych poddam transformacji do celów edukacyjnych.

# Data transformation
housing['AveRooms'] = housing['AveRooms'].astype(int)
housing['AveBedrms'] = housing['AveBedrms'].astype(int)

# Feature Engineering
housing['AveRooms_greater_5'] = np.where(housing['AveRooms'] > 5, '>5', '<=5')
housing['MedInc_greater_5'] = np.where(housing['MedInc'] > 5, '>5', '<=5')
housing.head()
MedInc HouseAge AveRooms AveBedrms Population AveOccup Latitude Longitude MedHouseVal AveRooms_greater_5 MedInc_greater_5
0 8.3252 41.0 6 1 322.0 2.555556 37.88 -122.23 4.526 >5 >5
1 8.3014 21.0 6 0 2401.0 2.109842 37.86 -122.22 3.585 >5 >5
2 7.2574 52.0 8 1 496.0 2.802260 37.85 -122.24 3.521 >5 >5
3 5.6431 52.0 5 1 558.0 2.547945 37.85 -122.25 3.413 <=5 >5
4 3.8462 52.0 6 1 565.0 2.181467 37.85 -122.25 3.422 >5 <=5

Przed przystąpieniem do wizualizacji należy zaznaczyć, które z powyższych zmiennych to zmienna celu, a które to zmienne objaśniające.

Zmienna celu: MedHouseVal

Zmienne objaśniające: MedInc, HouseAge, AveRooms, AveBedrms, Population, AveOccup, Latitude, Longitude

Fmri#

Opis: Funkcjonalne obrazowanie rezonansem magnetycznym lub funkcjonalny MRI (fMRI) mierzy aktywność mózgu za pomocą silnego, statycznego pola magnetycznego w celu wykrycia zmian związanych z przepływem krwi. Kiedy używany jest obszar mózgu, przepływ krwi do tego obszaru również wzrasta. Zwiększony przepływ krwi jest reprezentowany przez sygnał o wyższej amplitudzie, postrzegany jako silna aktywność nerwowa.

## Fmri
fmri = sns.load_dataset("fmri")

print(f'Wymiar ramki danych: {fmri.shape}')
print(f'Nazwy kolumn: {fmri.columns.values}')
Wymiar ramki danych: (1064, 5)
Nazwy kolumn: ['subject' 'timepoint' 'event' 'region' 'signal']
fmri.head()
subject timepoint event region signal
0 s13 18 stim parietal -0.017552
1 s5 14 stim parietal -0.080883
2 s12 18 stim parietal -0.081033
3 s11 18 stim parietal -0.046134
4 s10 18 stim parietal -0.037970

W tym przypadku mamy do czynienia z pewnymi szeregami czasowymi, gdzie zmienna czasu jest timepoint, a zmienna celu signal. Szeregi czasowe możemy podzielić względem zmiennej region oraz event, gdzie region == parietal dotyczy płatu ciemieniowego, natomimast region == frontal dotyczy jego płatu czołowego mózgu.

Tips#

Opis: Ramka danych opierająca się na informacjach reprezentujących niektóre dane dotyczące napiwków, w których jeden kelner zapisał informacje o każdym napiwku, który otrzymał w ciągu kilku miesięcy pracy w jednej restauracji. Kelner zebrał kilka zmiennych: napiwek w dolarach, rachunek w dolarach, płeć płatnika rachunku, czy na imprezie byli palacze, dzień tygodnia, pora dnia i wielkość imprezy.

## Tips
tips = sns.load_dataset("tips")

print(f'Wymiar ramki danych: {tips.shape}')
print(f'Nazwy kolumn: {tips.columns.values}')
Wymiar ramki danych: (244, 7)
Nazwy kolumn: ['total_bill' 'tip' 'sex' 'smoker' 'day' 'time' 'size']
tips.head()
total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

W tym przypadku możemy ustalić następujące zmienne objaśniające oraz zmienną celu:

Zmienna celu: tip

Zmienne objaśniające: total_bill, sex, smoker, day, time, size

Anscombe#

Opis: Kwartet Anscombe’a to cztery zestawy danych o identycznych cechach statystycznych, takich jak średnia arytmetyczna, wariancja, współczynnik korelacji czy równanie regresji liniowej, jednocześnie wyglądających zgoła różnie przy przedstawieniu graficznym. Układ tych danych został stworzony w 1973 roku przez brytyjskiego statystyka Francisa Anscombe’a aby ukazać znaczenie graficznej reprezentacji danych przy okazji ich analizy statystycznej.

## Anscombe
anscombe = sns.load_dataset("anscombe")

print(f'Wymiar ramki danych: {anscombe.shape}')
print(f'Nazwy kolumn: {anscombe.columns.values}')
Wymiar ramki danych: (44, 3)
Nazwy kolumn: ['dataset' 'x' 'y']
anscombe.head()
dataset x y
0 I 10.0 8.04
1 I 8.0 6.95
2 I 13.0 7.58
3 I 9.0 8.81
4 I 11.0 8.33

Poniżej, dowód dotyczących tych samych wartości statystyki średniej arytmetycznej oraz odchylenia standardowego dla zmiennych x i y.

anscombe.groupby(['dataset']).agg({
    'x': ['mean', 'std', 'min', 'max'],
    'y': ['mean', 'std', 'min', 'max']
})
x y
mean std min max mean std min max
dataset
I 9.0 3.316625 4.0 14.0 7.500909 2.031568 4.26 10.84
II 9.0 3.316625 4.0 14.0 7.500909 2.031657 3.10 9.26
III 9.0 3.316625 4.0 14.0 7.500000 2.030424 5.39 12.74
IV 9.0 3.316625 8.0 19.0 7.500909 2.030579 5.25 12.50

Wizualizacja zależności statystycznych#

Analiza statystyczna to proces zrozumienia, w jaki sposób zmienne w zbiorze danych są ze sobą powiązane i jak te relacje zależą od innych zmiennych. Wizualizacja może być kluczowym elementem tego procesu, ponieważ gdy dane są odpowiednio wizualizowane, możemy dostrzec trendy i wzorce wskazujące na związek między nimi. Przeprowadzenie dokładnej analizy statystycznej jest procesem często niezbędnym w pierwszej fazie projektu, gdyd dobre zrozumienie danych jest kluczowe przed przystąpieniem do dalszych etapów projektu.

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

sns.set_theme(style="darkgrid")

Badanie relacji między zmiennymi przy użyciu wykresu punktowego#

Wykres punktowy jest podstawą wizualizacji statystycznej. Pozwala nam odpowiedzieć na kilka podstwowych pytań:

- Czy istnieje jakakolwiek zależność między dwiema zmiennymi ?
- Czy istnieją obserwacje nietypowe (anomalie) ?
- Czy dane układają nam się może w jakieś podgrupy ?

Oczywiście to tylko przykłady. Generalnie, wykres punktowy przedstawia łączny rozkład dwóch zmiennych za pomocą punktów, gdzie każdy punkt reprezentuje obserwacje w zbiorze danych. Wykres tego rodzaju umożliwia wywnioskowanie czy istnieje między zmiennymi jakakolwiek relacja - liniowa bądź nieliniowa. Na podstawie odnalezionych relacji możemy też dojść do pierwszych wniosków związanych z przyszłym etapem Feature Engineering - może się okazać, że transformacja zmiennej objaśnianej np. log, power, square itp. w lepszy sposób wyjaśnia naszą zmienną celu.

sns.relplot(x="MedInc", y="MedHouseVal", data=housing, alpha=0.3)
plt.title('Wykres punktowy', fontsize=18)
Text(0.5, 1.0, 'Wykres punktowy')
../_images/4dc9fabe55cfa8ae0edf6ba9f5dbc40223d8ab6b7503c35d4110292d2a7a40b7.png
Info

W wielu rodzajach wizualizacji pojawia sie parametr alpha. Służy on do ustawienia przezroczystosci wykresu. Zdefiniowanie tego parametru jest szczególnie przydatne, gdy wiele obserwacji nachodzi na siebie. Dzięki ustawieniu niskiej wartości alpha jesteśmy w stanie określić w jakim obszarze najczęściej występują nasze dane.

W przypadku biblioteki matplotlib wykres wyglądał by następująco:

plt.scatter(x=housing['MedInc'], y=housing['MedHouseVal'], alpha=0.3)
plt.xlabel('MedInc')
plt.ylabel('MedHouseVal')
plt.title('Wykres punktowy', fontsize=18)
Text(0.5, 1.0, 'Wykres punktowy')
../_images/ac1330800a3eea638075b43e668fcc22d31159acd78b1ba7453ec1f7512409e2.png
Info

Z uwagi na to, że pod spodem biblioteki seaborn działa matplotlib to wiele funkcji, działająych dla matplotlib tj. xlabel, ylabel, title działa również dla seaborn.

W przypadku biblioteki seaborn w prosty sposób można dodać dodatkową relację do tego rodzaju wykresu. Dodając parameter hue, mamy możliwość sprawdzić powyższą relację względem zmiennej kategorycznej.

sns.relplot(x="MedInc", y="MedHouseVal", hue="AveRooms_greater_5", data=housing);
../_images/dbd7cade7c77c3bd021dff7ba867fb198ffcf52a9101ae5903c595af1daae2ef.png

Aby sprawdzić kolejną relację, mamy możliwość dodania zmiennej kategorycznej która będzie charakteryzowała się innym znacznikiem - do tego służy parametr style.

sns.relplot(x="MedInc", y="MedHouseVal", hue="AveRooms_greater_5", style="MedInc_greater_5", data=housing);
../_images/9e247ecafddbdc17864969f878560a431810f544f714d389f1c78d29670e14bc.png

Na powyższych wykresach w parametrach hue oraz style podane są zmienne kategoryczne. W przypadku podania tam zmiennych numerycznych wizualizacja wyglądała by następująco.

sns.relplot(x="MedInc", y="MedHouseVal", hue="HouseAge", data=housing)
<seaborn.axisgrid.FacetGrid at 0x2c1a02f6750>
../_images/09d20f2c1b85908dff4b28545807e56ea47043dab5d14af4b47f11da2f33252e.png
ha_value = np.sort(housing['HouseAge'].unique())

print(f'Unikalne wartości HouseAge: {ha_value}')
Unikalne wartości HouseAge: [ 1.  2.  3.  4.  5.  6.  7.  8.  9. 10. 11. 12. 13. 14. 15. 16. 17. 18.
 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36.
 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52.]

Jak widać funkcja relplot sama poradziła sobie z podziałem naszej zmiennej tak, aby kolory punktów nie były przypisane do każdej z wartości tylko do ich przedziałów - w tym przypadku do przedziału długości 10 jednostek.

Bardzo często podczas pracy z danymi chcemy mieć możliwość pracy interaktywnej z naszymi danymi - w tym przypadku bardzo pomocny jest pakiet plotly.

# Wizualizacja - plotly
fig = px.scatter(data_frame=housing, x='MedInc', y='MedHouseVal', color='MedInc_greater_5', title='Wykres punktowy')
fig.show()

W przypadku plotly zachęcam do indywidualnej nauki. Jego opanowanie na wysokim poziomie na pewno przyda się podczas pracy projektowej.

Podkreślenie relacji liniowych między zmiennymi#

Choć wykresy punktowe są bardzo efektywne i same w sobie są w stanie bardzo dużo powiedzieć nam o relacjach między zmiennymi to nie są jednak uniwersalnym typem wykresu. Wizualizacja powinna być dostosowana do specyfiki analizowanych danych i pytania, na które próbujemy sobie odpowiedzieć.

W przypadku szeregów czasowych chcemy zrozumieć zmiany ciągłej zmiennej w stosunku do zmiennej czasu. W takiej sytuacji niezbędnym jest narysowanie wykresu liniowego.

Wykresy liniowe sprawdzają się gdy naszym celem jest wizualizacja szeregu czasowego lub sprawdzenie ostatecznej zależności liniowej między zmiennymi - jak w przypadku regplot powyżej.

W poniższym przykładzie przed przystąpieniem do takiej wizualizacji należy przygotować dane.

import datetime as dt

n = 500
start = dt.date(2020, 1, 1)
end = start + dt.timedelta(days=n-1)

df_dict = dict(
    time=pd.date_range(start, end),
    value=np.random.randn(n).cumsum()
)

df = pd.DataFrame(df_dict)
g = sns.relplot(x="time", y="value", kind="line", data=df, height=8)
../_images/7453d4fceb3e54d1cc49629e504c95b1f64ac0dfc8a651c06a76904021bae548.png
Uwaga!

Ponieważ relplot zakłada, że najczęściej próbujemy narysować y jako funkcję od x, dlatego domyślnym zachowaniem jest sortowanie danych według wartości x narysowaniem wykresu. Sortowanie danych w tym przypadku jest niezwykle istotne - nalezy o tym pamiętać korzystając z innych bibliotek np. matplotlib lub plotly.

# Przypadek gdy wylaczymy sortowanie wzgledem zmiennej "x"
df_dict = dict(
    x=np.random.rand(100),
    y=np.random.rand(100).cumsum()
)

df = pd.DataFrame(df_dict)
g = sns.relplot(x="x", y="y", kind="line", sort = False, data=df, height=8)
../_images/45385db20fbb4064f898205c42de10dfc683030e95710b20b4bcf9306175ef6e.png

Wizualizacja w przypadku agregacji danych#

Bardziej złożone zbiory danych będą miały wiele pomiarów dla tej samej wartości zmiennej x. Domyślnym zachowaniem w seaborn jest agregacja wielokrotnych pomiarów dla każdej wartości x poprzez wykreślenie średniej i 95% przedziału ufności wokół średniej.

sns.relplot(x="timepoint", y="signal", kind="line", data=fmri);
../_images/8dabb4c09f02c54f15ba416e6f4376937050d7d200cd909e025ebd72fbbfe4ab.png

Czasami wykreślenie przedziału ufności może być czasochłonne, dlatego jest możliwość wyłączenia tego wykorzystując parametr ci.

sns.relplot(x="timepoint", y="signal", errorbar=None, kind="line", data=fmri);
../_images/d7fc2b7a8ad8634ae8acb9760721807ca0a5ea6f071e7c38c2c8337db026ef39.png

Inną interesującą opcją jest wykreślenie przedziału ufności jako wartość odchylenia standardowego dla danej zmiennej.

sns.relplot(x="timepoint", y="signal", kind="line", errorbar="sd", data=fmri);
../_images/186754604de2f3a7d5c7d09f2ebf5cbc66a1d7bbd84cd5c7e00c4f7ca400c432.png

Oczywiście jest możliwość wyłączenia estymacji średniej dla danej zmiennej, jednak w wyniku tej operacji mamy kilka wartości zmiennej y dla zmiennej x. Domyślnym estymatorem jest średnia.

sns.relplot(x="timepoint", y="signal", estimator=None, kind="line", data=fmri);
../_images/372f00ef4553c21321b1b0d4a71629d87c07385a3638e0b56902a8a42d2cbabb.png

Funkcja relplot(kind="line") ma taką samą elastyczność co wykres punktowy. Może pokazywać do trzech dodatkowych zmiennych, modyfikując odcień, rozmiar i styl elementów wykresu. Robi to przy użyciu tego samego API.

sns.relplot(x="timepoint", y="signal", hue="event", kind="line", data=fmri)
<seaborn.axisgrid.FacetGrid at 0x2c1a25add30>
../_images/ca82c9f3b32eb7be3267510c46f5400a2ca65d43f2569d0837ede5109f4acaf8.png
sns.relplot(x="timepoint", y="signal", hue="region", style="event",
            kind="line", data=fmri);
../_images/1c12a1eaa1a63fac5cfe4883604a5752066cfca7b726c6b333ee9968b5b27452.png
sns.relplot(x="timepoint", y="signal", hue="region", style="event",
            dashes=False, markers=True, kind="line", data=fmri);
../_images/efb59ddc224dbb6057d85caf18be929a2f238119f523f619a486df762872dd7b.png

Taki sam typ wykresu można przedstawić przy pomocy biblioteki matplotlib jednak wtedy wymagana jest większa liczba operacji na danych.

# Data preparation
fmri_agg = fmri.sort_values(by='timepoint').groupby(['timepoint', 'event', 'region']).agg({'signal': 'mean'}).reset_index()

print(f'Wymiar ramki danych: {fmri_agg.shape}')
print(f'Nazwy kolumn: {fmri_agg.columns.values}')
Wymiar ramki danych: (76, 4)
Nazwy kolumn: ['timepoint' 'event' 'region' 'signal']
# Data filters
mask1 = (fmri_agg['event'] == 'cue') & (fmri_agg['region'] == 'frontal')
mask2 = (fmri_agg['event'] == 'cue') & (fmri_agg['region'] == 'parietal')
mask3 = (fmri_agg['event'] == 'stim') & (fmri_agg['region'] == 'frontal')
mask4 = (fmri_agg['event'] == 'stim') & (fmri_agg['region'] == 'parietal')

plt.figure(figsize=(12, 8))

plt.plot('timepoint', 'signal', data=fmri_agg[mask1], color='blue')
plt.plot('timepoint', 'signal', data=fmri_agg[mask2], color='green')
plt.plot('timepoint', 'signal', data=fmri_agg[mask3], color='red')
plt.plot('timepoint', 'signal', data=fmri_agg[mask4], color='black')
plt.title('Wykres liniowy', fontsize=20)
plt.xlabel('Time')
plt.ylabel('Signal')
Text(0, 0.5, 'Signal')
../_images/8d7139d643fd3f7de0e7d5fac8c5d491ca35e958c14caac14e4d2abd436938bc.png

Prezentaja wielu relacji na róznych polach wykresu#

Czasami chcemy zrozumieć jakie zachodzą relację między zmiennymi wizualizując je na oddzienlych polach wykresu. W tym przypadku przydatnym staję się parametr col lub row.

sns.relplot(x="timepoint", y="signal", hue="event",
            col="region", kind='line', data=fmri);
../_images/6a7df18003ec39a756f97bee88e2b9f7cdd369802de0b69271024af91bb2eb34.png

W tym przypadku przydatny okazuje się także wykres oparty o plotly. Jego podstawowa forma wygląda następująco:

fig = px.line(data_frame=fmri_agg, x='timepoint', y='signal', color='event', facet_col='region', title='Wykres liniowy')
fig.show()

Czasami do wykresy opartego o seaborn warto dodać parametr col_wrap, który umożliwia nam zdefiniowanie liczby kolumn dla danej wizualizacji.

sns.relplot(x="timepoint", y="signal", hue="event", col="subject", 
            col_wrap=5, kind='line', data=fmri.query("region == 'frontal'"), height=3);
../_images/4ee4bad631e7060f3e8c6bb29f6acdddbca7787e2675282569da2912af6739b3.png

Wizualizacja rozkładu zmiennych#

Jednym z pierwszych kroków podczas budowy modeli uczenia maszynowego powinno być zrozumienie, w jaki sposób rozkładają się zmienne. Techniki wizualizacji rozkładu zmiennych mogą dostarczyć szybkich odpowiedzi na wiele ważnych pytań. Jaki zakres obejmują obserwacje? Jaka jest ich główna tendencja? Czy są mocno przekrzywione w jednym kierunku? Czy istnieją znaczące wartości odstające? Czy odpowiedzi na te pytania różnią się w podzbiorach zdefiniowanych przez inne zmienne?

Biblioteka seaborn zawiera kilka bardzo przydatnych funkcji pod kątem badania rozkładu tj. histplot(), kdeplot(), ecdfplot() i rugplot(). Są one zgrupowane w ramach funkcji displot(), jointplot() i pairplot().

Istnieje kilka różnych podejść do wizualizacji rozładu zmiennych, a każde z nich ma swoje względne zalety i wady. Ważne jest, aby zrozumieć te czynniki, aby wybrać najlepsze podejście do konkretnego celu.

Rozkład zmiennej jednowymiarowej#

Najczęstszym podejściem do wizualizacji rozkładu jest histogram, który jest graficzną reprezentacją danych, która agreguje grupę punktów w zakresy określone przez analityka. Podobnie jak w przypadku wykresu słupkowego, histogram kondensuje obserwacje w łatwo interpretowalną wizualizację. Histogram jest jedną z podstawowych form wizualizacji wykorzystywaną w celu określenie rozkładu danej cechy. Podczas pracy z danymi często kluczowym jest aby określić w jaki sposób rozkładają się nasze dane - takie informacje można wtedy wykorzystać w dalszej pracy m.in. określając rodzaj algorytmu czy dokonując różnego rodzaju transformacji danej zmiennej.

sns.displot(housing, x="MedHouseVal") 
<seaborn.axisgrid.FacetGrid at 0x2c1a0668b30>
../_images/8e1027f4c4b12d20acaa8e12602c4711d3249c9b9681ed5c48525ba028d66864.png

Powyższy histogram dla zmiennej MedHouseVal w bardzo szybki sposób jest w stanie przedstawić nam pewne kluczowe informacje na temat zmiennej celu. Przykładem może być kwestia najpopularniszych wartości tej zmiennej która jest na poziomie około 1.5 oraz 5. Jednak bardzo ciekawą sytuacją jest kwestia wartości 5, która jest bardzo popularna jednak z drugiej strony może być pewnego rodzaju błędem - zwłaczsza jak spojrzymy na rozkład zmiennej bez wartości 5, gdzie wartości dla tego ogona są malejące.

W przypadku histogramu bardzo ważną rolę odgrywają parametry bins lub binwdith, które mówią nam o wielkości lub długości przedziałów dla histogramu. Te same dane przedstawione z inną wartością parametru binwidth mogą nam odpowiedzieć na zadane pytanie w zupełnie inny sposób. Przykładam jesy poniższy histogram na którym nie widać żadnych anomalii dla wartości zmiennej równej 5.

sns.displot(housing, x="MedHouseVal", binwidth=1)
<seaborn.axisgrid.FacetGrid at 0x2c1a02b3e30>
../_images/293ecf6cff471678c2329bbf42629ed0cb2a9d0153bdc1dfab7776b1da8a5e35.png

Dodatkowo pokażmy jak ten sam wykres wyglądałby z wykorzystaniem pakietów matplotlib oraz plotly - oczywiście poniższe wizualizacje uwzględniają domyślne opcje.

plt.figure(figsize=(8, 6))
plt.hist(x='MedHouseVal', data=housing, bins=5)
plt.title('Histogram', fontsize=20)
plt.ylabel('Frequency')
plt.xlabel('MedHouseVal')        
Text(0.5, 0, 'MedHouseVal')
../_images/0f1969729aa883d553452eece2ba7f057b9ebd7fd74d30ca8770455ad52bbb47.png
fig = px.histogram(data_frame=housing, x='MedHouseVal', nbins=5, title='Histogram')
fig.show()

Wizualizacja zmiennych kategorycznych#

Możliwa jest również wizualizacja rozkładu zmiennej kategorycznej za pomocą logiki histogramu. W tym przypadku pomocny może być parametr shrink, który nieco zwężą słupki aby podkreślić kategorialny charakter osi.

sns.displot(housing, x="MedInc_greater_5", shrink=0.7)
<seaborn.axisgrid.FacetGrid at 0x2c1a43372c0>
../_images/4bced8a247c0f96977d72b7bf5edf51baf00ae624c744c3fac8923f32727e06c.png

Rozkład warunkowy względem innych zmiennych#

Po zrozumieniu rozkładu zmiennej, następnym krokiem jest często pytanie, czy cechy tego rozkładu różnią się od innych zmiennych w zbiorze danych. displot zapewnia obsługę podzbiorów warunkowych poprzez barwy.

sns.displot(fmri, x='signal', hue="region")
<seaborn.axisgrid.FacetGrid at 0x2c1a53248c0>
../_images/b46b075c2bca77d6e95a74ba89e5c1b96ee016f5f660b86b7a21971da65904dc.png

Czasam warto nieco zmienić wizualizacje naszych danych poprzez zmianę wartości parametru element na step. Pomaga to czasem nieco lepiej zauwazyć różnicę w danych.

sns.displot(fmri, x='signal', hue="region", element='step')
<seaborn.axisgrid.FacetGrid at 0x2c1a2499730>
../_images/19ea8faa5f5d10ff07da57f93c480109fdb6475b3fa992857fcc60e935e1be1d.png

Innym rozwiązaniem jest pokazanie rozkładów, które się na siebie nakładają.

sns.displot(fmri, x='signal', hue="region", multiple='stack')
<seaborn.axisgrid.FacetGrid at 0x2c1a587f2f0>
../_images/f94645694d359753e5032a296d0945a41fe48d4ee93f8a1ce793e53a834b378c.png
sns.displot(fmri, x='signal', hue="region", multiple='dodge')
<seaborn.axisgrid.FacetGrid at 0x2c1a5e9ef60>
../_images/f3abb01d023f017b4432f293a4636e5fbbf96ae8728077d5d896a557fca68dae.png

Rozkłady możemy też pokazać na dwóch osobnych wykresach.

sns.displot(fmri, x='signal', col="region")
<seaborn.axisgrid.FacetGrid at 0x2c1a62e2060>
../_images/fc9707b91ed334c03caf2b7a98bb1a094fad59ed3fdea9ce12fa40a4f5497f00.png
Wnioski

Wybór wizualizacji zależy głównie od analityka i od problemu, który chciałby rozwiązać. Róznego rodzaju dane wymagają róznego podejścia.

Wartym zaznaczenia jest jeszcze jeden przydatny parametr, mianowicie stat. Umożliwia on nam zmianę sposobu wyświetlenia zmiennej z domyślnej count na density lub probability.

sns.displot(fmri, x='signal', hue="region", stat='density')
<seaborn.axisgrid.FacetGrid at 0x2c1a79f0e30>
../_images/6fd8b4545f084211b2e1fba4b08f5886c33707f3184f6eb093e00af62c01b270.png
sns.displot(fmri, x='signal', hue="region", stat='probability')
<seaborn.axisgrid.FacetGrid at 0x2c1a5e8e690>
../_images/a53f3b82d1a909ed2ff8bb3b3cf62d55e53b659b95789b4f7c1f56bd0f985a9b.png

Gęstość rozkładu#

Histogram ma na celu przybliżenie podstawowej funkcji gęstości prawdopodobieństwa, która wygenerowała dane, poprzez grupowanie i liczenie obserwacji. Szacowanie gęstości jądra (KDE) przedstawia inne rozwiązanie tego samego problemu. Zamiast używać oddzielnych przedziałów, wykres KDE wygładza obserwacje za pomocą jądra Gaussa, tworząc ciągłe oszacowanie gęstości rozkładu.

sns.displot(fmri, x='signal', kind='kde')
<seaborn.axisgrid.FacetGrid at 0x2c1a4c44620>
../_images/67e84c5ba2f3a3431a3316a928e41df029dc7b8d22e78fde8ee14fade5e0e757.png

Podobnie jak w przypadku histogramu, wykres kde posiada parametr bw_adjust (parametr wygładzenia), który spełnia podobną rolę co binwidth lub bins dla histogramu. Ustawnienie tego parametru na zbyt niskim poziomie spowoduje nadmierne dopasowanie dodanych, w odwrotnym przypadku nadrmierne wygładzenie spowoduję wymazanie znaczących cech rozkładu.

sns.displot(fmri, x='signal', kind='kde', bw_adjust=0.1)
<seaborn.axisgrid.FacetGrid at 0x2c1a039da00>
../_images/cee9dec11eba8f39902e8afd0ac95458310c4f76f37df12a74a4974684142644.png
sns.displot(fmri, x='signal', kind='kde', bw_adjust=2)
<seaborn.axisgrid.FacetGrid at 0x2c1a5e8ffb0>
../_images/8540c160814bdbd6f7973142a0aa54fd4a9f039ed77654d1e230b424c9aca6b7.png

Rozkład gęstości ma podobne funkcjonalności jak wyżej przedstawiony histogram. Oto kilka z nich:

sns.displot(fmri, x="signal", hue="region", kind="kde")
<seaborn.axisgrid.FacetGrid at 0x2c1a54ab3e0>
../_images/e6ba5586b5d04d6a22093f58fd8fe65e53fac048d4f7ac631172d075c5960a0f.png
sns.displot(fmri, x="signal", hue="region", multiple='stack', kind="kde")
<seaborn.axisgrid.FacetGrid at 0x2c1a28d2c30>
../_images/fc35a9c398845f70c0b6ac6e9649cb8b4ceeef0912a853a3662ee5ee95b9ca69.png
sns.displot(fmri, x="signal", hue="region", fill=True, kind="kde")
<seaborn.axisgrid.FacetGrid at 0x2c1a25c4230>
../_images/2cea167f8e55ee8ec6cb1d07b0a82dcab97a75be8b131d3a829776d1ca1512b3.png

Bardzo częstym podejściem podczas wizualizacji danych jest skorzystanie z obu typów wykresu jednocześnie.

sns.displot(fmri, x="signal", kde=True)
<seaborn.axisgrid.FacetGrid at 0x2c1a28d2f30>
../_images/d88274ab51e274ca8b6b37dcc52cbbd221dfa909b8570f65ad72d2a83a0ed2e3.png

Dystrybuanta rozkładu#

Trzecia opcja wizualizacji rozkładów oblicza empiryczną dystrybuantę rozkładu (ECDF).

sns.displot(fmri, x="signal", kind='ecdf')
<seaborn.axisgrid.FacetGrid at 0x2c1a24835f0>
../_images/6625fe07e848d97a16eb988d6bd0164e5af58134924eee7426de97b091201480.png

Wizualizacja dystrybuanty rozkładu ma dwie istotne zalety. Po pierwsze bezpośrednio reprezentuje każdy punkt danych. Oznacza to, że nie trzeba brać pod uwagę rozmiaru przedziału ani parametru wygładzania. Dodatkowo, ponieważ krzywa rośnie monotonicznie, dobrze nadaje się do porównywania wielu rozkładów.

sns.displot(fmri, x="signal", hue="region", kind="ecdf")
<seaborn.axisgrid.FacetGrid at 0x2c1a4185130>
../_images/ef727decfd63a94999a196b69b4631b96312b7563f0eb577cacffcb2cbcfc561.png

Główną wadą wykresu dystrybuanty jest to, że mniej intuicyjnie przedstawia kształt rozkładu niż histogram lub krzywa gęstości.

Rozkład wielowymiarowy#

Wszystkie dotychczasowe przykłady uwzględniały rozkłady jednowymiarowe: rozkłady jednej zmiennej, z uwzględnieniem zależności od drugiej zmiennej przypisanej do barwy. Teraz zajemiemy się badaniem rozkładów dwuwymiarowych.

sns.displot(housing, x="MedHouseVal", y="MedInc")
<seaborn.axisgrid.FacetGrid at 0x2c1a4ba7b90>
../_images/29a09878958d1df7d78f8b3a83485317216410bfdc43e3a878b2c14896c158ce.png
sns.displot(housing, x="MedHouseVal", y="MedInc", kind='kde')
<seaborn.axisgrid.FacetGrid at 0x2c1a251f860>
../_images/19d3db19918e4748dbcc66031beb1111822c7cc39603a8a16c004a3f6e954a5e.png
sns.displot(housing, x="MedInc", y="MedHouseVal", hue="AveRooms_greater_5")
<seaborn.axisgrid.FacetGrid at 0x2c1a79f2ba0>
../_images/648f9c0c831f2d44b96578f18c958d3c9d7836460b8926e1ce805a3a12ce1f60.png
sns.displot(housing, x="MedInc", y="MedHouseVal", hue="AveRooms_greater_5", kind='kde')
<seaborn.axisgrid.FacetGrid at 0x2c1a5e8dac0>
../_images/67e2836b05d3824e8eb5fff5703da6178d5309ae0ec174eca1592d19ce06dc43.png

Jak widać każdy z powyższych wykresów posiada podobne lub wręcz takie same parametry jak w przypadku wykresów jednowymiarowych. Zachęcam do zgłębienia innych dodatkowych opcji pod kątem analizy rozkładu jedno i dwuwymiarowego.

Ostatnim typem wykresu, który warto mieć w zanadrzu podczas analizy rozkładu jest jointplot.

sns.jointplot(data=housing, x="MedInc", y="MedHouseVal")
<seaborn.axisgrid.JointGrid at 0x2c1a066a120>
../_images/345c70f50524cffa0411e506a3f612a937185643ffaf7b1c2177f146217e29fd.png
sns.jointplot(data=housing, x="MedInc", y="MedHouseVal", hue="AveRooms_greater_5", kind='kde')
<seaborn.axisgrid.JointGrid at 0x2c1acf76ab0>
../_images/eb93ff472f6374f5a935b97d7d0697b4c9d5e3789c80f75869b1d77233aa226c.png

Zaletą wykresy typu joinplot jest dodatkowe wyświetlanie jednowymiarowego rozkładu zmiennej w postaci histogramu lub funkcji gęstości. Dzięki temu możemu jeszcze lepiej zrozumieć relacje zachodzące w naszym zbiorze danych.

Wizualizacja modeli regresyjnych#

Zazwyczaj zbiory danych zawierają wiele zmiennych numerycznych, a celem analizy jest często powiązanie tych zmiennych ze sobą. Wcześniej omówione funkcje pokazują łączny rozkład dwóch zmiennych lub pewne ich relacje określone wykresem punktowym. Bardzo pomocne może być jednak wykorzystanie modeli statystycznych do oszacowania prostej zależności między dwoma zaszumionymi zestawami obserwacji.

Info

Pakiet seaborn nie jest pakietem do analizy statystycznej. Aby uzyskać miary ilościowe związane z dokładnym dopasowaniem modeli regresji, należy użyć modeli statystycznych zawartych w bibliotekach sklearn czy statsmodels.

Wizualizacja regresji liniowej#

W seaborn wykorzystywane są dwie główne funkcje do wizualizacji zależności liniowej określonej za pomocą regresji. Te funkcje to: regplot() i lmplot(). Obie funkcje są ze sobą ściśle powiązane i dzielą większość swoich podstawowych parametrów.

W najprostszym użyciu obie funkcje rysują wykres rozrzutu dwóch zmiennych, x i y, a następnie dopasowują model regresji y ~ x. Następnie wykreślają wynikową linię regresji oraz 95% przedział ufności.

sns.regplot(x="total_bill", y="tip", data=tips);
../_images/34e0c6cba6d85824fddcc914120bf86e7f918de93b9575b2ec2a04569fd1f6bb.png
sns.lmplot(x="total_bill", y="tip", data=tips);
../_images/2c499036089d2c54d4de8069d087b166afe07a293d3a457a7c6635af2fd164bc.png

W poniższym notatniku w głównej mierze skupimy się na funkcji lmplot.

Możliwe jest dopasowanie regresji liniowej, gdy jedna ze zmiennych przyjmuje wartości dyskretne, jednak prosty wykres rozrzutu utworzony przez ten rodzaj danych często jest nieoptymalny.

sns.lmplot(x="size", y="tip", data=tips);
../_images/ecbd038b6f47df0f767dcddec816c8fbcb0819856c6eadc2aa5e3fd33b4928b9.png

Jedną z opcji rozwiązania tego problemu jest dodanie losowego szumu jitter do wartości dyskretnych, aby rozkład tych wartości był bardziej przejrzysty.

sns.lmplot(x="size", y="tip", data=tips, x_jitter=.05);
../_images/21d9374dc70d9a7bf552f6d848427ca0b6765256255d1e7d4f4d6ebf3818d669.png

Drugą opcją jest “zwinięcie” obserwacji w każdym dyskretnym przedziale, aby wykreślić oszacowanie tendencji centralnej (w tym przypadku średniej) wraz z przedziałem ufności.

sns.lmplot(x="size", y="tip", data=tips, x_estimator=np.mean);
../_images/710324603d9560f5f5eb194d150ab0090ade8f6245b96bb1a87139acee611f21.png

Wizualizacja z wykorzystaniem innych modeli#

Wizualizacja wielu relacji jednocześnie#

sns.jointplot(x="total_bill", y="tip", data=tips, kind="reg");
../_images/52279aab1fd01155660a6ef5cba36de04f04d29fcdeab13d2b0eeae0429e0b7d.png
sns.pairplot(tips, x_vars=["total_bill", "size"], y_vars=["tip"],
             height=5, aspect=.8, kind="reg");
../_images/2f645388ade42592d75f9a649b5aaa0c5545129275c91db021a03f7452e8eae0.png

Wizualizacja danych kategorycznych#

Powyższe metody wizulizacji skupiały się najczęściej na danych liczbowych, gdzie zmienna kategoryczna była nam potrzebna jedynie do grupowania czy agregowania naszych danych. W tej części skupimy się na metodach bezpośrednij wizualizacji zmiennej kategorycznej.

Zmienna kategoryczna w postaci wykresu punktowego#

Podstawową formą wizualizacji dla zmiennej katgorycznej jest wykres rozrzutu przedstawiający daną zmienną liczbową w zależności od zmiennej kategorycznej. Parametr kind == strip oznacza, że do zmiennej y dodawany jest pewinen element losowy w celu “rozrzucenia” obserwacji na osi y. Tak przedstawiony wykres może nam odpowiedzieć na pytania dotyczące rozkładu naszej zmiennej y wzlędem zmiennej x oraz może pomóc nam dostrzeć pewne anomalie w naszych danych.

sns.catplot(x="day", y="total_bill", kind="strip", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1b2cb6cc0>
../_images/c90cab134848818c6e2b2edce6bef419b957cd544e7e596d7c645a012bfeb2d6.png

Tak wykres wyglądałby w przypadku pominięcia dodawania składnika losowego do każdej obserwacji z osobna.

sns.catplot(x="day", y="total_bill", jitter=False, data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1a071db20>
../_images/a616e098c9b9f3f7c0ba72a27ca734d1ec3fee4998c482f6a61442a4e11b253e.png

Czasami dobrym pomysłem jest, także dodanie do wykresu kolejnego wymiaru (w tym przypadku płci). Może nam to pomoć zrozumieć kolejne relacje zachodzące w naszych danych.

sns.catplot(x="day", y="total_bill", hue="sex", kind="strip", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1a497b020>
../_images/d5959cd11d097c8e9a749ecc4708a481714d14bd5fdb3ed27ee60dad2bde26b4.png

Rozkład zmiennej w zależności od danych kategorycznych#

W poprzednich wizualizacjach pokazaliśmy w jaki sposób można zwizulizować histogram, a wieć wykres rozkładu naszej zmiennej w zależności od danych kategorycznych. Istnieją również innego rodzaju wykresy, które będące odpowiedzią na rozkład naszej zmiennej - wykresy pudełkowe.

Podstawowy wykres pudełkowy można uzyskać korzystając z matplotlib.

plt.boxplot(x=housing['MedHouseVal']);
../_images/65cbf47dc7cd54a6f7813f0e66687f231173dcf85f1e8a4f5f52b3e7bbadae25.png

Jednakże, tym samym małym wysiłkiem można uzyskać dużo ładniejszy wykres korzystając z API seaborn.

sns.catplot(y='MedHouseVal', data=housing, kind="box")
<seaborn.axisgrid.FacetGrid at 0x2c1a4c6ea20>
../_images/c477dc6bee88fb546deca552713588282c9b924436899fcca13eb6ce60c41332.png
sns.catplot(x="day", y="total_bill", kind="box", data=tips, hue="day")
<seaborn.axisgrid.FacetGrid at 0x2c1a26262d0>
../_images/906f3967f5d075275ad9bd78f55efccf46bf760626c6eec323cc280aab548ed0.png
sns.catplot(x="day", y="total_bill", hue="smoker", kind="box", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1a5223980>
../_images/ff0e5a74a4b0220cc200c04385475cc501a968457b630c19cf993489841c4ef4.png

Interpretacja wykresu pudełkowego jest dość prosta. Są w nim zawarte informacje na temat wartości minimalnej, kwartylu I, medianie, kwartylu III, wartości maksymalnej, a także o potencjalnych anomaliach wyliczonych za pomocą rozstępu między kwartylowego. Jednakże wykres pudełkowy można zastąpić innymi podobnymi wizualizacjami, którą czasami mogą okazać się bardzo pomocne.

sns.catplot(x="AveRooms_greater_5", y="MedHouseVal", kind="box",
            data=housing.sort_values("AveRooms_greater_5"), hue="AveRooms_greater_5")
<seaborn.axisgrid.FacetGrid at 0x2c1a2a37380>
../_images/a6ce9f86b4fa29a79b6cafc016b70ba3770a6baf7bb472e06e20009bfe2d7801.png

Wykresem podobnym do wykresu pudełkowego - boxplot, ale zoptymalizowany pod kątem wyświetlania większej ilości informacji o kształcie rozkładu jest inny wykres pudełowy - boxenplot.

sns.catplot(x="AveRooms_greater_5", y="MedHouseVal", kind="boxen",
            data=housing.sort_values("AveRooms_greater_5"), hue="AveRooms_greater_5")
<seaborn.axisgrid.FacetGrid at 0x2c1a4c6f1a0>
../_images/ae1be4c72dfc0746c5d7b50d19afbf6fe977c97de543477e39f4a1b9a5fcec9d.png

Ciekawą oraz często wykorzystywana interpretacją rozkładu jest violinplot* łączący wykres pudełkowy z estymacją gęstości rozkładu. Jest on w stanie jeszcze dokładniej pomóc nam oszacować miejsca w których występują większe skupiska naszych obserwacji.

sns.catplot(x="AveRooms_greater_5", y="MedHouseVal", kind="violin",
            data=housing.sort_values("AveRooms_greater_5"), hue="AveRooms_greater_5")
<seaborn.axisgrid.FacetGrid at 0x2c1acf50140>
../_images/83dd187031492a7fd89446692e8d7163f0a6b7e5b7d4d2811a3f405d91eddf38.png

Dobrym połączeniem jest violinplot z stripplot, czyli przedstawionym wcześniej wykresem rozrzutu. Jednakże w przypadku dużej ilości danych wizualizacja może się długo ładować.

g = sns.catplot(x="day", y="total_bill", kind="violin", inner=None, data=tips, hue="day")
sns.stripplot(x="day", y="total_bill", color="k", size=3, data=tips, ax=g.ax)
<Axes: xlabel='day', ylabel='total_bill'>
../_images/fe61ecbd6b7b9783f2ddd203580ed48af6e9c2555ac100a0f18fd1ac90ef9559.png

Podczas pracy z danymi są sytuacje gdy chcemy aby nasz wykres był bardziej interaktywny. Wtedy w przypadku wykresu pudełkowego można skorzystać z API plotly. Podstawowa forma takiego wykresu wygląda następująco:

fig = px.box(data_frame=tips, x='day', y='total_bill', title='Wykres pudełkowy')
fig.show()

Estymacja statystyczna w ramach zmiennej kategorycznej#

W pewnych przypadkach naszym celem może być oszacowanie tendencji centralnej dla naszych danych np. średniej czy mediany. Wtedy bardzo często korzysta się z wykresu słupkowego wraz z pewnym pozniomem ufności. W przypadku biblioteki seaborn narysowanie tego typu wykresu jest bardzo proste. Domyślnie tendecją centralną jest średnia arytmetyczna.

sns.catplot(x="sex", y="tip", hue="time", kind="bar", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1b3e70b90>
../_images/a6c6c0c7823c0ddb3634ad510819037a41e604c3336aa91e77df161e6fc84d7e.png

Szczególnym przypadkiem wykresu catplot jest wykres przedstawiający liczbę obserwacji przypadającą na daną kategorię.

sns.catplot(x="sex", kind="count", data=tips, hue='sex')
<seaborn.axisgrid.FacetGrid at 0x2c1b3e466c0>
../_images/ff534f82d238eae8531d539c0b2cb9709a08116fba7163146b1d79f2dc6e98a8.png
sns.catplot(y="sex", hue="time", palette="pastel",  kind="count", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1b2c3f500>
../_images/ab926bc96f1055a958979afbbf44f0745d6ee358e1a9c5dc6b860520c461e8e4.png

Inna formą wizualizacji może być, także pointplot, który te same relacje przedstawia w postaci wykresu punktowego, gdzie dany punkt przedstawia tendencję centralną danej kategorii natomiast pionowe linię określają przedział ufności. Atutem tego wykresu jest łączenie tych samych kategorii podanych w parametrze hue.

sns.catplot(x="sex", y="tip", hue="time", kind="point", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1b53c35f0>
../_images/18be3479ab060dac3e750a1f17906c7a40b26b75681f513083b71f4804987c55.png
sns.catplot(x="size", y="tip", hue='sex', kind="point", data=tips)
<seaborn.axisgrid.FacetGrid at 0x2c1b3ea72f0>
../_images/819920829af2cf7967ca8137692d015155521e710d1ee6ac370deee3c64c01aa.png

Podsumowanie#

Wnioski:

Wykresy oparte o pandas lub matplotlib sprawdzają się w przypadku chęci zbudowania prostej wizualizacji podczas pierwszej fazy Exploratory Data Analysis. Wykresy z rodziny seaborn oraz plotly dają większe możliwości, dzięki czemu możemy w ładniejszy sposób przedstawić nasze dane i wyciągnąć na ich podstawie istotne wnioski.

Zadanie#

Opierając się na powyższych wizualizacjach należy przeprowadzić eksploracyjną analizę danych dla ramki danych tips. Analiza powinna odpowiadać na kilka postawionych przez nas pytań tj. Czy istnieje jakakolwiek relacja między zmienną x i y, Czy relacja zależy w jakiś sposób od zmiennej z ? Jaki jest rozkład zmiennej x ? Jaki jest rozkład zmiennych kategorycznych ? itp. Oprócz wykresów warto dodać kalkulację podstawowych statystyk opisowych oraz wnioski z przygotowanych z wykresów. W zadaniu przynajmniej jeden wykres musi być narysowany w seaborn, matplotlib oraz plotly.

Analiza#

Postawione pytania:

1. ...
2. ...
...