Исходный размер 960x1280

Эффективность ваших тренировок

PROTECT STATUS: not protected

Введение.

Спорт и здоровый образ жизни — не просто тренды, а важная часть современной культуры заботы о себе. Однако зачастую люди следуют шаблонным рекомендациям, не учитывая индивидуальные особенности: пол, уровень подготовки, состав тела или даже привычки, такие как потребление воды. И поскольку я сама не так давно начала ходить в спортивный зал и работать над своим телом, эта тема мне особенно интересна.

Данные я искала на платформе Kaggle и решила остановиться на датасете "Gym Members Exercise Dataset", содержащий подробную информацию о 973 тренировках — от физиологических показателей (ЧСС, калории, % жира) до поведенческих (тип тренировки, частота, длительность, гидратация).

В этом проекте я решила исследовать, какие факторы действительно влияют на эффективность тренировки. Цель — найти закономерности, которые помогут сделать тренировки умнее, безопаснее и результативнее.

Поскольку меня заинтересовал этот проект, я решила подробнее углубиться в способы визуализации и анализа данных и дополнительно изучила курс на stepik по библиотеке matplotlib "Визуализация с Matplotlib для анализа данных" и документацию по библиотекам matplotlib, seaborn, numpy, pandas.

Ссылка на копию ноутбука с кодом: https://colab.research.google.com/drive/1L3N8pEg2tLE09fTxX6ZHAkJKmge-NpQo

Коррелограмма.

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

Чтобы визуализировать все попарные корреляции сразу, я построила тепловую карту —коррелограмму. Чтобы избежать дублирования и улучшить читаемость, отображена только нижняя треугольная часть матрицы: диагональ (где каждый признак коррелирует сам с собой, r=1) и зеркальные значения исключены как избыточные.

data_corr = data[num_cols].corr().round(2) mask = np.triu(np.ones_like(data_corr, dtype=bool)) # Приводим к нижнетреугольной матрице

plt.figure(figsize=(10, 8)) heatmap = sns.heatmap( data_corr, mask=mask, annot=True, fmt=".2f", cmap='coolwarm', square=True, linewidths=0.6, linecolor='#E0E0E0') heatmap.set_facecolor('#FAFAFA') heatmap.tick_params(axis='x', rotation=45, colors='#333333', labelsize=9) heatmap.tick_params(axis='y', rotation=0, colors='#333333', labelsize=9)

plt.title('Коррелограмма', fontsize=14, pad=20, fontweight='bold', color='#222222') plt.tight_layout() plt.show()

Исходный размер 890x790

Анализ зависимостей признаков с высокой корреляцией.

Важно помнить, что высокая корреляция не гарантирует наличия реальной линейной зависимости, а также не учитывает возможные выбросы, нелинейные тренды или смещения в распределении. Поэтому я не ограничилась числами — для всех пар признаков с коэффициентом корреляции выше 0.5 я построила диаграммы рассеяния (scatter plots).

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

Такую же отчетливую зависимость мы можем наблюдать между весом и индексом массы тела человека (BMI), потому что BMI вычисляется как вес, деленный на квадрат роста. Поскольку рост в выборке варьируется меньше, чем вес, основной вклад в изменение BMI вносит именно масса тела.

Отрицательная корреляция между количеством сожженых калорий и процентом жира человека тоже согласуется с ожиданиями: регулярные тренировки способствуют снижению жировой массы, особенно в сочетании с контролем питания. Однако важно помнить: корреляция не означает причинно-следственную связь — возможно, люди с уже низким % жира просто чаще и интенсивнее тренируются.

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

Особый интерес вызывает распределение на графике зависимости длительности тренировки от процента жира: точки словно формируют две обособленные группы. Чтобы понять, что стоит за этим паттерном, я разделила участников на три категории по уровню жировой массы — низкий, средний и высокий — и построила точечную диаграмму с расслоением (strip plot) для более детального сравнения.

data['Fat_Group'] = pd.cut(data['Fat_Percentage'], bins=[0, 15, 25, 100], labels=['Низкий', 'Норма', 'Высокий']) plt.figure(figsize=(10, 6)) ax = plt.gca()
ax.set_facecolor('#FAFAFA') plt.gcf().set_facecolor('white') ax.grid(axis='y', linestyle='--', linewidth=0.6, color='#CCCCCC', alpha=0.5)

