查看原文
其他

个人生活的量化分析(二):Apple健康数据分析

林筱越 R语言中文社区 2019-04-22

点击蓝字关注这个神奇的公众号~

作者简介

林筱越:华东政法大学 社会学专业 R语言爱好者 


往期回顾:

使用ggplot2绘制心形

定量论文:探究「健康水平、婚姻状况」对幸福感的影响

个人生活的量化分析(一):时间管理


全文目录:

1. 前言

2. 数据准备

3. 数据导入

4. 数据预处理

5. 可视化部分

6. 结语



1. 前言

因为我是一个平时经常锻炼的人,因此基本上每次下载一个有关健康的app(例如Keep、悦跑圈等),我都会允许将数据导入iPhone的自带的健康app。

可能大家平时只对于健康app使用的比较少,但是它除了能提供有关健康数据的视图部分外,其实它还提供了「数据导出」的功能,这毫无疑问也为了解自己的锻炼状况提供了分析的可能。

本次使用的数据是通过iPhone导出后的健康数据,用以看看自己之前的一些锻炼状况。


2. 数据准备

进入健康app后点击右上角的用户图标:

之后进入之后点击最下面的「Export Data」,然后iPhone会将所有健康数据以一个名为「export.zip」的压缩包形式打包,接着通过iCloud或者微信传输到电脑:

