Использую NumPy для анализа своих ежедневных привычек (сон, экранное время и настроение)

Автор: Дмитрий Иванов [Команда P9X]

~8 минут чтения

Небольшой проект с использованием NumPy

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

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

Давайте рассмотрим процесс шаг за шагом.

Шаг 1 — Загрузка и понимание данных

Я начал с создания простого массива NumPy, который содержал 30 строк (по одной на каждый день) и шесть столбцов — каждый столбец представлял отдельный показатель привычки. Затем я сохранил его в виде файла .npy, чтобы потом можно было легко загрузить.

import numpy as np
data = np.load('activity_data.npy')

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

data.shape
data.ndim

ВЫВОД: 30 строк, 6 столбцов, ndim=2

Я также распечатал первые несколько строк, чтобы визуально убедиться, что каждое значение выглядит нормально — например, что часы сна не были отрицательными или что значения настроения находились в разумном диапазоне.

data[:5]

ВЫВОД:

array([[ 1. , 6.5, 5. , 4.2, 20. , 6. ],
[ 2. , 7.2, 6. , 3.1, 35. , 7. ],
[ 3. , 5.8, 4. , 5.5, 0. , 5. ],
[ 4. , 8. , 7. , 2.5, 30. , 8. ],
[ 5. , 6. , 5. , 4.8, 10. , 6. ]])

Шаг 2 — Валидация данных

Прежде чем приступать к анализу, я хотел убедиться, что данные имеют смысл. Это то, что мы часто пропускаем, работая с вымышленными данными, но это всё равно хорошая практика.

Поэтому я проверил:

  • Нет отрицательных часов сна
  • Нет оценок настроения ниже 1 или выше 10

Для сна это означало выбор столбца сна (индекс 1 в моём массиве) и проверку, были ли какие-либо значения ниже нуля.

data[:, 1] < 0

ВЫВОД:

array([False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False, False, False, False, False, False, False,
False, False, False])

Это означает отсутствие отрицательных значений. Затем я сделал то же самое для настроения. Я подсчитал, что столбец настроения был под индексом 5, и проверил, были ли какие-либо значения ниже 1 или выше 10.

data[:, 5] < 1
data[:, 5] > 10

МЫ ПОЛУЧИЛИ ТОТ ЖЕ ВЫВОД.

Всё выглядело хорошо, так что мы могли двигаться дальше.

Шаг 3 — Разделение данных на недели

У меня было 30 дней данных, и я хотел анализировать их по неделям. Первый инстинкт — использовать функцию split() NumPy, но это не удалось, потому что 30 не делится на 4 без остатка. Поэтому вместо этого я использовал np.array_split(), который допускает неравномерные разбиения.

Это дало мне:

  • Неделя 1 → 8 дней
  • Неделя 2 → 8 дней
  • Неделя 3 → 7 дней
  • Неделя 4 → 7 дней
weekly_data = np.array_split(data, 4)
weekly_data

ВЫВОД:

[array([[ 1. , 6.5, 5. , 4.2, 20. , 6. ],
[ 2. , 7.2, 6. , 3.1, 35. , 7. ],
[ 3. , 5.8, 4. , 5.5, 0. , 5. ],
[ 4. , 8. , 7. , 2.5, 30. , 8. ],
[ 5. , 6. , 5. , 4.8, 10. , 6. ],
[ 6. , 7.5, 6. , 3.3, 25. , 7. ],
[ 7. , 8.2, 3. , 6.1, 40. , 7. ],
[ 8. , 6.3, 4. , 5. , 15. , 6. ]]),

array([[ 9. , 7. , 6. , 3.2, 30. , 7. ],
[10. , 5.5, 3. , 6.8, 0. , 5. ],
[11. , 7.8, 7. , 2.9, 25. , 8. ],
[12. , 6.1, 5. , 4.5, 15. , 6. ],
[13. , 7.4, 6. , 3.7, 30. , 7. ],
[14. , 8.1, 2. , 6.5, 50. , 7. ],
[15. , 6.6, 5. , 4.1, 20. , 6. ],
[16. , 7.3, 6. , 3.4, 35. , 7. ]]),

array([[17. , 5.9, 4. , 5.6, 5. , 5. ],
[18. , 8.3, 7. , 2.6, 30. , 8. ],
[19. , 6.2, 5. , 4.3, 10. , 6. ],
[20. , 7.6, 6. , 3.1, 25. , 7. ],
[21. , 8.4, 3. , 6.3, 40. , 7. ],
[22. , 6.4, 4. , 5.1, 15. , 6. ],
[23. , 7.1, 6. , 3.3, 30. , 7. ]]),

array([[24. , 5.7, 3. , 6.7, 0. , 5. ],
[25. , 7.9, 7. , 2.8, 25. , 8. ],
[26. , 6.2, 5. , 4.4, 15. , 6. ],
[27. , 7.5, 6. , 3.5, 30. , 7. ],
[28. , 8. , 2. , 6.4, 50. , 7. ],
[29. , 6.5, 5. , 4.2, 20. , 6. ],
[30. , 7.4, 6. , 3.6, 35. , 7. ]])]

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

Шаг 4 — Расчёт еженедельных показателей

Я хотел понять, как каждая привычка менялась от недели к неделе. Поэтому я сосредоточился на четырёх основных вещах:

  • Среднее количество часов сна
  • Среднее количество учебных часов
  • Среднее время, проведённое за экраном
  • Средний балл настроения

