Original size 736x948

Анализ выживаемости пассажиров Титаника с помощью Pandas и визуализаций

PROTECT STATUS: not protected
The project is taking part in the competition

датасет

Название: Titanic passengers Источник: публичный датасет библиотеки seaborn (репозиторий на GitHub) Прямая ссылка: https://raw.githubusercontent.com/mwaskom/seaborn-data/master/titanic.csv

почему эти данные интересны

1.Исторически известная катастрофа, связанная с человеческим фактором. 2.Есть много категориальных и числовых признаков (пол, класс, возраст, стоимость билета и т. д.). 3.Удобно демонстрировать базовые статистические методы и интерпретируемые визуализации.

типы графиков (минимум 4 разных вида)

1. Столбчатая диаграмма (barplot) — общая выживаемость. 2. Составленная (stacked) столбчатая диаграмма — выживаемость по классам. 3. Гистограмма + KDE — распределение возраста по группам выживаемости. 4. Boxplot (ящик с усами) — возраст по полу и классу. 5. Тепловая карта (heatmap) — матрица корреляций числовых признаков.

используемые статистические методы

- Описательная статистика: среднее, медиана, стандартное отклонение (df.describe ()). - Частоты и доли (value_counts, normalize=True) для категориальных признаков. - Группировка и агрегация (groupby + agg, mean как оценка вероятности выживания). - Сводные таблицы (pivot_table). - Корреляция Пирсона для числовых признаков (df.corr ()).

import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns

Чтобы графики отображались крупнее и читабельнее

plt.rcParams['figure.figsize'] = (10, 6) plt.rcParams['axes.titlesize'] = 16 plt.rcParams['axes.labelsize'] = 12 plt.rcParams['xtick.labelsize'] = 10 plt.rcParams['ytick.labelsize'] = 10

def set_custom_style ():

Настройка единого стиля инфографики. Здесь создаём минималистичный «журнальный» стиль:  — светлый фон  — приглушённая палитра  — единый шрифт без засечек

