Original size 1140x1600

Визуализация данных Mushroom Classification

PROTECT STATUS: not protected
3

Введение

Большую часть времени в детстве я проводила на природе. Переехав в большой город, мне стало не хватать живой природы — растений, грибов и диких животных. Тоскуя по родному краю, в своих проектах я стала часто обращаться к темам, связанным с ним.

Во втором модуле я создала книгу, посвященную грибам, которые обитают в лесах Мордовии. В процессе работы над иллюстрациями, я очень полюбила то, насколько грибы могут быть разными и совсем непохожими на свой распространённый образ «ножка-шляпка», что сподвигло меня немного углубиться в любительское изучение.

Я выбрала датасет «Mushroom Classification», который доступен в формате CSV на Kaggle. Он содержит информацию о 8124 грибах и их признаках: форма шляпки, цвет, запах, текстура ножки и др., а также классификацию: съедобный (e) или ядовитый (p). Все признаки категориальные — то есть значения заданы в виде символов.

Визуальный стиль

post

Для создания визуального стиля мне захотелось использовать самую первую ассоциацию с грибами — красно-белый мухомор, для этого я извлекла из обычной стоковой фотографии палитру из девяти цветов.

big
Original size 2400x425

Этапы работы

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib as mpl

df = pd.read_csv («mushrooms.csv»)

1. Загрузка и первичный анализ.

Самым первым этапом был импорт необходимых библиотек для визуализации данных. Pandas — для обработки датасета, Matplotlib — для настройки и построения графиков, а Seaborn — для построения наглядных диаграмм с красивым оформлением. Затем, я загрузила датасет «mushrooms.csv» и сохранила его в переменной df, чтобы в дальнейшем работать с ним как с таблицей.

class_map = {'e': 'съедобный', 'p': 'ядовитый'}
odor_labels = {
    'a': 'миндаль', 'l': 'анис', 'c': 'креозот', 'y': 'рыба',
    'f': 'фрукт', 'm': 'затхлый', 'n': 'нет запаха',
    'p': 'едкий', 's': 'пряный'
}
cap_color_labels = {
    'n': 'коричневый', 'b': 'белый', 'c': 'кремовый', 'g': 'серый',
    'r': 'зелёный', 'p': 'розовый', 'u': 'фиолетовый', 'e': 'красный',
    'w': 'белый', 'y': 'жёлтый'
}
habitat_labels = {
    'g': 'трава', 'l': 'листва', 'm': 'луга', 'p': 'поляна',
    'u': 'город', 'w': 'лес', 'd': 'древесина'
}
gill_size_labels = {'b': 'широкие', 'n': 'узкие'}

Далее, для удобства анализа и визуализации, я прописала словари, которые переводят сокращённые буквенные обозначения из датасета в понятные категории на русском языке — например, класс грибов, запах, цвет шляпки, среду обитания и размер пластинок.

df['class_label'] = df['class'].map (class_map)
df['odor_label'] = df['odor'].map (odor_labels)
df['cap_color_label'] = df['cap-color'].map (cap_color_labels)
df['habitat_label'] = df['habitat'].map (habitat_labels)
df['gill_size_label'] = df['gill-size'].map (gill_size_labels)

С помощью метода .map () создала в датафрейме новые столбцы с русскоязычными названиями категорий. Это позволило заменить кодовые обозначения (например, e, p, a, n) на понятные подписи — такие как «съедобный», «ядовитый», «миндаль», «нет запаха» и т. д.

mpl.rcParams.update ({
    «axes.facecolor»: «white»,
    «axes.edgecolor»: «#492925»,
    «axes.labelcolor»: «#492925»,
    «xtick.color»: «#492925»,
    «ytick.color»: «#492925»,
    «text.color»: «#3B1E1E»,
    «axes.titleweight»: «bold»,
    «axes.titlesize»: 18,
    «font.family»: «serif»
})

mushroom_palette = [
    «<h3>c42521», »</h3>cb5040», «<h3>d26a63», »</h3>edd9c5», «#d59b90»,
    «<h3>cf9973», »</h3>ad968e», «<h3>492925», »</h3>745e5e»
]
odor_colors = dict (zip (odor_labels.values (), mushroom_palette))

Я задала единый стиль для всех графиков: настроила цвета осей, текста и подписей. Также я создала палитру mushroom_palette, визуальный ряд которой я представляла выше в разделе с визуальным стилем. С помощью словаря odor_colors я сопоставила каждому значению запаха определённый цвет из палитры, чтобы сохранить единообразие двойного графика, посвященного сравнению запахов ядовитых и съедобных грибов.

Построение графиков и визуализация

1. Pie chart / Соотношение количества съедобных и несъедобных грибов.

labels = counts.index.map (class_map)

fig, ax = plt.subplots (figsize=(6, 6))
ax.pie (
    counts,
    labels=labels,
    autopct='%1.1f%%',
    startangle=90,
    colors=[mushroom_palette[0], mushroom_palette[3]],
    wedgeprops={'edgecolor': 'white'}
)
ax.set_title («Соотношение съедобных и ядовитых грибов»)
plt.tight_layout ()
plt.show ()

Чтобы показать соотношение съедобных и ядовитых грибов. Сначала с помощью value_counts () посчитала количество объектов каждого класса, а затем перевела их обозначения через class_map. Для построения графика использовала метод pie (): задала подписи, проценты, угол поворота и цветовые сегменты из палитры. Из построенного графика можно сделать вывод, что количество съедобных грибов на 3,6% больше, чем ядовитых.