Я сохранил массив каждой недели в отдельной переменной, затем использовал np.mean(), чтобы вычислить средние значения для каждого показателя.

Средние часы сна

week_1 = weekly_data[0]
week_2 = weekly_data[1]
week_3 = weekly_data[2]
week_4 = weekly_data[3]

week1_avg_sleep = np.mean(week_1[:, 1])
week2_avg_sleep = np.mean(week_2[:, 1])
week3_avg_sleep = np.mean(week_3[:, 1])
week4_avg_sleep = np.mean(week_4[:, 1])

Средние учебные часы

week1_avg_study = np.mean(week_1[:, 2])
week2_avg_study = np.mean(week_2[:, 2])
week3_avg_study = np.mean(week_3[:, 2])
week4_avg_study = np.mean(week_4[:, 2])

Среднее время, проведённое за экраном

week1_avg_screen = np.mean(week_1[:, 3])
week2_avg_screen = np.mean(week_2[:, 3])
week3_avg_screen = np.mean(week_3[:, 3])
week4_avg_screen = np.mean(week_4[:, 3])

Средний балл настроения

week1_avg_mood = np.mean(week_1[:, 5])
week2_avg_mood = np.mean(week_2[:, 5])
week3_avg_mood = np.mean(week_3[:, 5])
week4_avg_mood = np.mean(week_4[:, 5])

Затем, чтобы всё было удобнее для чтения, я красиво оформил результаты.

print(f"Неделя 1 — Среднее количество часов сна: {week1_avg_sleep:.2f} часов, Учёба: {week1_avg_study:.2f} часов, "
f"Время за экраном: {week1_avg_screen:.2f} часов, Балл настроения: {week1_avg_mood:.2f}")

print(f"Неделя 2 — Среднее количество часов сна: {week2_avg_sleep:.2f} часов, Учёба: {week2_avg_study:.2f} часов, "
f"Время за экраном: {week2_avg_screen:.2f} часов, Балл настроения: {week2_avg_mood:.2f}")

print(f"Неделя 3 — Среднее количество часов сна: {week3_avg_sleep:.2f} часов, Учёба: {week3_avg_study:.2f} часов, "
f"Время за экраном: {week3_avg_screen:.2f} часов, Балл настроения: {week3_avg_mood:.2f}")

print(f"Неделя 4 — Среднее количество часов сна: {week4_avg_sleep:.2f} часов, Учёба: {week4_avg_study:.2f} часов, "
f"Время за экраном: {week4_avg_screen:.2f} часов, Балл настроения: {week4_avg_mood:.2f}")

ВЫВОД:

Неделя 1  Среднее количество часов сна: 6.94 часов, Учёба: 5.00 часов, Время за экраном: 4.31 часов, Балл настроения: 6.50
Неделя 2  Среднее количество часов сна: 6.97 часов, Учёба: 5.00 часов, Время за экраном: 4.39 часов, Балл настроения: 6.62
Неделя 3  Среднее количество часов сна: 7.13 часов, Учёба: 5.00 часов, Время за экраном: 4.33 часов, Балл настроения: 6.57
Неделя 4  Среднее количество часов сна: 7.03 часов, Учёба: 4.86 часов, Время за экраном: 4.51 часов, Балл настроения: 6.57

Шаг 5 — Понимание результатов

После того как я распечатал числа, некоторые закономерности начали проявляться.

Мои часы сна были довольно стабильными в течение первых двух недель (около 6,9 часов), но на третьей неделе они подскочили примерно до 7,1 часа. Это означает, что я «спал лучше» по мере того, как месяц шёл. К четвёртой неделе оно оставалось примерно на уровне 7,0 часов.

Для учебных часов всё было наоборот. В первую и вторую неделю среднее количество часов составляло около 5 часов в день, но к четвёртой неделе оно снизилось примерно до 4 часов.

Затем появилось время, проведённое за экраном. Оно немного огорчило. В первую неделю оно составляло примерно 4,3 часа в день, и каждую неделю оно только увеличивалось. Классический цикл продуктивной работы на раннем этапе, а затем постепенный переход к «прокручиванию» позже в месяце.

Наконец, было настроение. Мой балл настроения начинался примерно с 6,5 в первую неделю, немного повысился до 6,6 во вторую неделю и затем как бы колебался там до конца периода. Он не менялся резко, но было интересно увидеть небольшой всплеск во вторую неделю — прямо перед тем, как мои учебные часы снизились, а время, проведённое за экраном, увеличилось.

Шаг 6 — Поиск закономерностей

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

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

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

Шаг 7 — Подведение итогов и следующие шаги

В этом небольшом проекте я узнал несколько ключевых вещей — как о NumPy, так и о структурировании анализа.

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

Это тот вид небольшого проекта, который напоминает вам, что анализ данных не всегда должен быть сложным. Иногда это просто вопрос постановки простых вопросов, таких как «Как меняется моё время, проведённое за экраном, с течением времени?» или «Когда я чувствую себя лучше всего?».

Если я захочу пойти дальше (что, вероятно, сделаю), есть так много направлений, в которых можно двигаться:

  • Найти лучшие и худшие дни в целом
  • Сравнить будние дни и выходные
  • Или даже создать простой «индекс благополучия», основанный на нескольких привычках вместе взятых

Но это, вероятно, будет в следующей части серии.

На данный момент я доволен тем, что смог применить NumPy к чему-то, что кажется реальным и понятным — не просто абстрактным массивам и числам, а привычкам и эмоциям. Это тот вид обучения, который запоминается.

Спасибо за чтение.