sns.set_theme (style="whitegrid») custom_palette = [«

0d6efd», »

20c997», «

fd7e14», »

e83e8c», «#6f42c1»] sns.set_palette (custom_palette) plt.rcParams['font.family'] = 'DejaVu Sans' plt.rcParams['axes.facecolor'] = «#f8f9fa» plt.rcParams['figure.facecolor'] = «#f8f9fa» plt.rcParams['axes.edgecolor'] = «#dee2e6» plt.rcParams['grid.color'] = «#dee2e6»

def load_data ():

Загрузка датасета Titanic из GitHub (seaborn-data). Возвращает DataFrame.

url = «<a rel="noopener" href="https://raw.githubusercontent.com/mwaskom/seaborn-data/master/titanic.csv" data-target="blank" target="_blank">https://raw.githubusercontent.com/mwaskom/seaborn-data/master/titanic.csv"</a>
df = pd.read_csv (url)
return df

def preprocess_data (df):

предобработка данных

- Переименование столбцов для удобства (русские названия в отдельных столбцах)  — Создание новых признаков (family_size, is_child, age_group)  — Обработка пропусков (возраст, класс и т. д. оставляем как есть, но можем фильтровать по необходимости) «»» df = df.copy ()

переименуем некоторые переменные для ясности при визуализации (создадим дубли-столбцы на русском)

df[«Пол»] = df[«sex»].map ({"male»: «Мужчина», «female»: «Женщина"}) df[«Класс»] = df[«class»].map ({"First»: «1 класс», «Second»: «2 класс», «Third»: «3 класс"}) df[«Выжил»] = df[«survived»].map ({0: «Нет», 1: «Да"})

новый признак: размер семьи (чем больше семья, тем потенциально сложнее эвакуация)

df[«family_size»] = df[«sibsp»] + df[«parch»] + 1

новый признак: ребёнок/взрослый (возраст < 16 лет)

df[«is_child»] = np.where (df[«age»] < 16, 1, 0)

группы возраста для более «объясняющего» анализа

bins = [0, 12, 18, 30, 50, 80] labels = [«0-12 (дети)», «13-18 (подростки)», «19-30 (молодые)», «31-50 (взрослые)», «51+ (старшие)»] df[«age_group»] = pd.cut (df[«age»], bins=bins, labels=labels, right=True)

return df

def descriptive_statistics (df):

показ описательной статистики и базовых частот

Это демонстрация использования статистических методов:  — describe () для числовых колонок  — value_counts () и доли (normalize=True) для категорий «»» print («=== Описательная статистика числовых признаков ===») print (df[[«survived», «pclass», «age», «sibsp», «parch», «fare», «family_size»]].describe (), «\n»)

print («=== Распределение по полу ===»)
print (df[«Пол»].value_counts (), «\n»)

print («=== Распределение по полу (доли) ===»)
print (df[«Пол»].value_counts (normalize=True), «\n»)

print («=== Общий уровень выживаемости (доля выживших) ===»)
survival_rate = df[«survived»].mean ()
print (f"Доля выживших: {survival_rate:.2%}\n»)

print («=== Уровень выживаемости по полу ===»)
print (df.groupby («Пол»)[«survived»].mean ().apply (lambda x: f"{x:.2%}»), «\n»)

print («=== Уровень выживаемости по классам ===»)
print (df.groupby («Класс»)[«survived»].mean ().apply (lambda x: f"{x:.2%}»), «\n»)

print («=== Уровень выживаемости по возрастным группам ===»)
print (
    df.groupby («age_group»)[«survived»]
    .mean ()
    .dropna ()
    .apply (lambda x: f"{x:.2%}»)

)

def plot_overall_survival (df):

график 1 (столбчатая диаграмма)

Общий уровень выживаемости на Титанике (количество и доля). Показывает изучающий и объясняющий формат:  — понятные подписи  — подписи процентов на столбиках

Original size 984x579

set_custom_style ()

surv_counts = df[«Выжил»].value_counts ().reindex ([«Да», «Нет»])
surv_rate = df[«survived»].mean ()

fig, ax = plt.subplots ()
sns.barplot (x=surv_counts.index, y=surv_counts.values, ax=ax)

ax.set_title («Выживаемость на Титанике (общее распределение)»)
ax.set_xlabel («Выжил»)
ax.set_ylabel («Количество пассажиров»)

# Подпишем значения на столбиках
for i, v in enumerate (surv_counts.values):
    ax.text (i, v \+ 5, str (v), ha="center», va="bottom», fontweight="bold»)

# Добавим текстовое пояснение с общим процентом выживаемости
ax.text (
    0.5, -0.2,
    f"Общая доля выживших: {surv_rate:.1%}»,
    transform=ax.transAxes,
    ha="center»,
    va="center»,
    fontsize=12

)

plt.tight_layout ()
plt.savefig («plot1_overall_survival.png», dpi=300)
plt.show ()

def plot_survival_by_class_stacked (df):

график 2 (составленная столбчатая диаграмма)

Original size 984x584

Выживаемость по классам (1, 2, 3) — stacked bar. Используется сводная таблица (pivot_table) как статистический метод. «»» set_custom_style ()

pivot = pd.crosstab (df[«Класс»], df[«Выжил»], normalize="index») * 100
pivot = pivot[[«Да», «Нет»]] # порядок столбцов

ax = pivot.plot (
    kind="bar»,
    stacked=True,
    figsize=(10, 6),

)

ax.set_title («Выживаемость по классам (в процентах)»)
ax.set_xlabel («Класс»)
ax.set_ylabel («Доля пассажиров, %»)

# Подпишем проценты внутри столбиков
for c in ax.containers:
    ax.bar_label (c, fmt="%.1f%%», label_type="center»)

plt.legend (title="Выжил»)
plt.tight_layout ()
plt.savefig («plot2_survival_by_class_stacked.png», dpi=300)
plt.show ()

def plot_age_distribution_by_survival (df):

изучающий формат: средний билет и выживаемость по полу и классу

Original size 483x165

Комментарий: - Видно, что пассажиры 1 класса платили больше и имели более высокий шанс выживания. - Женщины в среднем выживали чаще мужчин во всех классах.

график 3 (гистограмма + KDE)

Original size 984x584

Распределение возраста в зависимости от выживания. Используется:  — гистограмма (распределение частот)  — оценка плотности (KDE) как изучающий метод «»» set_custom_style ()

# Фильтруем строки с известным возрастом
age_df = df.dropna (subset=[«age»])

fig, ax = plt.subplots ()
sns.histplot (
    data=age_df,
    x="age»,
    hue="Выжил»,
    element="step»,
    kde=True,
    stat="density»,
    common_norm=False,
    ax=ax,
    bins=25,

)

ax.set_title («Распределение возраста по статусу выживания»)
ax.set_xlabel («Возраст»)
ax.set_ylabel («Плотность»)

plt.tight_layout ()
plt.savefig («plot3_age_distribution_by_survival.png», dpi=300)
plt.show ()

def plot_box_age_by_class_and_sex (df):

график 4 (boxplot)

Original size 984x584

Возраст пассажиров по полу и классу. Позволяет изучить распределение (медиана, квартили, выбросы). «»» set_custom_style ()

age_df = df.dropna (subset=[«age»])

fig, ax = plt.subplots ()
sns.boxplot (
    data=age_df,
    x="Класс»,
    y="age»,
    hue="Пол»,
    ax=ax,

)

ax.set_title («Возраст пассажиров по полу и классу»)
ax.set_xlabel («Класс»)
ax.set_ylabel («Возраст»)

plt.legend (title="Пол»)
plt.tight_layout ()
plt.savefig («plot4_box_age_by_class_and_sex.png», dpi=300)
plt.show ()

def plot_correlation_heatmap (df):

график 5 (тепловая карта корреляций)

Original size 691x584

Матрица корреляций числовых признаков. Используется коэффициент корреляции Пирсона (corr ()). «»» set_custom_style ()

numeric_cols = [«survived», «pclass», «age», «sibsp», «parch», «fare», «family_size», «is_child»]
corr = df[numeric_cols].corr ()

fig, ax = plt.subplots ()
sns.heatmap (
    corr,
    annot=True,
    fmt=».2f»,
    cmap="coolwarm»,
    vmin=-1,
    vmax=1,
    square=True,
    ax=ax,

)

ax.set_title («Корреляция числовых признаков (Пирсон)»)
plt.tight_layout ()
plt.savefig («plot5_correlation_heatmap.png», dpi=300)
plt.show ()

def exploring_and_explaining_examples (df):

примеры «изучающего» и «объясняющего» форматa

  1. Изучающий:  — Посмотрим, как меняется средняя цена билета и шанс выживания в зависимости от класса и пола.

    1. Объясняющий:  — Сформируем табличку с ключевыми метриками по группам.

print («\n=== Изучающий формат: средний билет и выживаемость по полу и классу ===») group_stats = ( df.groupby ([«Пол», «Класс»]) .agg ( mean_fare=(«fare», «mean»), survival_rate=(«survived», «mean»), count=(«survived», «size»), ) .reset_index () )

group_stats[«survival_rate»] = group_stats[«survival_rate»].apply (lambda x: f"{x:.1%}»)
group_stats[«mean_fare»] = group_stats[«mean_fare»].round (2)

print (group_stats.to_string (index=False))

print («\nКомментарий:»)
print (» — Видно, что пассажиры 1 класса платили больше и имели более высокий шанс выживания.»)
print (» — Женщины в среднем выживали чаще мужчин во всех классах.»)

print («\n=== Объясняющий формат: ключевые выводы ===»)
print («1. Общая доля выживших на Титанике около "
      f"{df['survived'].mean ():.1%}.»)
print («2. Наибольшая выживаемость наблюдается у женщин и у пассажиров 1 класса.»)
print («3. Размер семьи и факт, что пассажир ребёнок, также связаны с выживаемостью.»)
print («4. Корреляционная матрица показывает, что класс билета и стоимость билета "
      «связаны между собой и с вероятностью выживания (через социальный статус).»)

def main (): # 1. Загрузка данных df_raw = load_data ()

# 2. Предобработка данных и создание новых признаков
df = preprocess_data (df_raw)

# 3. Описательная статистика и базовый анализ
descriptive_statistics (df)

# 4. Визуализации (минимум 4 разных вида графиков)
plot_overall_survival (df) # График 1: barplot
plot_survival_by_class_stacked (df) # График 2: stacked bar
plot_age_distribution_by_survival (df) # График 3: histogram \+ KDE
plot_box_age_by_class_and_sex (df) # График 4: boxplot
plot_correlation_heatmap (df) # График 5: heatmap

# 5. Примеры изучающего и объясняющего форматов
exploring_and_explaining_examples (df)

print («\nГотово! Графики также сохранены в файлы:»)
print (» — plot1_overall_survival.png»)
print (» — plot2_survival_by_class_stacked.png»)
print (» — plot3_age_distribution_by_survival.png»)
print (» — plot4_box_age_by_class_and_sex.png»)
print (» — plot5_correlation_heatmap.png»)

if name == «main»: main ()

описательная статистика числовых признаков

Original size 895x455
Original size 518x602
Original size 576x170

/tmp/ipython-input-4227034227.py: 125: FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning. df.groupby («age_group»)[«survived»]

объясняющий формат: ключевые выводы

1. Общая доля выживших на Титанике около 38,4%. 2. Наибольшая выживаемость наблюдается у женщин и у пассажиров 1 класса. 3. Размер семьи и факт, что пассажир ребёнок, также связаны с выживаемостью. 4. Корреляционная матрица показывает, что класс билета и стоимость билета связаны между собой и с вероятностью выживания (через социальный статус).

В рамках проекта применялась генеративная модель ChatGPT (OpenAI) для помощи в структурировании проекта, формулировке аналитических выводов и оптимизации визуального оформления графиков. ИИ использовался как вспомогательный инструмент и не заменял самостоятельный анализ данных.