得到压缩包后解压可以得到是「xml文件」,仍然不是我们需要的csv表格或xls格式,所以这时就需要进入健康数据转化的网站(http://ericwolter.com/projects/health-export.html),然后直接将解压后的xml文件拖入当中转化后便可以得到所有健康数据了:

由于篇幅有限,在导入数据之前我已经用Excel对所有csv格式的数据做了「分列」的预先处理,并删除一些无用的列,保留了基本的数据;但这并不代表数据就已经可以完全拿来使用了,因此还需要进一步进行清洗。

本次仅选取「体重记录」、「饮水量」、「卡路里消耗」、「每日步数记录」四部分数据来进行分析。


3. 数据导入

此次为大家展示一下通过与数据库交互,来导入数据将4个csv的数据文件导入进R;在此之前已经将4个文件导入MySQL:

library(RMySQL) #读取MySQL
library(tidyverse) #数据处理、可视化
# 1. 数据导入部分
## 调用MySQL
conn <- dbConnect(MySQL(), dbname='rdata',
                  username='root',
                  password='934804',
                  host='127.0.0.1',
                  port=3306)

## 读取表格
weight <- dbReadTable(conn, 'weight')
water <- dbReadTable(conn, 'water')
steps <- dbReadTable(conn, 'step_count')
calories <- dbReadTable(conn, 'calories')


•  其中conn部分最为重要:

–   dbname:为数据库中的数据库名称

–   username:一般个人的MySQL都为「root」

–   password:是自己设定的密码(也可能为空)

–   host:一般填「127.0.0.1」

–   port:端口好一般为「3306」

•  建立好与MySQL连接的端口后,就可以使用RMySQL包中的dbReadTable函数来对数据库的表进行读取,第一个参数为端口,第二个参数为表格名称

•  不熟悉MySQL的朋友可以使用read_csv来读取,读取tidyverse包后就可以使用


4. 数据预处理

4.1 保留变量

由于这四部分数据存在着数据内容上的一致性,为了统一操作,这里其存入一个list中:

# 存入list
all_data <- list(weight, water, steps, calories)

然后这时,我们用for循环来对这四个数据进行批量操作,即保留仅需要的列:

# 通过for循环保留列
keep_cols <- c('sourceName', 'creationDate', 'value')
for (i in c(1:4)) {
  all_data[[i]] <- all_data[[i]][,keep_cols]
}

•  这里系统会提示说选择了没有定义列的警告信息,这里是因为有些数据没有sourceName这一列,但实际上并不影响列的提取,可以忽略

4.2 数据重组

由于没有使用read_csv函数导入,所以这里导入的所有数据都是字符串类型;但通过观察数据可以发现,所有数据基本都是包含时间对象和一个记录值。但时间对象我们仅需要提取「日期」即可,因此这里就需要所有数据时间对象进行日期提取。

在此之前我们先简单定义一个字符串列表分隔的函数:

# 定义提取日期函数
date_split_func <- function(name) {
  date_split <- strsplit(name$creationDate, ' ')
  date_get <- sapply(date_split, '[[', 1)
  return(as.Date(date_get))
}

•  这里需要注意的就是sapply的用法:

–   第一个参数指定的是已经被strsplit函数分割的字符串列表

–   第二个参数是索引列表中的各部分(如果大家对此有疑问的话,可以查阅《R语言实战/第5章:高级数据管理》中学生成绩排名这一案例,当中就使用到了这一函数,很实用。算是一个骚操作:p)

–   第三个参数是提取时间对象的第1列(也就是日期)

接下来就是将四个数据进行筛选和重组:

# 数据筛选与重组
weight <- all_data[[1]]
weight_date <- date_split_func(weight)
weight <- weight %>%
  select(value) %>%
  cbind(weight_date)

calories <- all_data[[4]]
calories_date <- date_split_func(calories)
calories <- calories %>%
  select(value, sourceName) %>%
  cbind(calories_date)

•  这里为了方便大家阅读,就删去当中water和steps数据的重组过程,只需要将weight数据过程中的名称和索引进行替换即可。这三个数据的重组过程完全一致

•  然后calories数据与其他三个数据不同的是,多提取了sourceName一列


5. 可视化部分

5.1 体重记录

上个寒假放假的一段期间里,我每天都会早上测量自己的体重,打算看看在开学之前自己能胖多少斤:

weight %>%
  ggplot(aes(x=weight_date, y=as.numeric(value))) +
  geom_point() +
  geom_line() +
  # 添加平均线
  # 设置颜色和线条:红色虚线,
  # alpha:透明度减少50%
  geom_hline(yintercept = mean(as.numeric(weight$value)),
             color='red', linetype='dotdash', alpha=0.5)+
  labs(x='日期(天)', y='重量(kg)', title='体重记录') +
  scale_x_date(date_breaks = '3 day') + 
 
  # 在图中添加注释
  # bolditalic为斜粗体
  # parse=T时转化为数学公式样式
  annotate(geom='text', x=weight_date[4], y=68,
           label = 'paste(bolditalic(Mean), \' = 66.94(kg)\')', parse=T) +
 
  # plot.title用于调整标题
  theme_bw() +
  theme(text = element_text(family = 'STKaiti'),
        axis.text.x = element_text(angle = 45, vjust=1, hjust = 1),
        plot.title = element_text(hjust = 0.5))

•  当中一些细节调整我已给出注释,大家对照着看应该很容易理解;后面我也不再一一重复

•  为了使图形简介,我使用scale_x_date函数稍微对x轴的日期进行分割

•   对于annotate函数中的选项,这里给大家稍微详解一下:

–  x和y的坐标实际上是我个人指定图形中的空白区域部分,为了label注释部分能很好的展示

–   label部分我使用了paste来将字符串进行黏贴,当中要注意一下「\」单斜杆的用法:用于对符号进行转化,以便系统视为「文本」的一部分

–   parse=T时,label的内容会以数学公式的样式来呈现

在放假前,我的体重是63kg。从图形可以看出,一个假期我竟然一直在胖!

5.2 饮水量记录

为了贯彻每天8杯水的饮水理念(1杯水大概500ml?),我使用了一款名为「Water Reminder」的app来进行记录,就假定水杯为500ml,所以每次就喝一半就为250ml,因此就对应记录:

# 查看平均饮水量
water %>%
  group_by(water_date) %>%
  summarize(total_water = sum(as.numeric(value))) %>%
  summarize(mean_drink = mean(total_water))

# 绘制
water_plot <- water %>%
  group_by(water_date) %>%
  summarise(total_water = sum(as.numeric(value))) %>%
  ggplot(aes(x=water_date, y=total_water))+
  geom_line() +
  labs(x='日期(每3天)', y='饮水量(毫升)', title='饮水量') +
 
  # 这里的yintercept=2802根据平均饮水量来输入
  geom_hline(yintercept = 2802, color='red',
             linetype='dotdash', alpha=0.5)+
  annotate(geom='text', x=weight_date[1], y=1000,
           label = 'paste(bolditalic(Mean), \' = 2802(ml)\')', parse=T) +
  scale_x_date(date_breaks = '3 day') +
  theme_bw() +
  theme(text = element_text(family = 'STKaiti'),
        axis.text.x = element_text(angle = 45, vjust=1,hjust = 1),
        plot.title = element_text(hjust = 0.5))

从趋势可以看出,每天饮水量在不断下降(好吧,其实有时候会懒得记或者忘记记了);没想到的是,1月19号那天我竟然喝了5L的水!

不过平均来说我每天喝水量大概也接近3000ml了(查看了一下中位数与平均数差不多,这里就没有使用中位数),总的来说每天身体的水分还是相对维持在一个平衡的状态吧!(多喝水有益健康)

5.3 卡路里消耗记录

不同app的卡路里记录

成人每日消耗大约1000~1500千卡(百度的)。手机里的卡路里记录主要由日常行走和锻炼两部分组成,虽然可能会有部分重合,但是对于整体的影响并不大,还是能较为直观的反映出平日里的能量消耗。

这里我就首先看一看我在Keep和悦跑圈两个app上锻炼时候的记录:

  # 提出分组好的数据集
diff_app <- calories %>%
  group_by(sourceName) %>%
  summarize(total_calories = sum(as.numeric(value)))

  # 创建标签
calories_label <- paste(diff_app$total_calories,'Kcal')

  # 绘制
diff_app %>%
  ggplot(aes(x=sourceName, y=total_calories, fill=factor(sourceName))) +
  geom_bar(stat='identity', show.legend = F, width = 0.3) +
  labs(x='健康App',y='总消耗卡路里(Kcal)',title='不同app的卡路里记录') +
 
  # 将标签映射到数据上
  geom_text(aes(label=calories_label), vjust = -0.2) +
  theme_bw() +
  theme(text = element_text(family='STKaiti'),
        panel.grid.major.x = element_blank(),
        plot.title = element_text(hjust = 0.5))

•  悦跑圈功能相对简单,仅作为跑步使用,消耗了3505千卡

•  Keep既提供锻炼健身动作的功能,也提供了跑步的功能,因此自己经常性使用;到目前为止也已经消耗了大约11142千卡!

2018年的卡路里记录

数据里包含了从2017年到至今的数据(期间还原过手机几次,所以更早的记录就丢失了),但这里仅选取2018年的数据:

  # 建立上年记录的索引
  # 提取本年度的记录
last_year <-seq.Date(from = as.Date('2017-01-01'),
                     to = as.Date('2017-12-31'),
                     by = 'day')
drop_index <- calories$calories_date %in% last_year
calories <- calories[which(!drop_index),]

  # 查看中位数
median(as.numeric(calories$value))

  # 绘制部分
calories %>%
  group_by(calories_date) %>%
  summarise(total_calories = sum(as.numeric(value))) %>%
  ggplot(aes(x=calories_date, y=total_calories)) +
  geom_point() +
  geom_line(alpha = 0.5) +
  geom_hline(yintercept = 83, linetype='dotdash',
             color='red', alpha=0.5) +
  labs(x='日期(月)',y='总卡路里(Kcal)', title='卡路里消耗图') +
  scale_x_date(date_breaks = 'week') +
  annotate(geom='text', x=calories$calories_date[15], y=300,
           label = 'paste(bolditalic(Median),\' = 83(Kcal)\')', parse = T) +
  theme_bw() +
  theme(text = element_text(family = 'STKaiti'),
        axis.text.x = element_text(angle = 45, vjust = 1, hjust =1),
        plot.title = element_text(hjust = 0.5))

•  这里的83千卡其实并不准确,因为这仅是手机记录的运动时消耗的能量;还缺少日常行为所消耗的能量。

•  同时,为了避免受极端值的影响,我使用了中位数来进行衡量。

可以看到的,今年是平时活动时消耗的卡路里大约是83Kcal,主要是因为今年处于备考状态,所以在锻炼上所分配的精力就少了,这也就是为什么导致记录的数据不变偏低的原因。

5.4 每日步数记录

在大一大二喜欢跑步的时候,经常会沉迷于微信运动的排行榜,不过之后就没有再关注并且关闭了微信运动(因为点赞什么的太烦)。不过每日步数的记录,也能侧面反映出一个人每日活动的状况吧:

  # 汇总数据
group_steps <- steps%>%
  group_by(steps_date) %>%
  summarize(total_steps = sum(as.numeric(value)))
  # 查看均值
mean_steps <- mean(group_steps$total_steps)

  # 绘制部分
steps_plot <- group_steps %>%
  ggplot(aes(x=steps_date, y=total_steps)) +
  geom_line() +
  labs(x='日期(周)', y='每日总步数', title='行走步数') +
  scale_x_date(date_breaks='week') +
  geom_hline(yintercept = mean_steps, linetype='dotdash',
             color='red', alpha=0.5) +
  annotate(geom='text', x=group_steps$steps_date[120], y=18000,
           label = 'paste(bolditalic(Mean),\' = 7947.88(steps)\')',
           parse = T) +
  theme_bw() +
  theme(text = element_text(family = 'STKaiti'),
        axis.text.x = element_text(angle=45, vjust=1, hjust=1),
        plot.title = element_text(hjust = 0.5))

•  从图形可以看出,基本上2017年下半年,因为课程安排的还是比较多,所以几乎每天都保持超过8000步的行走记录

•  到了今年,行走的步数也越来越少了……因为基本上每天活动的范围仅限于寝室……


6. 结语

•  分析至此,我觉得我平日里的生活习惯还是蛮健康的,也正因如此也会渐渐养成了某些保持健康的习惯。

•  iPhone的健康app记录了多种活动的数据(如果有佩戴Apple Watch可能还会记录心率之类的数据)并提供了数据导出的功能;当然,如果拥有更多健康测量的设备,那么获得的数据也许还会更多。

•  可以看出,几张可视化的分析(除了app对比的那张图外)基本上可以看作是时间序列对象的描述性分析;至于对时间序列进行分解与建模更深层次、更复杂的统计方法方面,暂时没有涉及,不过还是有深挖的可能。如果感兴趣对自己的日常行为有兴趣的朋友可以尝试去探索一番!





 大家都在看 

2017年R语言发展报告(国内)

R语言中文社区历史文章整理(作者篇)

R语言中文社区历史文章整理(类型篇)


公众号后台回复关键字即可学习

回复 R                  R语言快速入门及数据挖掘 
回复 Kaggle案例  Kaggle十大案例精讲(连载中)
回复 文本挖掘      手把手教你做文本挖掘
回复 可视化          R语言可视化在商务场景中的应用 
回复 大数据         大数据系列免费视频教程 
回复 量化投资      张丹教你如何用R语言量化投资 
回复 用户画像      京东大数据,揭秘用户画像
回复 数据挖掘     常用数据挖掘算法原理解释与应用
回复 机器学习     人工智能系列之机器学习与实践
回复 爬虫            R语言爬虫实战案例分享

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存