Анализируем посещения фитнес-клуба
Краткий рассказ о том, как я решил собрать метрики своих тренировок.
Вступление
Недавно я установил приложение своего фитнес клуба. Приметил для себя там раздел с историей посещений. Там была дата и продолжительность всех моих тренировок за последние полтора года.
«А из всего это получатся крутые графики»
В то же время я проходил курс по анализу данных. И не долго думая, я решил собрать статистику по этим визитам.
Добываем данные
Я надеялся обойтись без использования мобильного приложения. Зашел на сайт фитнес клуба и обнаружил аналогичную страницу со статистикой. Страница посещений рендерилась напрямую с сервера. Никакое API там не использовалось, а мне совсем не хотелось вытягивать данные из HTML.
У меня был уже опыт сниффинга мобильных приложений через Charles. Он уже был настроен у меня на компьютере. О том, как это сделать есть достаточно информации в интернете. В будущем возможно и сам об этом напишу. Включил в телефоне прокси, открыл историю посещений в приложении, и вот оно.
Метод API на получение истории посещений. Авторизация производится через private-key в заголовке. В теле запроса только два параметра. Один передает начальную, а другой конечную дату для поиска. Никаких лимитов я не обнаружил. И вытащил всю историю посещений одним запросом. Посещений набралось аж 163.
Очищаем данные
Объекты посещения содержали много ненужной для меня информации. Меня интересовали только поля с датой и продолжительностью. Пришло время использовать python. С помощью генератора списков я убрал все лишнее. И сохранил в новый массив filtered.
filtered = [{'dt': v['visitTime'], 'duration': v['visitDuration']} for v in visits]
Встроенные списки неудобно анализировать. Для этого лучше подходят датафреймы из библиотеки pandas. Я преобразовал массив в него, и сохранил в .csv файл для дальнейшего использования.
import pandas as pd
df = pd.DataFrame.from_dict(filtered, orient='columns')
df.to_csv('visits.csv')
Вызвал метод df.info() и получил информацию о своем фрейме.
Одинаковое количество значений, пропущенных данных нет. Проверил на дубликаты по дате и времени посещения через df.duplicated(). Их тоже не нашлось.
Теперь мне предстояло проверить данные на наличие outliers. Хорошего русского перевода у этого термина нет. Он означает обособленно стоящие данные. Которые могут негативно влиять на среднее значение. В моем случае они попали в таблицу из-за какой-то ошибки на стороне фитнес клуба.
Я легко заметил на гистограмме колонки с продолжительностью:
df['duration'].hist()
Кроме очевидной погрешности справа, я решил отфильтровать все значения меньше 40 минут. Эти значения тоже могли попасть в таблицу только по ошибке. Составляем запрос для фильтрации и изменяет датафрейм.
clean_df = np.logical_and(df['duration'] > 40, df['duration'] < 400)
df = df[clean_df]
Количество значений сократилось до 158.
Изменяем и дополняем данные
В самом начале я обратил внимание, что столбец даты и времени хранится в формате объекта. Для более удобного анализа перевел его в формат datetime
df['dt'] = pd.to_datetime(df['dt'])
Благодаря этому изменению я легко смог добавить новые поля в таблицу: день недели, месяц, час посещения для будущего анализа.
df['weekday'] = df['dt'].dt.dayofweek
df['month'] = df['dt'].dt.month
df['hour'] = df['dt'].dt.hour
Для большей чистоты устанавливаем дату и время, как индекс таблицы
df = df.set_index('dt')
Много полей не бывает. Добавил еще поле для выходных дней
df['holiday'] = np.array([True if weekday == 5 or weekday == 6 else False for weekday in df['weekday']])
Заканчиваем здесь очистку данных и можем приступать к самому интересному — анализу.
Анализируем данные
Начинаю с базового анализа. Применю к колонке с продолжительностью базовый статистический метод describe.
df['duration'].describe()
Из него узнаю, что средняя продолжительность тренировки 113 минут. Максимальная 243, минимальная 48. Метод отдает и другие статистические данные, но они не так интересны.
Есть еще один метод для определения самых частых значений
df.mode()
Отсюда узнает, что больше всего посещений по месяцу — в марте, по дням недели — в среду, а по часов — с 10 до 11.
Пока немного скучновато, не так ли? Давайте построим графики. Например
scatter plot с зависимостью продолжительности от дня недели.
sns.swarmplot(x=df['weekday'], y=df['duration'], scatter=True)
Уже интереснее, видим, что тренировки на выходных можно пересчитать на пальцах. А что если вместо дня недели подставить месяц?
sns.swarmplot(x=df['month'], y=df['duration'])
Очень интересный график. Заметный спад количества тренировок и их продолжительности с окончанием лета. И их увеличение с его же приближением.
Теперь давайте построим что-нибудь для диаграммы самых популярных часов посещений.
sns.swarmplot(x=df['weekday'], y=df['hour'])
Никакой час особо не выделяется. Но намного чаще у меня были тренировки в первой половине дня.
Заключение
Анализировать данные можно бесконечно. И для любого из значений можно построить много разных графиков. Я не утверждаю, что мой метод анализа данных правильный. Я лишь показываю, как средствами одного Python можно превратить разные части свой жизни в статистику и графики.
Если эта тема будет вам интересна, то продолжу раскрывать её в других постах.
Понравилась статья? Похлопайте в ладоши возле поста.
А также подписывайтесь на мой канал в телеграме.