Original size 1354x1050

2. Count plot / Соотношение запахов ядовитых и съедобных грибов

fig, axes = plt.subplots (1, 2, figsize=(16, 6), sharey=True)

for ax, class_name in zip (axes, ['съедобный', 'ядовитый']):
    subset = df[df['class_label'] == class_name]
    sns.countplot (
        data=subset,
        x='odor_label',
        hue='odor_label',
        order=odor_order,
        palette=odor_colors,
        ax=ax
)
    if ax.legend_:
        ax.legend_.remove ()
    ax.set_title (f"Запахи ({class_name})»)
    ax.set_xlabel («Запах»)
    ax.set_ylabel («Количество»)
    ax.tick_params (axis='x', rotation=30)

plt.tight_layout ()
plt.show ()

Я создала две области построения (subplots), чтобы графики отображались рядом и имели общую шкалу по оси Y. Затем с помощью countplot из библиотеки Seaborn для каждого класса грибов отобразила количество экземпляров с тем или иным запахом. Я зафиксировала порядок категорий (odor_order), задала цветовую палитру (odor_colors), убрала легенду, добавила подписи осей и заголовки.

По графикам можно сделать вывод, что ядовитые грибы обладают более широким спектром запахов, и наиболее часто встречающийся — фруктовый, в то время как съедобные грибы чаще всего не имеют запаха вовсе.

Original size 3180x1180

3.Scatter plot / Частота цветов шляпок грибов

    df.groupby (['cap_color_label', 'class_label'])
    .size ()
    .reset_index (name='count')
)

plt.figure (figsize=(10, 6))
sns.scatterplot (
    data=color_counts,
    x='cap_color_label',
    y='count',
    hue='class_label',
    palette=[mushroom_palette[0], mushroom_palette[3]],
    s=300,
    linewidth=0.5,
    edgecolor="white»
)
plt.title («Частота цветов шляпки по классам грибов»)
plt.xlabel («Цвет шляпки»)
plt.ylabel («Количество»)
plt.xticks (rotation=30)
plt.legend (title="Класс»)
plt.tight_layout ()
plt.show ()

Я сгруппировала данные по цвету шляпки и классу гриба, посчитав количество в каждой комбинации. Полученный результат отобразила на диаграмме рассеяния с помощью sns.scatterplot: по оси X указаны цвета шляпок, по оси Y — количество грибов, а цвет точек различает классы (съедобные и ядовитые). Также я настроила размер и обводку маркеров, подписи осей и легенду.

По графику можно сказать, что самый частотный цвет шляпки среди грибов как съедобных, так и ядовитых — коричневый, в то время как зелёный, фиолетовый и кремовый встречаются реже всего.

Original size 1968x1180

4. Histogram / Распределение размеров пластинок у съедобных и ядовитых грибов

sns.histplot (
    data=df,
    x='gill_size_label',
    hue='class_label',
    multiple='dodge',
    palette={
        'съедобный': mushroom_palette[3],
        'ядовитый': mushroom_palette[7]
    },
    shrink=0.8,
    edgecolor='white',
    linewidth=0.5
)
plt.title («Размеры пластинок у грибов»)
plt.xlabel («Размер пластинок»)
plt.ylabel («Количество»)
plt.tight_layout ()
plt.show ()

Чтобы построить гистограмму распределения размеров пластинок у съедобных и ядовитых грибов я использовала sns.histplot с параметром multiple='dodge', чтобы столбцы для каждого класса располагались рядом, а не наслаивались.

График показал, что широкие пластинки наиболее свойственны съедобным видам грибов, в то время как распределение узкопластинчатых и широкопластинчатых видов ядовитых грибов примерно одинаковое.

Original size 1580x1180

5. Stacked bar chart / Распределение ядовитых и съедобных грибов в разных средах обитания

stacked_data = (
    df.groupby (['habitat_label', 'class_label'])
    .size ()
    .unstack (fill_value=0)
    .reindex (habitat_order)
)

stacked_data.plot (
    kind='bar',
    stacked=True,
    figsize=(10, 6),
    color=[mushroom_palette[3], mushroom_palette[0]]
)
plt.title («Среда обитания по классам»)
plt.xlabel («Среда обитания»)
plt.ylabel («Количество»)
plt.xticks (rotation=45)
plt.legend (title="Класс»)
plt.tight_layout ()
plt.show ()

Я сгруппировала данные по двум признакам и посчитала количество объектов в каждой комбинации с помощью groupby ().size (). С помощью unstack (fill_value=0) развернула таблицу так, чтобы классы грибов стали отдельными столбцами, а reindex (habitat_order) упорядочила строки по логической последовательности сред обитания (трава, листва, луга, и т. д.). После этого я построила диаграмму с помощью метода plot (kind='bar', stacked=True), чтобы столбцы каждого класса складывались друг на друга.

Диаграмма показала, что чаще всего грибы в целом обитают на древесине, и реже всего в лесу.

Original size 1080x644

Описание применения генеративной модели

С помощью генеративной модели Chat GPT я генерировала код для построения графиков, после чего самостоятельно его редактировала. Изображение на обложке проекта было сгенерировано с помощью Google Gemini.

Визуализация данных Mushroom Classification
3
We use cookies to improve the operation of the website and to enhance its usability. More detailed information on the use of cookies can be fo...
Show more