Site icon Mirosław Mamczur

#005 Wykres skrzypcowy (violin plot)

Wykres skrzypcowy (ang. Violin Plot) jest jednym z ciekawszych i jednocześnie rzadko spotykanych wykresów. Pozwala wizualizować jednocześnie gęstość prawdopodobieństwa oraz rozkład dla kilku grup jednocześnie. Można powiedzieć, że jest to tak naprawdę połączenie wykresu pudełkowego (ang. Box Plot) oraz wykresu gęstości (Dense Plot), który jest umieszczony z każdej strony by zobrazować kształt rozkładu danych. Zaskakujące jest to, że wykres skrzypcowy jest znacznie rzadziej używany niż pudełkowy, nawet jeśli moim zdaniem zawiera więcej informacji.

Każde „skrzypce” przedstawiają grupę lub zmienną. Kształt skrzypiec reprezentuje tak naprawdę oszacowanie gęstości zmiennej: im więcej punktów danych w określonym zakresie, tym większe skrzypce będą w tym miejscu.

Skrzypce są szczególnie przystosowane, gdy ilość danych jest ogromna, a pokazanie indywidualnych obserwacji staje się niemożliwe. W przypadku małych zestawów danych lepszym rozwiązaniem jest prawdopodobnie wykres pudełkowy, ponieważ pokaże wszystkie informacje.

Biała kropka na środku to wartość mediany, a gruby czarny pasek na środku reprezentuje zakres międzykwartylowy. Cienka czarna linia przedłużona od niej reprezentuje górne i dolne wartości w danych.

Dodatkowo warto wspomnieć, że wypełnieniem wykresu skrzypcowego nie musi być boxplot – może być zarówno pusty, jak i wypełniony konkretnymi obserwacjami oznaczonymi poprzez punkty / kropki lub inne wizualizacje.

Główne zalety:

Główne wady:

Kod w Python

Do pokazania przykładu użyję wcześniej już używanego zbioru z pokemonami.

import pandas as pd
import seaborn as sns

import matplotlib.pyplot as plt

print(f'pandas: {pd.__version__}')
print(f'seaborn: {sns.__version__}')
df = pd.read_csv('../data/pokemon.csv')
df = df[df['type1'].isin(['water', 'psychic', 'electric', 'fire'])]
pd.options.display.max_columns = 100
df.head(3)

Najpierw narysujmy dla powyższych danych informacje jak wygląda cecha opisująca wysokość ataku pokemonów 🙂

plt.figure(figsize=(10,5))
ax = sns.violinplot(x = df['attack'])

Teraz porównajmy tą informację w podziale na typy pokemonów:

plt.figure(figsize=(10,8))
ax = sns.violinplot(x=df['type1'], y = df['attack'])

A teraz zobaczcie jak za pomocą parametru inner możemy zmienić pudełko wewnątrz w linie przedstawiające pierwszy, drugi i trzeci kwartyl:

plt.figure(figsize=(10,8))
ax = sns.violinplot(x=df['type1'], y = df['attack'], inner="quartile")

Możemy jeszcze w prosty sposób dokonać kolejnego podziału po kolejnej charakterystyce, np. czy pokemon jest legendarny (czyli taki rzadki :))

plt.figure(figsize=(10,8))
ax = sns.violinplot(x=df['type1'], y = df['attack'], hue = df['is_legendary'])

… oraz dla uproszczenia analizowania przedstawmy te informacje na jednych skrzypcach

plt.figure(figsize=(10,8))
ax = sns.violinplot(x=df['type1'], y = df['attack'], 
                    hue = df['is_legendary'], split=True)

W przypadku specyficznych rozkładów możecie dobrać odpowiedni poziom wygładzenia poprzez parametr bandwith (dokładniej z przykładem było w wpisie o wykresie gęstości)

plt.figure(figsize=(10,8))
ax = sns.violinplot(x=df['type1'], y = df['attack'], hue = df['is_legendary'], 
                    split=True, bw=0.25)

Podsumowanie:

Wykresy skrzypcowe są naprawdę wygodnym sposobem wyświetlania danych i prawdopodobnie zasługiwałyby na większą uwagę w porównaniu do wykresów pudełkowych.

Mam nadzieję, że chętniej będziecie teraz ich używać.

Pozdrawiam,

Exit mobile version