Суицид - важная и тяжелая проблема нашего общества, о которой не принято говорить открыто. Анализ уровня суицида является важным социально-демографическим показателем, отражающим совокупное влияние экономических, культурных и психологических факторов. В разных странах и временных периодах этот показатель ведёт себя по-разному, что делает его анализ особенно значимым для понимания устойчивых различий между социальными группами. Изучение динамики самоубийств во времени, а также различий по полу, странам и поколениям позволяет увидеть, как масштабные человеческие процессы проявляются в статистических данных.
В своём анализе я использовала датасет “Suicide Rates Overview 1985–2016”, опубликованный на платформе Kaggle. Датасет содержит данные о количестве самоубийств, численности населения, уровне самоубийств на 100 тысяч человек, поле, возрастных группах и поколениях в разных с странах в период с 1985 по 2016 год.
Кроме того, в набор данных входят макроэкономические показатели, такие как ВВП на душу населения и индекс человеческого развития (HDI), что позволяет рассматривать уровень самоубийств в более широком социально-экономическом контексте.
Интерес к этому датасету был обусловлен несколькими причинами:
Во-первых, тема напрямую связана с социальными и демографическими процессами и показывает, как сложные и болезненные человеческие явления могут быть формализованы в виде чисел.
Во-вторых, структура данных позволяет анализировать изменения во времени и сравнивать разные группы — по полу, странам и поколениям, — выстраивая связный исследовательский нарратив и предоставляя пространство для анализа причин суицида и выявления наиболее подверженных проблеме групп.
В-третьих, датасет даёт возможность сочетать визуальный анализ с применением статистических методов, переходя от наглядных графиков к проверке гипотез.
На начальном этапе данные были загружены из CSV-файла master.csv с использованием языка программирования Python и библиотеки Pandas.
После загрузки была выполнена базовая подготовка структуры таблицы: названия столбцов очищены от лишних пробелов.
Для первичного ознакомления с данными были выведены первые строки таблицы, а также информация о типах переменных и наличии пропусков. Этот шаг позволил понять общую структуру датасета, определить числовые и категориальные переменные и наметить дальнейшие шаги по очистке данных.
На втором этапе была проведена очистка данных и приведение переменных к корректным типам, необходимым для дальнейшего анализа и визуализации. В первую очередь столбец year был преобразован в числовой формат.
Далее числовые показатели, содержащие значения с разделителями, были очищены от запятых и приведены к типам float или int. Также была выполнена стандартизация значений переменной sex, чтобы избежать дублирования категорий из-за различий в формате записи.
Для визуального оформления проекта была выбрана ограниченная холодная палитра, основанная на сочетании чёрного, тёмно-синего и светлых голубых оттенков с белыми акцентами. Такое решение напрямую отсылает к визуальному языку фирменного стиля проекта и поддерживает общее эмоциональное и смысловое поле - холодное, тяжелое.
Глубокий чёрный (фон) #0E0E11 Тёмный ночной синий #1C2A3A Холодный сине-серый #3A5F7D Приглушённый голубой #6FA3C8 Светлый ледяной голубой #BFD9EA Мягкий белый (акценты, текст) #F4F6F8
Динамика во времени не является линейной или однозначной. В разные периоды наблюдаются росты и спады, что показывает: для корректной интерпретации необходимо учитывать дополнительные факторы и разбиение на группы. Также становится очевидно, что абсолютные значения и нормализованный показатель могут демонстрировать разные визуальные тренды, поэтому их важно рассматривать совместно.
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot( yearly["year"], yearly["suicides_total"], color=COL_BLACK, linewidth=2.2 )
ax.set_title("Глобальная динамика: абсолютное число самоубийств (1985–2016)") ax.set_xlabel("Год") ax.set_ylabel("Количество случаев (сумма по всем странам)")
ax.text( 0.02, 0.98, "Абсолютные числа зависят от размера населения.\n" "Поэтому далее дополнительно смотрим показатель на 100 тыс.", transform=ax.transAxes, ha="left", va="top", color="#F4F6F8", bbox=dict( boxstyle="round,pad=0.4", facecolor="#1C2A3A", edgecolor="#3A5F7D", linewidth=1 ) )
plt.tight_layout() plt.show()
fig, ax = plt.subplots(figsize=(12, 5))
ax.plot( yearly["year"], yearly["rate_mean"], color=COL_RED, linewidth=2.2 )
ax.set_title( "Глобальная динамика: средний уровень самоубийств на 100 тыс. населения" ) ax.set_xlabel("Год") ax.set_ylabel("Самоубийства на 100 тыс. (среднее по странам/наблюдениям)")
подсказка-вынос (использует обновлённый add_callout)
add_callout( ax, "Нормализация (на 100 тыс.)\n" "позволяет сравнивать страны и годы корректнее.", xy=(0.02, 0.98) )
plt.tight_layout() plt.show()
Гендерный разрыв сохраняется на протяжении всего анализируемого периода: показатели среди мужчин стабильно выше, чем среди женщин. При этом форма кривых у мужчин и женщин схожа, что говорит о схожей общей динамике, но на разных уровнях. Это указывает на устойчивый структурный характер различий, а не на единичные всплески.
pivot_sex = yearly_sex.pivot(index="year", columns="sex", values="rate_mean")
fig, ax = plt.subplots(figsize=(12, 5), facecolor=BG)
if "male" in pivot_sex.columns: ax.plot( pivot_sex.index, pivot_sex["male"], color=COL_RED, # приглушённый голубой linewidth=2.4, label="Мужчины" )
if "female" in pivot_sex.columns: ax.plot( pivot_sex.index, pivot_sex["female"], color=COL_ORNG, # светлый ледяной голубой linewidth=2.4, label="Женщины" )
ax.set_title( "Уровень самоубийств по полу: динамика (на 100 тыс.)", color=COL_BLACK ) ax.set_xlabel("Год", color=COL_BLACK) ax.set_ylabel("Самоубийства на 100 тыс.", color=COL_BLACK)
легенда в тёмном стиле
ax.legend( frameon=True, facecolor="
1C2A3A",
тёмный ночной синий edgecolor="#3A5F7D", labelcolor=COL_BLACK )выноска (использует обновлённый add_callout)
add_callout( ax, "Наблюдается устойчивый гендерный разрыв:\n" "мужчины выше женщин на протяжении всего периода." )
plt.tight_layout() plt.show()
У стран наблюдаются принципиально разные формы динамики: в одних странах уровень снижается, в других — растёт или колеблется. Это подтверждает, что не существует универсального глобального тренда, и анализ уровня самоубийств требует учёта национального контекста.
countries = list(top_countries) colors = custom_colors[:len(generations)]
fig, ax = plt.subplots(figsize=(12, 6))
for country, color in zip(countries, colors): d = yearly_country[yearly_country["country"] == country] ax.plot(d["year"], d["rate_mean"], color=color, linewidth=2.0, label=country)
ax.set_title(f"Топ-{topN} стран по вкладу: уровень самоубийств (на 100 тыс.)") ax.set_xlabel("Год") ax.set_ylabel("Самоубийства на 100 тыс.") ax.legend(ncol=2, frameon=True, facecolor="
FFFDF8", edgecolor="
E5DDCF")add_callout(ax, "Одинакового «универсального» тренда нет:\n" "траектории заметно отличаются между странами.")
plt.tight_layout()
Некоторые показатели демонстрируют статистическую связь с уровнем самоубийств. При этом важно подчеркнуть, что корреляция не означает причинно-следственную связь, а лишь указывает на совместное изменение показателей.
fig, ax = plt.subplots(figsize=(6.5, 5.5), facecolor=BG)
чтобы область осей тоже была тёмной (иногда rcParams не применяются везде)
ax.set_facecolor(BG)
im = ax.imshow( corr.values, cmap=custom_cmap, vmin=-1, vmax=1 )
подписи осей
ax.set_xticks(range(len(corr.columns))) ax.set_yticks(range(len(corr.columns)))
ax.set_xticklabels( ["Суициды / 100 тыс.", "ВВП на душу", "ИЧР"], rotation=25, ha="right", color=COL_BLACK ) ax.set_yticklabels( ["Суициды / 100 тыс.", "ВВП на душу", "ИЧР"], color=COL_BLACK )
тонкие линии сетки по ячейкам (чтобы матрица читалась аккуратно)
ax.set_xticks([x - 0.5 for x in range(1, corr.shape[1])], minor=True) ax.set_yticks([y - 0.5 for y in range(1, corr.shape[0])], minor=True) ax.grid(which="minor", color="#1C2A3A", linestyle="-", linewidth=1) ax.tick_params(which="minor", bottom=False, left=False)
Автоконтраст текста: цвет зависит от яркости ячейки
norm = mcolors.Normalize(vmin=-1, vmax=1)
for i in range(corr.shape[0]): for j in range(corr.shape[1]): val = corr.values[i, j]
# RGBA цвет ячейки из cmap
r, g, b, _ = custom_cmap(norm(val))
# воспринимаемая яркость
luminance = 0.2126 * r + 0.7152 * g + 0.0722 * b
# если фон тёмный — белый текст, если светлый — тёмный
txt_color = "<h3>F4F6F8" if luminance < 0.45 else "</h3>0E0E11"
ax.text(
j, i,
f"{val:.2f}",
ha="center",
va="center",
color=txt_color,
fontsize=11,
fontweight="bold"
)
оформление осей под тёмный фон
ax.tick_params(colors=COL_BLACK) for spine in ax.spines.values(): spine.set_color(COL_BLACK)
ax.set_title("Корреляции (Спирмен): уровень и макропоказатели", color=COL_BLACK)
выноска (предполагается, что add_callout уже обновлена под тёмный фон)
add_callout( ax, "Спирмен оценивает монотонную связь\nи менее чувствителен к выбросам,\nчем корреляция Пирсона.", xy=(0.02, 0.98) )
plt.tight_layout() plt.show()




