Ты просыпаешься в 3 ночи. Снова. Слышишь плач. Смотришь на часы. В голове мелькает мысль: "Какого чёрта этот ребёнок так плохо спит?" А потом ещё одна: "А может, это я что-то делаю не так?"
Знакомо? У меня было так же. Пока я не решил перестать гадать и начать считать.
Это не статья о воспитании детей. Это история о том, как превратить хаос ночных пробуждений в чистые данные, а данные - в понимание. С помощью Python, пары библиотек и нейросети, которая не спит никогда.
Зачем всё это?
Потому что человеческая память - лгунья. Она помнит только экстремумы: "вчера спал отлично" или "сегодня не спал вообще". А реальность - это 30 ночей подряд с разной продолжительностью сна, разным количеством пробуждений, разными причинами плача.
Когда я начал записывать данные о сне своего ребёнка, я понял две вещи:
- Мои ощущения не совпадали с реальностью
- В данных были закономерности, которые я не замечал
Важный момент: мы говорим не о медицинской диагностике. Это личная аналитика. Если у ребёнка реальные проблемы со сном - к врачу, а не к Python.
Что нам понадобится
Ничего экзотического:
- Python 3.11+ (да, я знаю про 3.12, но на 3.11 всё стабильнее работает)
- Pandas 2.2+ (последняя стабильная версия на февраль 2026 года)
- Matplotlib и Seaborn для визуализации
- Jupyter Notebook или обычный скрипт - как удобнее
- Доступ к DeepSeek-V3.2 через API или локально
1 Собираем данные: проще, чем кажется
Я начал с простой Google Таблицы. Столбцы:
- Дата
- Время укладывания
- Время подъёма
- Количество пробуждений за ночь
- Причина пробуждения (голод, мокро, просто так)
- Общее время сна (часы)
- Примечания (что ели вечером, была ли прогулка и т.д.)
Собирал 30 дней. Да, это требует дисциплины. Но после недели это становится привычкой.
2 Готовим данные к анализу
Экспортируем таблицу в CSV и загружаем в Python:
import pandas as pd
import numpy as np
from datetime import datetime, timedelta
import matplotlib.pyplot as plt
import seaborn as sns
# Загружаем данные
sleep_data = pd.read_csv('child_sleep_data.csv', parse_dates=['date'])
# Смотрим, что получилось
print(f"Всего записей: {len(sleep_data)}")
print(f"Период: {sleep_data['date'].min().date()} - {sleep_data['date'].max().date()}")
print("\nПервые 5 строк:")
print(sleep_data.head())
# Проверяем пропуски
print("\nПропущенные значения:")
print(sleep_data.isnull().sum())
Первая проблема, с которой сталкиваешься: данные грязные. Время записано как "22:30", даты в разных форматах, в столбце "причина пробуждения" - текстовые описания вместо категорий.
Ошибка новичка: пытаться анализировать сырые данные. 80% времени уходит на очистку. Смиритесь.
Чистим:
# Преобразуем время укладывания и подъёма в datetime
sleep_data['bedtime'] = pd.to_datetime(sleep_data['date'].astype(str) + ' ' + sleep_data['bedtime'])
sleep_data['waketime'] = pd.to_datetime(sleep_data['date'].astype(str) + ' ' + sleep_data['waketime'])
# Если время подъёма раньше времени укладывания (переход через полночь)
mask = sleep_data['waketime'] < sleep_data['bedtime']
sleep_data.loc[mask, 'waketime'] += pd.Timedelta(days=1)
# Рассчитываем продолжительность сна
sleep_data['sleep_duration'] = (sleep_data['waketime'] - sleep_data['bedtime']).dt.total_seconds() / 3600
# Создаём категории для причин пробуждения
def categorize_wake_reason(text):
text = str(text).lower()
if 'голод' in text:
return 'hunger'
elif 'мокр' in text or 'писать' in text:
return 'wet'
elif 'зуб' in text:
return 'teething'
elif 'кошмар' in text or 'испуг' in text:
return 'nightmare'
else:
return 'unknown'
sleep_data['wake_reason_category'] = sleep_data['wake_reason'].apply(categorize_wake_reason)
# Добавляем день недели
sleep_data['weekday'] = sleep_data['date'].dt.day_name()
print("\nПосле очистки:")
print(sleep_data[['date', 'bedtime', 'waketime', 'sleep_duration', 'wake_reason_category', 'weekday']].head())
3 Базовая статистика: цифры не врут
Теперь смотрим на агрегированные показатели:
# Основные статистики
print("=== ОСНОВНЫЕ СТАТИСТИКИ ===")
print(f"Средняя продолжительность сна: {sleep_data['sleep_duration'].mean():.2f} часов")
print(f"Медианная продолжительность: {sleep_data['sleep_duration'].median():.2f} часов")
print(f"Минимум: {sleep_data['sleep_duration'].min():.2f} часов")
print(f"Максимум: {sleep_data['sleep_duration'].max():.2f} часов")
print(f"Стандартное отклонение: {sleep_data['sleep_duration'].std():.2f} часов")
print("\n=== ПРОБУЖДЕНИЯ ===")
print(f"Среднее количество пробуждений за ночь: {sleep_data['wakeups'].mean():.2f}")
print(f"Максимальное количество: {sleep_data['wakeups'].max()}")
print(f"Ночей без пробуждений: {(sleep_data['wakeups'] == 0).sum()}")
print("\n=== РАСПРЕДЕЛЕНИЕ ПРИЧИН ПРОБУЖДЕНИЙ ===")
print(sleep_data['wake_reason_category'].value_counts())
У меня получилось:
| Метрика | Значение |
|---|---|
| Средняя продолжительность сна | 9.2 часа |
| Медиана | 9.5 часов |
| Разброс (мин-макс) | 6.5-11 часов |
| Средние пробуждения за ночь | 2.3 раза |
| Самая частая причина | Голод (48%) |
Первое открытие: ребёнок спит в среднем 9.2 часа, а не "всю ночь", как мне казалось. Разброс от 6.5 до 11 часов - огромный. Значит, есть факторы, которые влияют.
4 Визуализация: когда графики говорят больше слов
Цифры - это скучно. Графики - нет.
# Настраиваем стиль графиков
plt.style.use('seaborn-v0_8-darkgrid')
sns.set_palette("husl")
# Создаём фигуру с несколькими графиками
fig, axes = plt.subplots(2, 2, figsize=(15, 10))
# 1. Тренд продолжительности сна по дням
axes[0, 0].plot(sleep_data['date'], sleep_data['sleep_duration'], marker='o', linewidth=2)
axes[0, 0].axhline(y=sleep_data['sleep_duration'].mean(), color='r', linestyle='--', alpha=0.5, label=f'Среднее: {sleep_data["sleep_duration"].mean():.1f}ч')
axes[0, 0].set_title('Продолжительность сна по дням', fontsize=14, fontweight='bold')
axes[0, 0].set_xlabel('Дата')
axes[0, 0].set_ylabel('Часы сна')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)
# 2. Распределение продолжительности сна
axes[0, 1].hist(sleep_data['sleep_duration'], bins=10, edgecolor='black', alpha=0.7)
axes[0, 1].axvline(x=sleep_data['sleep_duration'].mean(), color='r', linestyle='--', linewidth=2, label=f'Среднее: {sleep_data["sleep_duration"].mean():.1f}ч')
axes[0, 1].set_title('Распределение продолжительности сна', fontsize=14, fontweight='bold')
axes[0, 1].set_xlabel('Часы сна')
axes[0, 1].set_ylabel('Количество ночей')
axes[0, 1].legend()
# 3. Пробуждения по дням недели
weekday_order = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']
weekday_data = sleep_data.groupby('weekday')['wakeups'].mean().reindex(weekday_order)
axes[1, 0].bar(weekday_order, weekday_data, color='skyblue', edgecolor='black')
axes[1, 0].set_title('Среднее количество пробуждений по дням недели', fontsize=14, fontweight='bold')
axes[1, 0].set_xlabel('День недели')
axes[1, 0].set_ylabel('Средние пробуждения')
axes[1, 0].tick_params(axis='x', rotation=45)
# 4. Причины пробуждений
wake_reason_counts = sleep_data['wake_reason_category'].value_counts()
axes[1, 1].pie(wake_reason_counts.values, labels=wake_reason_counts.index, autopct='%1.1f%%', startangle=90)
axes[1, 1].set_title('Распределение причин пробуждений', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.savefig('sleep_analysis.png', dpi=300, bbox_inches='tight')
plt.show()
Графики показали то, что я не замечал:
- В воскресенье ребёнок просыпается в среднем на 1.5 раза чаще. Почему? Возможно, потому что в субботу мы нарушаем режим.
- Есть явные "выбросы" - ночи с 6.5 часами сна. Все они приходятся на дни, когда были гости или мы поздно вернулись с прогулки.
- 48% пробуждений - из-за голода. Может, стоит увеличить вечернюю порцию?
5 Корреляционный анализ: ищем связи
А что если посмотреть, как связаны разные факторы? Например, время укладывания и продолжительность сна?
# Преобразуем время укладывания в числовой формат (часы после 18:00)
sleep_data['bedtime_hour'] = sleep_data['bedtime'].dt.hour + sleep_data['bedtime'].dt.minute / 60
# Считаем корреляцию
correlation = sleep_data[['sleep_duration', 'bedtime_hour', 'wakeups']].corr()
print("Матрица корреляции:")
print(correlation)
# Визуализируем корреляцию
plt.figure(figsize=(8, 6))
sns.heatmap(correlation, annot=True, cmap='coolwarm', center=0, square=True,
linewidths=1, cbar_kws={"shrink": .8}, fmt=".2f")
plt.title('Корреляция между параметрами сна', fontsize=14, fontweight='bold')
plt.tight_layout()
plt.show()
Результат меня удивил: корреляция между временем укладывания и продолжительностью сна составила всего -0.15. То есть позже уложился - не значит меньше поспал. А вот корреляция между количеством пробуждений и общей продолжительностью сна была -0.42. Чем чаще просыпается - тем меньше общее время сна. Логично, но теперь есть цифры.
6 Подключаем DeepSeek-V3.2: нейросеть как аналитик
Здесь начинается магия. Я взял DeepSeek-V3.2 - не потому что это модно, а потому что он бесплатный, работает локально и отлично справляется с анализом структурированных данных.
Сначала подготовил данные для нейросети:
# Создаём сводный отчёт для DeepSeek
summary_report = f"""
АНАЛИЗ ДАННЫХ О СНЕ РЕБЁНКА
Период: {sleep_data['date'].min().date()} - {sleep_data['date'].max().date()}
Всего ночей: {len(sleep_data)}
ОСНОВНЫЕ МЕТРИКИ:
- Средняя продолжительность сна: {sleep_data['sleep_duration'].mean():.2f} часов
- Медианная продолжительность: {sleep_data['sleep_duration'].median():.2f} часов
- Среднее количество пробуждений за ночь: {sleep_data['wakeups'].mean():.2f}
- Ночей без пробуждений: {(sleep_data['wakeups'] == 0).sum()} из {len(sleep_data)}
РАСПРЕДЕЛЕНИЕ ПРИЧИН ПРОБУЖДЕНИЙ:
"""
for reason, count in sleep_data['wake_reason_category'].value_counts().items():
percentage = (count / len(sleep_data)) * 100
summary_report += f"- {reason}: {count} ночей ({percentage:.1f}%)\n"
summary_report += f"""
АНАЛИЗ ПО ДНЯМ НЕДЕЛИ:
"""
for day in weekday_order:
if day in sleep_data['weekday'].values:
day_data = sleep_data[sleep_data['weekday'] == day]
avg_sleep = day_data['sleep_duration'].mean()
avg_wakeups = day_data['wakeups'].mean()
summary_report += f"- {day}: {avg_sleep:.1f}ч сна, {avg_wakeups:.1f} пробуждений\n"
summary_report += f"""
КОРРЕЛЯЦИИ:
- Время укладывания vs Продолжительность сна: {correlation.loc['bedtime_hour', 'sleep_duration']:.2f}
- Пробуждения vs Продолжительность сна: {correlation.loc['wakeups', 'sleep_duration']:.2f}
ВЫБРОСЫ (аномальные значения):
"""
# Находим аномалии (более 1.5 межквартильных размахов от медианы)
q1 = sleep_data['sleep_duration'].quantile(0.25)
q3 = sleep_data['sleep_duration'].quantile(0.75)
iqr = q3 - q1
lower_bound = q1 - 1.5 * iqr
upper_bound = q3 + 1.5 * iqr
outliers = sleep_data[(sleep_data['sleep_duration'] < lower_bound) | (sleep_data['sleep_duration'] > upper_bound)]
for _, row in outliers.iterrows():
summary_report += f"- {row['date'].date()}: {row['sleep_duration']:.1f}ч сна ({'ниже' if row['sleep_duration'] < lower_bound else 'выше'} нормы)\n"
print(summary_report)
Теперь отправляем этот отчёт в DeepSeek с промптом:
prompt = f"""
Ты - эксперт по анализу данных и детскому сну.
Проанализируй следующие данные о сне ребёнка и дай практические рекомендации.
{summary_report}
Вопросы для анализа:
1. Какие закономерности ты видишь в данных?
2. Какие дни недели наиболее проблемные и почему?
3. Какие практические шаги можно предпринять для улучшения сна?
4. Есть ли связь между временем укладывания и качеством сна?
5. На что стоит обратить особое внимание?
Ответь структурированно, с конкретными рекомендациями.
"""
# Здесь код для вызова DeepSeek API
# В реальности используй свою реализацию
print("Отправляю запрос в DeepSeek-V3.2...")
# response = deepseek_chat(prompt)
# print(response)
Что я получил от DeepSeek (сокращённая версия):
1. ЗАКОНОМЕРНОСТИ: Сон наиболее стабилен со вторника по четверг. Воскресенье - худший день (на 1.5 пробуждения больше среднего). 48% пробуждений из-за голода - это много для возраста 1.5 года.
2. ПРАКТИЧЕСКИЕ РЕКОМЕНДАЦИИ: Увеличить вечернюю порцию еды. Соблюдать режим в выходные. Ввести ритуал отхода ко сну (чтение, спокойная музыка).
3. ВРЕМЯ УКЛАДЫВАНИЯ: Слабая корреляция (-0.15) говорит, что важнее не когда укладываешь, а как. Консистентность важнее точного времени.
Что это дало на практике
Через месяц после внедрения рекомендаций:
- Средняя продолжительность сна выросла с 9.2 до 9.8 часов
- Пробуждения из-за голода сократились с 48% до 22%
- Воскресенье перестало быть адским днём
Но главное - я перестал гадать. Теперь у меня есть данные. И когда бабушка говорит "он плохо спит потому что...", я могу показать график и сказать: "Нет, вот статистика за 60 дней, и она говорит другое".
Ошибки, которые я совершил (чтобы вы их не повторили)
Ошибка 1: Записывал слишком много данных. Первую неделю я фиксировал каждое вздох. Потом понял, что 80% этих данных бесполезны. Сейчас записываю только ключевые метрики.
Ошибка 2: Пытался анализировать данные в реальном времени. Бесполезно. Нужно набрать минимум 30 точек, иначе это просто шум.
Ошибка 3: Доверял своей памяти. "Вчера спал хорошо" оказалось 7.5 часов при среднем 9.2. Память врёт. Данные - нет.
Можно ли автоматизировать сбор данных?
Можно, но не нужно. Я пробовал:
- Умные часы для детей - данные неточные, ребёнок их снимает
- Детские мониторы с анализом сна - дорого, а точность сомнительная
- Приложения для трекинга - удобно, но экспорт данных часто платный
В итоге вернулся к Google Таблице на телефоне. Открыл, тапнул три раза - записал. 10 секунд перед сном.
Если хотите автоматизировать - посмотрите в сторону DeepEyesV2 для анализа видео с камеры или создайте простой телеграм-бот.
Что дальше?
Сейчас экспериментирую с предиктивным анализом. Обучаю простую модель предсказывать, как ребёнок будет спать сегодня, исходя из:
- Продолжительности дневного сна
- Активности днём
- Что ел на ужин
- Погоды (да, оказалось влияет)
Пока точность около 65%, но это лучше, чем гадание на кофейной гуще.
Если интересно - могу сделать продолжение про машинное обучение на данных о сне. Пишите в комментариях.
Самый главный инсайт за два месяца анализа: ребёнок - не машина. Данные помогают найти закономерности, но не заменяют интуицию. Иногда он плохо спит просто потому что режутся зубы. И это нормально.
Но когда ты видишь на графике, что после дней с длительной прогулкой сон на 45 минут дольше - это меняет поведение. Ты начинаешь гулять больше не потому что "так надо", а потому что видишь цифры.
Данные не сделают ребёнка идеально спящим. Но они сделают тебя менее тревожным родителем. А это, пожалуй, даже важнее.