sns.stripplot( data=data, x='Fat_Group', y='Session_Duration', jitter=0.25, alpha=0.6, size=5,palette=['

609AC9', '

669DAD', '#567EB9'])

medians = data.groupby('Fat_Group')['Session_Duration'].median() for i, (group, med) in enumerate(medians.items()): plt.hlines(med, i - 0.3, i + 0.3, color='black', linestyle='--', linewidth=1.2)

plt.xlabel('Группа по % жира') plt.ylabel('Длительность тренировки (часы)') plt.title('Длительность тренировки и процент жира', fontweight='bold', fontsize=16) sns.despine() plt.tight_layout() plt.show()

Исходный размер 989x590

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

Сжигают ли женщины и мужчины калории одинаково?

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

На графике по оси X отложена длительность тренировки, по оси Y — количество сожжённых калорий. Голубым цветом обозначены мужчины, а розовым — женщины. Линии регрессии позволяют оценить среднюю эффективность (наклон линии = калории в час) и сравнить её между группами.

gender_palette = { 'Male': '#609AC9', 'Female': '#B97FB9' } line_colors = { 'Male': '#406A8D', 'Female': '#7B4B7C' }

g = sns.lmplot(data=data, x='Session_Duration', y='Calories_Burned', hue='Gender', palette=gender_palette, height=6, aspect=1.2, scatter_kws={'alpha': 0.6, 's': 50, 'edgecolor': 'gray'}, line_kws={'linewidth': 3}, legend=False )

for i, gender in enumerate(['Male', 'Female']): g.ax.get_lines()[i].set_color(line_colors[gender])

g.ax.set_facecolor('#FAFAFA') g.ax.grid(True, linestyle='--', alpha=0.3) sns.despine() g.set_axis_labels('Длительность тренировки (часы)', 'Сожжённые калории') g.fig.suptitle('Сравнение эффективности тренировок по полу', fontsize=16, fontweight='bold')

handles = [ plt.Line2D([0], [0], marker='o', color='w', markerfacecolor=gender_palette[gender], markersize=8, markeredgecolor='gray', linestyle='None', label='Мужчины' if gender == 'Male' else 'Женщины') for gender in ['Male', 'Female'] ] g.ax.legend( handles=handles, title='Пол', loc='lower right', frameon=True, facecolor='#FAFAFA', framealpha=0.95 )

plt.tight_layout() plt.show()

Исходный размер 709x592

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

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

Насколько % жира зависит от уровня спортивной подготовки для разных полов?

Чтобы понять, как уровень спортивной подготовки влияет на состав тела, я исследую распределение процента жира отдельно для мужчин и женщин на разных этапах фитнес-пути: от новичков (уровень 1) до опытных спортсменов (уровень 3).

Для визуализации я выбрала точечные диаграммы с наложением кривых плотности (strip plots с KDE), потому что они позволяют сравнивать формы распределений, а не только средние значения, кривая плотности (она же KDE) показывает, где сосредоточена основная масса данных (аналог гистограммы, но без зависимости от числа корзин). Это особенно важно, когда группы имеют разный размер — плотность нормирована на единицу площади, поэтому сравнение остаётся корректным.

Такой подход помогает увидеть не только средний сдвиг (% жира снижается с опытом), но и изменение разброса и формы распределения — например, становится ли состав тела более однородным у продвинутых атлетов.

levels = [1, 2, 3] gender_colors_fill = {'Male': '

609AC9', 'Female': '

B97FB9'} gender_colors_kde = {'Male': '

406A8D', 'Female': '

7B4B7C'}

fig, axes = plt.subplots(1, 3, figsize=(12, 5), sharex=True, sharey=True) fig.suptitle('Распределение процента жира по уровню подготовки', fontsize=16, fontweight='bold')

for i, level in enumerate(levels): ax = axes[i] data_level = data[data['Experience_Level'] == level]

# Гистограмма в шкале плотности
for gender in ['Male', 'Female']:
    subset = data_level[data_level['Gender'] == gender]['Fat_Percentage']
    sns.histplot(subset,bins=15, stat='density', alpha=0.6, color=gender_colors_fill[gender], kde=False,ax=ax)

# 2. Добавляем кривые KDE
for gender in ['Male', 'Female']:
    subset = data_level[data_level['Gender'] == gender]['Fat_Percentage']
    sns.kdeplot(subset, color=gender_colors_kde[gender], linewidth=2.5, ax=ax)

ax.set_title(f'Уровень подготовки: {level}')
ax.set_facecolor('#FAFAFA')
ax.grid(axis='y', linestyle='--', alpha=0.4)
sns.despine(ax=ax)
if i == 0:
    ax.set_ylabel('Относительная частота')
else:
    ax.set_ylabel('')

fig.text(0.5, 0.02, 'Процент жира (%)', ha='center', fontsize=12)

handles = [ plt.Rectangle((0, 0), 1, 1, color=gender_colors_fill['Male'], alpha=0.6), plt.Rectangle((0, 0), 1, 1, color=gender_colors_fill['Female'], alpha=0.6) ] fig.legend(handles, ['Мужчины', 'Женщины'], title='Пол', loc='lower left', bbox_to_anchor=(0.7, 0.02), ncol=2, shadow=True)

plt.tight_layout(rect=[0.02, 0.12, 0.98, 0.92]) plt.show()

Исходный размер 1142x504

Любопытно, что между первым и вторым уровнями спортивной подготовки практически не наблюдается значимых различий в распределении процента жира. Существенное снижение жировой массы проявляется лишь на третьем (экспертном) уровне, что может указывать либо на нелинейный характер прогресса, либо на особенности критериев, использованных при классификации уровней в исходном датасете (к сожалению, методология формирования этих групп не раскрыта).

Как и предполагалось на основании физиологических различий, распределение процента жира у мужчин смещено влево по сравнению с женщинами. Это согласуется с биологическими нормами: у мужчин базовый уровень жировой массы ниже, поскольку значительная часть энергетических ресурсов направляется на поддержание мышечной ткани, тогда как у женщин жир играет важную роль в гормональной регуляции и репродуктивной функции.

Какой тип тренировок самый эффективный для сжигания жира?

Одна из главных целей фитнес-тренировок — снижение жировой массы. Чтобы оценить эффективность разных видов нагрузки, я рассчитала среднее количество калорий, сжигаемых за час (Calories_Burned / Session_Duration) для каждого типа тренировки и визуализировала результаты в виде горизонтальной столбчатой диаграммы (barh). Этот тип графика позволяет легко сравнивать значения между категориями и сразу видеть лидера по эффективности.

Попробуем еще поизучать различия в типах тренировок: для этого я построила четыре графика boxplot (так называемые «ящики с усами») по ключевым метрикам: сожжённые калории, средняя ЧСС (частота сердечных сокращений, интенсивность), длительность сессии, эффективность (ккал/час).

Boxplot’ы позволяют увидеть не только средние значения, но и полное распределение данных: разброс, наличие выбросов, асимметрию. Это особенно важно, когда средние могут вводить в заблуждение — например, из-за небольшого числа аномально длинных йога-сессий.

efficiency = data.groupby('Workout_Type')['Calories_Per_Hour'].mean().sort_values()

color_map = { 'Cardio': '#91B7D6', 'Strength': '#609AC9', 'Yoga': '#567EB9', 'HIIT': '#669DAD' }

colors = [color_map[w] for w in efficiency.index]

plt.figure(figsize=(8, 4)) bars = plt.barh(efficiency.index, efficiency.values, color=colors)

for i, (workout, value) in enumerate(efficiency.items()): plt.text(value + 10, i, f'{value:.0f} кал/ч', va='center', fontsize=11, color='#333333')

plt.xlabel('Среднее количество калорий в час') plt.title('Эффективность тренировок по сжиганию калорий', fontweight='bold', fontsize=16) sns.despine(left=True)
plt.tight_layout() plt.show()

Исходный размер 789x390

color_map = { 'Cardio': '#91B7D6', 'Strength': '#609AC9', 'Yoga': '#567EB9', 'HIIT': '#669DAD' } metrics = ['Water_Intake', 'Avg_BPM', 'Session_Duration', 'Calories_Per_Hour'] titles = [ 'Потребление воды (л/день)', 'Средняя ЧСС (уд/мин)', 'Длительность тренировки (ч)', 'Эффективность тренировок (кал/ч)' ]

fig, axes = plt.subplots(2, 2, figsize=(10, 7)) axes = axes.flatten() fig.suptitle('Влияние типа тренировки на основные показатели', fontsize=16, fontweight='bold')

for i, (metric, title) in enumerate(zip(metrics, titles)): ax = axes[i] sns.boxplot(data=data, x='Workout_Type', y=metric, ax=ax, palette=color_map, width=0.6, linewidth=1.2) ax.set_title(title, fontsize=13, fontweight='bold', pad=12) ax.set_xlabel('') ax.set_ylabel('') ax.set_facecolor('#FAFAFA') ax.grid(True, linestyle='--', linewidth=0.5, alpha=0.4)

fig.text(0.5, 0.02, 'Тип тренировки', ha='center', fontsize=12) fig.text(0.02, 0.5, 'Значение показателя', va='center', rotation='vertical', fontsize=12)

plt.tight_layout(rect=[0.03, 0.03, 1, 1]) plt.show()

Эффективность ваших тренировок
Проект создан 17.01.2026
Мы используем файлы cookies для улучшения работы сайта НИУ ВШЭ и большего удобства его использования. Более подробную...
Показать больше