Iris - analiza danych dla 3 różnych gatunków¶

Cel zadania¶
Analiza cech gatunków irysów, ich zależności i różnic oraz wpływu na ostateczną wielkość kwiatu.
Informacja o danych¶
Zbiór danych zawiera informacje o trzech gatunkach irysów: Iris setosa, Iris versicolor, i Iris virginica. Dane obejmują pomiary czterech cech: długość i szerokość działki kielicha oraz długość i szerokość płatka. Każdy wiersz w zbiorze danych reprezentuje pojedynczy kwiat, a wartości pomiarów są podane w centymetrach. Zbiór składa się z 150 próbek, po 50 dla każdego gatunku.
1. Ogólny przegląd danych¶
W tym kroku zapoznamy się z podstawową strukturą zbioru danych.
1.1. Wczytanie danych z pliku do analizy¶
Importujemy bibliotekę pandas i wczytujemy zbiór danych z pliku CSV do dalszej analizy.
import pandas as pd
df = pd.read_csv('25__iris.csv', sep=',')
df
| długość kielicha (sepal length) | szerokość kielicha (sepal width) | długość płatka (petal length) | szerokość płatka (petal width) | klasa (class) | |
|---|---|---|---|---|---|
| 0 | 5.1 | 3.5 | 1.4 | 0.2 | Iris-setosa |
| 1 | 4.9 | 3.0 | 1.4 | 0.2 | Iris-setosa |
| 2 | 4.7 | 3.2 | 1.3 | 0.2 | Iris-setosa |
| 3 | 4.6 | 3.1 | 1.5 | 0.2 | Iris-setosa |
| 4 | 5.0 | 3.6 | 1.4 | 0.2 | Iris-setosa |
| ... | ... | ... | ... | ... | ... |
| 145 | 6.7 | 3.0 | 5.2 | 2.3 | Iris-virginica |
| 146 | 6.3 | 2.5 | 5.0 | 1.9 | Iris-virginica |
| 147 | 6.5 | 3.0 | 5.2 | 2.0 | Iris-virginica |
| 148 | 6.2 | 3.4 | 5.4 | 2.3 | Iris-virginica |
| 149 | 5.9 | 3.0 | 5.1 | 1.8 | Iris-virginica |
150 rows × 5 columns
1.2. Losowe 10 rekordów¶
Wyświetlamy losowe próbki danych, aby sprawdzić ich strukturę i różnorodność.
df.sample(10)
| długość kielicha (sepal length) | szerokość kielicha (sepal width) | długość płatka (petal length) | szerokość płatka (petal width) | klasa (class) | |
|---|---|---|---|---|---|
| 68 | 6.2 | 2.2 | 4.5 | 1.5 | Iris-versicolor |
| 130 | 7.4 | 2.8 | 6.1 | 1.9 | Iris-virginica |
| 24 | 4.8 | 3.4 | 1.9 | 0.2 | Iris-setosa |
| 67 | 5.8 | 2.7 | 4.1 | 1.0 | Iris-versicolor |
| 97 | 6.2 | 2.9 | 4.3 | 1.3 | Iris-versicolor |
| 56 | 6.3 | 3.3 | 4.7 | 1.6 | Iris-versicolor |
| 110 | 6.5 | 3.2 | 5.1 | 2.0 | Iris-virginica |
| 4 | 5.0 | 3.6 | 1.4 | 0.2 | Iris-setosa |
| 17 | 5.1 | 3.5 | 1.4 | 0.3 | Iris-setosa |
| 85 | 6.0 | 3.4 | 4.5 | 1.6 | Iris-versicolor |
1.3. Liczba wartości unikatowych w poszczególnych kolumnach¶
Sprawdzamy ile unikalnych wartości zawiera każda kolumna, co pozwala zrozumieć zróżnicowanie danych.
df.nunique()
długość kielicha (sepal length) 35 szerokość kielicha (sepal width) 23 długość płatka (petal length) 43 szerokość płatka (petal width) 22 klasa (class) 3 dtype: int64
1.4. Podstawowe statystyki dla kolumn numerycznych¶
Wyświetlamy podstawowe statystyki opisowe (średnia, mediana, odchylenie standardowe, min, max) dla wszystkich parametrów.
df.describe().T
| count | mean | std | min | 25% | 50% | 75% | max | |
|---|---|---|---|---|---|---|---|---|
| długość kielicha (sepal length) | 150.0 | 5.843333 | 0.828066 | 4.3 | 5.1 | 5.80 | 6.4 | 7.9 |
| szerokość kielicha (sepal width) | 150.0 | 3.054000 | 0.433594 | 2.0 | 2.8 | 3.00 | 3.3 | 4.4 |
| długość płatka (petal length) | 150.0 | 3.758667 | 1.764420 | 1.0 | 1.6 | 4.35 | 5.1 | 6.9 |
| szerokość płatka (petal width) | 150.0 | 1.198667 | 0.763161 | 0.1 | 0.3 | 1.30 | 1.8 | 2.5 |
Wyświetlamy dodatkową tabelę, gdzie pokazujemy różnice między największymi a najmniejszymi wartościami dla każdej cechy (wart. max - wart.min), dzięki czemu sprawdzimy które cechy mają największe różnice w wartościach, a które są najabrdziej zawężone.
df_roznica_minmax = pd.DataFrame([
{'parametr': 'długość kielicha', 'max-min': df['długość kielicha (sepal length)'].max() - df['długość kielicha (sepal length)'].min()},
{'parametr': 'szerokość kielicha', 'max-min': df['szerokość kielicha (sepal width)'].max() - df['szerokość kielicha (sepal width)'].min()},
{'parametr': 'długość płatka', 'max-min': df['długość płatka (petal length)'].max() - df['długość płatka (petal length)'].min()},
{'parametr': 'szerokość płatka', 'max-min': df['szerokość płatka (petal width)'].max() - df['szerokość płatka (petal width)'].min()}
],
index = ['A','B','C','D']
)
df_roznica_minmax
| parametr | max-min | |
|---|---|---|
| A | długość kielicha | 3.6 |
| B | szerokość kielicha | 2.4 |
| C | długość płatka | 5.9 |
| D | szerokość płatka | 2.4 |
Wniosek: Długość zarówno płatka jak i kielicha są cechami najbardziej zmiennymi oraz z największą rozpiętością między wartością maksymalną a minimalną. Szerokości kielicha i płatka są do siebie bardziej zbliżone niezależnie od klasy kwiatu.
1.5. Dane statystyczne dla każdej z kolumn, pogrupowane według klas kwiatu¶
Porównujemy parametry między trzema gatunkami irysów aby zidentyfikować różnice między nimi.
Wyróżnienia kolorystyczne:
Kolor niebieski - wartości najmniejsze w danym wierszu
Kolor czerwowny - wartości największe w danym wierszu
Średnia¶
df_srednia_klasy = df.groupby('klasa (class)', as_index=True).mean().T
df_srednia_klasy.style.highlight_min(axis=1, color='blue').highlight_max(axis=1, color='red')
| klasa (class) | Iris-setosa | Iris-versicolor | Iris-virginica |
|---|---|---|---|
| długość kielicha (sepal length) | 5.006000 | 5.936000 | 6.588000 |
| szerokość kielicha (sepal width) | 3.418000 | 2.770000 | 2.974000 |
| długość płatka (petal length) | 1.464000 | 4.260000 | 5.552000 |
| szerokość płatka (petal width) | 0.244000 | 1.326000 | 2.026000 |
Mediana¶
df_mediana_klasy = df.groupby('klasa (class)', as_index=True).median().T
df_mediana_klasy.style.highlight_min(axis=1, color='blue').highlight_max(axis=1, color='red')
| klasa (class) | Iris-setosa | Iris-versicolor | Iris-virginica |
|---|---|---|---|
| długość kielicha (sepal length) | 5.000000 | 5.900000 | 6.500000 |
| szerokość kielicha (sepal width) | 3.400000 | 2.800000 | 3.000000 |
| długość płatka (petal length) | 1.500000 | 4.350000 | 5.550000 |
| szerokość płatka (petal width) | 0.200000 | 1.300000 | 2.000000 |
Wartości maksymalne¶
df_max_klasy = df.groupby('klasa (class)', as_index=True).max().T
df_max_klasy.style.highlight_min(axis=1, color='blue').highlight_max(axis=1, color='red')
| klasa (class) | Iris-setosa | Iris-versicolor | Iris-virginica |
|---|---|---|---|
| długość kielicha (sepal length) | 5.800000 | 7.000000 | 7.900000 |
| szerokość kielicha (sepal width) | 4.400000 | 3.400000 | 3.800000 |
| długość płatka (petal length) | 1.900000 | 5.100000 | 6.900000 |
| szerokość płatka (petal width) | 0.600000 | 1.800000 | 2.500000 |
Wartości minimalne¶
df_min_klasy = df.groupby('klasa (class)', as_index=True).min().T
df_min_klasy.style.highlight_min(axis=1, color='blue').highlight_max(axis=1, color='red')
| klasa (class) | Iris-setosa | Iris-versicolor | Iris-virginica |
|---|---|---|---|
| długość kielicha (sepal length) | 4.300000 | 4.900000 | 4.900000 |
| szerokość kielicha (sepal width) | 2.300000 | 2.000000 | 2.200000 |
| długość płatka (petal length) | 1.000000 | 3.000000 | 4.500000 |
| szerokość płatka (petal width) | 0.100000 | 1.000000 | 1.400000 |
Wniosek: Z uśrednionych parametrów z każdej klasy zarysowuje się zależność, że najmniejszym kwiatem jest Iris-setosa, średnim jest Iris-versicolor, a największym Iris-virginica. Bardziej szczegółowo będzie to wykazane w kolejnych punktach.
2. Analiza brakujących wartości¶
Sprawdzamy jakość danych pod kątem kompletności i duplikatów.
2.1. Wartości brakujące dla każdej z kolumn¶
Liczymy ile wartości brakujących (NULL) występuje w każdej kolumnie.
df.isnull().sum()
długość kielicha (sepal length) 0 szerokość kielicha (sepal width) 0 długość płatka (petal length) 0 szerokość płatka (petal width) 0 klasa (class) 0 dtype: int64
2.2. Rekordy zduplikowane lub identyczne¶
Sprawdzamy czy w zbiorze występują identyczne rekordy, które mogą być wynikiem błędu w danych.
df[df.duplicated()]
| długość kielicha (sepal length) | szerokość kielicha (sepal width) | długość płatka (petal length) | szerokość płatka (petal width) | klasa (class) | |
|---|---|---|---|---|---|
| 34 | 4.9 | 3.1 | 1.5 | 0.1 | Iris-setosa |
| 37 | 4.9 | 3.1 | 1.5 | 0.1 | Iris-setosa |
| 142 | 5.8 | 2.7 | 5.1 | 1.9 | Iris-virginica |
Wniosek:
- Dane nie mają wartości brakujących.
- Dane mają 3 duplikaty, jednakże nie będziemy ich usuwać, ponieważ prawdopodobne jest, że wśród 150 kwiatów rzeczywiście mogą zdarzyć się kwiaty o identycznych parametrach.
3. Analiza pojedynczych zmiennych¶
Wizualizujemy rozkład każdej zmiennej numerycznej za pomocą histogramów.
3.1. Histogram dla każdej z kolumn numerycznych¶
Tworzymy histogramy dla wszystkich parametrów, aby zobaczyć ogólny rozkład wartości w całym zbiorze danych.
df.hist(bins=30);
Wniosek: Z powyżej przedstawionych histogramów nie wyczytamy zbyt wiele zależności, ponieważ parametry kwiatu różnią się w zależności od tego, do jakiej klasy przynależą. Dlatego lepszym sposobem na wizualizację parametrów będą histogramy z podziałem na klasy.
3.2. Histogram długości płatka z podziałem na klasy¶
Przedstawiamy rozkład długości płatka osobno dla każdego gatunku, aby porównać ich różnice.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
for class_name, group in df.groupby('klasa (class)'):
plt.hist(group['długość płatka (petal length)'], bins=10, alpha=0.5, label=class_name)
# Add labels and title in Polish
plt.xlabel('Długość płatka (cm)')
plt.ylabel('Liczba wystąpień')
plt.title('Histogram długości płatka z podziałem na klasy')
plt.legend(title='Klasa')
plt.show()
Wniosek: Klasa Iris-setosa zdecydowanie odstaje od pozostałych 2 klas pod względem długości płatka.
3.3. Histogram szerokości płatka z podziałem na klasy¶
Przedstawiamy rozkład szerokości płatka osobno dla każdego gatunku, aby porównać ich różnice.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
for class_name, group in df.groupby('klasa (class)'):
plt.hist(group['szerokość płatka (petal width)'], bins=10, alpha=0.5, label=class_name)
# Add labels and title in Polish
plt.xlabel('Szerokość płatka (cm)')
plt.ylabel('Liczba wystąpień')
plt.title('Histogram szerokości płatka z podziałem na klasy')
plt.legend(title='Klasa')
plt.show()
Wniosek: Klasa Iris-setosa, podobnie jak w przypadku długości płatka, również ma szerokość płatka znacznie mniejszą niż pozostałe 2 klasy.
3.4. Histogram długości kielicha z podziałem na klasy¶
Przedstawiamy rozkład długości kielicha osobno dla każdego gatunku, aby porównać ich różnice.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
for class_name, group in df.groupby('klasa (class)'):
plt.hist(group['długość kielicha (sepal length)'], bins=10, alpha=0.5, label=class_name)
# Add labels and title in Polish
plt.xlabel('Długość kielicha (cm)')
plt.ylabel('Liczba wystąpień')
plt.title('Histogram długości kielicha z podziałem na klasy')
plt.legend(title='Klasa')
plt.show()
Wniosek: Długość kielicha ma mniejsze zróżnicowanie niż wcześniejsze 2 parametry, długości kielicha są bardziej zbliżone do siebie. Jednakże wciąż zostaje zachowana kolejność: Iris-setosa ma najmniejsze wartości, następnie jest Iris-versicolor, a największy jest Iris-virginica.
3.5. Histogram szerokości kielicha z podziałem na klasy¶
Przedstawiamy rozkład szerokości kielicha osobno dla każdego gatunku, aby porównać ich różnice.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
for class_name, group in df.groupby('klasa (class)'):
plt.hist(group['szerokość kielicha (sepal width)'], bins=10, alpha=0.5, label=class_name)
# Add labels and title in Polish
plt.xlabel('Szerokość kielicha (cm)')
plt.ylabel('Liczba wystąpień')
plt.title('Histogram szerokości kielicha z podziałem na klasy')
plt.legend(title='Klasa')
plt.show()
Wniosek: Klasa Iris-setosa ma największe parametry szerokości kielicha. To pierwszy parametr, w którym Iris-setosa dominuje nad resztą klas pod względem wielkości. Nie są to jednak jakieś duże różnice – wszystko mieści się w przedziale zaledwie 2,4 cm.
3.6. Mediana parametrów dla każdej z klas kwiatu¶
Przedstawiamy wykres słupkowy z medianą wartości dla każdego gatunku, co pozwala na szybkie porównanie typowych wartości między klasami.
import matplotlib.pyplot as plt
medians = df.groupby('klasa (class)').median()
medians.plot(kind='bar', figsize=(10, 6))
plt.title('Mediana parametrów dla każdej klasy')
plt.xlabel('Klasa')
plt.ylabel('Mediana wartości')
plt.xticks(rotation=45)
plt.legend(title='Parametry', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.show()
Wniosek: Powyższy wykres z najczęściej występującymi wartościami potwierdza wcześniejsze histogramy:
- Iris-setosa ma w 3 parametrach (na 4 badane) najniższe wartości. Jedynie szerokość kielicha Iris-setosa jest wyjątkiem i jest największa wśród wszystkich 3 klas.
- Iris-setosa ma kielich najbardziej zbliżony do kształtu owalnego spośród wszystkich klas, ponieważ długość i szerokość kielicha mają zbliżone wartości.
- Pod względem ogólnej wielkości kwiatu można sklasyfikować poszczególne klasy jako: Iris-setosa (najmniejszy), Iris-versicolor (średni), Iris-virginica (największy).
4. Transformacja danych¶
Dane są czyste, brak konieczności poprawiania danych.
5. Relacje między zmiennymi¶
Badamy zależności między różnymi parametrami kwiatów, aby zrozumieć, które cechy są ze sobą powiązane.
5.1. Macierz korelacji między kolumnami¶
Obliczamy korelację między wszystkimi parametrami numerycznymi i wizualizujemy ją za pomocą mapy cieplnej, aby zobaczyć, które cechy są najbardziej ze sobą powiązane.
import seaborn as sns
import matplotlib.pyplot as plt
# Obliczanie macierzy korelacji dla kolumn numerycznych
correlation = df.corr(numeric_only=True)
plt.figure(figsize=(10, 8))
sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0,
square=True, linewidths=1, cbar_kws={"shrink": 0.8})
plt.title('Macierz korelacji między parametrami irysów')
plt.tight_layout()
plt.show()
Wnioski: Najbardziej skorelowane pary parametrów to:
- Długość płatka z szerokością płatka (0.96) – bardzo silna korelacja, co oznacza że im dłuższy płatek, tym jest również szerszy.
- Długość kielicha z długością płatka (0.87) – silna korelacja, większy kielich to większy płatek.
- Długość kielicha z szerokością płatka (0.82) – silna korelacja.
Wielkość całego kwiatu zależy najbardziej od długości płatka. Długość kielicha jest dobrym predyktorem wielkości całego kwiatu – silnie koreluje z wymiarami płatka. Szerokość kielicha nie jest wyznacznikiem wielkości kwiatu.
5.2. Wykres punktowy dla długości i szerokości płatka z podziałem na klasy¶
Tworzymy wykres rozrzutu (scatter plot), aby zobaczyć zależność między długością a szerokością płatka oraz jak różnią się klasy pod tym względem.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 6))
colors = {'Iris-setosa': 'red', 'Iris-versicolor': 'green', 'Iris-virginica': 'blue'}
for class_name, group in df.groupby('klasa (class)'):
subset = df[df['klasa (class)'] == class_name]
plt.scatter(subset['długość płatka (petal length)'], subset['szerokość płatka (petal width)'],
label=class_name, color=colors[class_name])
# Add labels and title
plt.xlabel('Długość płatka w cm')
plt.ylabel('Szerokość płatka w cm')
plt.title('Wykres rozrzutu dla długości i szerokości płatka')
plt.legend(title='Klasa')
plt.show()
Wniosek: Klasa Iris-setosa ma zdecydowanie mniejsze płatki (długość i szerokość) niż pozostałe 2 klasy.
6. Wartości odstające¶
Identyfikujemy wartości odstające (outliers) za pomocą wykresów pudełkowych (box plot).
Tworzymy wykresy pudełkowe dla wszystkich cech, które pokazują medianę, kwartyle oraz wartości odstające dla każdego parametru.
import matplotlib.pyplot as plt
plt.figure(figsize=(10, 5))
df_nazwy_kolumn = df.copy()
df_nazwy_kolumn.columns = ['długość kielicha', 'szerokość kielicha', 'długość płatka', 'szerokość płatka', 'klasa']
df_nazwy_kolumn.boxplot(column=['długość kielicha', 'szerokość kielicha', 'długość płatka', 'szerokość płatka'])
plt.title('Box Plot dla cech irysów')
plt.ylabel('Wartości w cm')
plt.xlabel('Cechy')
plt.show()
Wniosek: Największy rozrzut w wartościach ma parametr długości płatka, wpływ na to niewątpliwie ma klasa Iris-setosa, która ma znacznie krótsze płatki niż pozostałe 2 klasy. Najmniejszy rozrzut wartości występuje w szerokości kielicha, jednakże jako jedyny parametr ma on wartości odstające poza normę.
7. Podsumowanie analizy¶
Dokonano analizy 150 pomiarów dla 4 parametrów kwiatu Irisa. Dane były podzielone na 3 klasy kwiatu (po 50 pomiarów dla każdej z klas).
Dane były czyste, bez wartości brakujących, jedynie z 3 duplikatami, które jednak mogły nie być wynikiem pomyłki w zapisie danych – duplikaty w tego typu analizie są możliwe.
Klasa Iris-setosa zdecydowanie odstaje pod względem długości i szerokości płatka od pozostałych 2 klas. W przypadku długości kielicha wartości są bardziej zbliżone we wszystkich klasach. Natomiast wyjątkowo w szerokości kielicha klasa Iris-setosa nieznacznie dominuje nad resztą klas.
Na podstawie przeanalizowanych danych można stwierdzić, że najmniejszym/najdrobniejszym kwiatem jest Iris-setosa, średnim jest Iris-versicolor, a największym Iris-virginica.
Wielkość całego kwiatu w największym stopniu zależy od długości płatka (korelacja 0.96 z szerokością płatka). Długość kielicha jest dobrym predyktorem wielkości – silnie koreluje z wymiarami płatka (0.87 i 0.82). Natomiast szerokość kielicha nie ma większego znaczenia co do wielkości całego kwiatu.
Największy rozrzut w wartościach ma parametr długości płatka, wpływ na to niewątpliwie ma klasa Iris-setosa, która ma znacznie krótsze płatki niż pozostałe 2 klasy. Najmniejszy rozrzut wartości występuje w szerokości kielicha, jednakże jako jedyny parametr ma on wartości odstające poza normę.
Wnioski bardziej szczegółowe znajdują się w niemal każdym podpunkcie powyższej analizy.
!jupyter nbconvert Zad.1_Iris_EDA_raport_presentation.ipynb --to slides --no-input --no-prompt
[NbConvertApp] Converting notebook Zad.1_Iris_EDA_raport_presentation.ipynb to slides [NbConvertApp] WARNING | Alternative text is missing on 9 image(s). [NbConvertApp] Writing 719001 bytes to Zad.1_Iris_EDA_raport_presentation.slides.html