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

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

Этапы работы
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% больше, чем ядовитых.
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), убрала легенду, добавила подписи осей и заголовки.
По графикам можно сделать вывод, что ядовитые грибы обладают более широким спектром запахов, и наиболее часто встречающийся — фруктовый, в то время как съедобные грибы чаще всего не имеют запаха вовсе.
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 — количество грибов, а цвет точек различает классы (съедобные и ядовитые). Также я настроила размер и обводку маркеров, подписи осей и легенду.
По графику можно сказать, что самый частотный цвет шляпки среди грибов как съедобных, так и ядовитых — коричневый, в то время как зелёный, фиолетовый и кремовый встречаются реже всего.
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', чтобы столбцы для каждого класса располагались рядом, а не наслаивались.
График показал, что широкие пластинки наиболее свойственны съедобным видам грибов, в то время как распределение узкопластинчатых и широкопластинчатых видов ядовитых грибов примерно одинаковое.
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), чтобы столбцы каждого класса складывались друг на друга.
Диаграмма показала, что чаще всего грибы в целом обитают на древесине, и реже всего в лесу.
Описание применения генеративной модели
С помощью генеративной модели Chat GPT я генерировала код для построения графиков, после чего самостоятельно его редактировала. Изображение на обложке проекта было сгенерировано с помощью Google Gemini.