|
| 1 | +原文:[Analyzing iPhone Step Data](http://blog.yhat.com/posts/phone-steps-timeseries.html) |
| 2 | + |
| 3 | +--- |
| 4 | + |
| 5 | +### 自白书 |
| 6 | + |
| 7 | +我叫Ross,沉迷于计算步数。行走的那种。这种沉迷带来的是经常性打开iPhone上的计步应用,查看步数上升,保证我的步数超过了10,000 (我妈妈说,那是一个神奇的数字)。幸运的是,在大多数的日子里,住在纽约让这个目标容易实现。 |
| 8 | + |
| 9 | +在这篇文章中,我会告诉你如何使用[pandas](http://pandas.pydata.org/)时间序列和[ggplot](http://github.com/yhat/ggplot)来分析我的iPhone步数数据。我在Python中使用[Rodeo](https://www.yhat.com/products/rodeo)来进行所有的数据科学工作,它是用于数据科学的[Yhat](https://www.yhat.com/) IDE。 |
| 10 | + |
| 11 | +### 收集数据 |
| 12 | + |
| 13 | +正如所有正经的数据迷,我希望能够将数据从手机导出以用于分析。Quantified Self Labs的牛人推出了一个名为[QS Access](http://quantifiedself.com/access-app/app)的应用,它让检索这些数据不在话下! |
| 14 | + |
| 15 | +下面是几个导出数据的截图。 |
| 16 | + |
| 17 | +  |
| 18 | + |
| 19 | + |
| 20 | +QS Access应用导出一个CSV文件,它包含3列:一个`start`时间戳,一个`finish`时间戳和期间的`steps (count)`。有一个选项,用来生成每小时/每天的数据行。为什么不从小时开始,看看情况如何 —— 更大的数据总是更好,对不对? |
| 21 | + |
| 22 | +### TO THE DATAS! |
| 23 | + |
| 24 | +我们的分析将利用[pandas](http://pandas.pydata.org/)中内置的时间序列工具。当[Wes McKinney](https://github.com/wesm)开始pandas项目时,他正为一家投资管理公司工作,而这个行业广泛依赖于时间序列分析。结果,pandas自带了这个领域的全面功能。 |
| 25 | + |
| 26 | +此时,有一些关于导入这个数据其他注意事项。 |
| 27 | + |
| 28 | +首先,我们已经知道我们拥有时间序列数据,因此,我们可以通过使用`parse_dates`参数告诉pandas。 |
| 29 | + |
| 30 | +CSV中的结束时间数据并不是特别有趣,因为我们有开始时间,并且还有每小时的频率,因此,可以用`usecols`来忽略它。 |
| 31 | + |
| 32 | +最后,设置开始时间 (col 0) 为索引列,获得一个`DateTimeIndex`,这在后面将让我们的工作更容易。 |
| 33 | + |
| 34 | +```python |
| 35 | +df_hour = pd.read_csv('health_data_hour.csv', parse_dates=[0,1], names=['start_time', 'steps'], usecols=[0, 2], skiprows=1, index_col=0) |
| 36 | +# ensure the steps col are ints - weirdness going on with this one |
| 37 | +df_hour.steps = df_hour.steps.apply(lambda x: int(float(x))) |
| 38 | +df_hour.head() |
| 39 | +type(df_hour.index) |
| 40 | +type(df_hour.steps[1]) |
| 41 | +``` |
| 42 | + |
| 43 | +start_time| steps |
| 44 | +---|--- |
| 45 | +2014-10-24 18:00:00 |459 |
| 46 | +2014-10-24 19:00:00 |93 |
| 47 | +2014-10-24 20:00:00 |421 |
| 48 | +2014-10-24 21:00:00 |1306 |
| 49 | +2014-10-24 22:00:00 |39 |
| 50 | + |
| 51 | + |
| 52 | +注意到,start_time列的类型:`pandas.tseries.index.DatetimeIndex`。这是因为在数据采集过程中设置索引列,它为我们提供了访问所有好东西的能力 —— 重采样一个,我们稍后会看到。 |
| 53 | + |
| 54 | +### 每小时步数 |
| 55 | + |
| 56 | +快速绘制[(gg)plot](http://github.com/yhat/ggplot)来探索下我们这里拥有的数据,如何? |
| 57 | + |
| 58 | + |
| 59 | + |
| 60 | +我去!有点太乱了。我们可以如何提高我们的可视化呢?我想到了一个方法 —— pandas有一个名为`resample`的函数,它允许我们在更长的时间上汇总数据。 |
| 61 | + |
| 62 | +更精确地说,当你减少一个给定标志的采样率时,这就是所谓的**降低取样频率**。在这个例子中,我们将采用每小时的数据,并基于天/周/月,使用均值和总和聚合,进行重新取样。 |
| 63 | + |
| 64 | +### 降低取样频率到天步数 |
| 65 | + |
| 66 | +让我们先从每天总和开始 (注意,你可以将dataframe `__index__`传递到ggplot函数中): |
| 67 | + |
| 68 | +```python |
| 69 | +df_daily = pd.DataFrame() |
| 70 | +df_daily['step_count'] = df_hour.steps.resample('D').sum() |
| 71 | +df_daily.head() |
| 72 | +p = ggplot(df_daily, aes(x='__index__', y='step_count')) + \ |
| 73 | + geom_step() + \ |
| 74 | + stat_smooth() + \ |
| 75 | + scale_x_date(labels="%m/%Y") + \ |
| 76 | + ggtitle("Daily Step Count") + \ |
| 77 | + xlab("Date") + \ |
| 78 | + ylab("Steps") |
| 79 | +print p |
| 80 | +``` |
| 81 | + |
| 82 | + |
| 83 | + |
| 84 | +哈哈!现在,我们取得了一些进展。这是一个更可读得多的图。**而且**,看起来有一个很好的上升趋势 (稍后我们将提到)。 |
| 85 | + |
| 86 | +### 降低取样频率到周/月步数 |
| 87 | + |
| 88 | +有了这个,我们就可以再进行每周/月的重新采样了。仅需传递`'W'`或者`'M'`到resample函数中。 |
| 89 | + |
| 90 | +因为我对每天的步数总和指标最感兴趣,因此我们可以开始使用一个均值聚合函数来获得周/月样本中的每日平均值 (一天获得10,000个!)。这只需要修改`resample`之后的`sum()`函数为`mean()`。 |
| 91 | + |
| 92 | +它看起来像这样: |
| 93 | + |
| 94 | +```python |
| 95 | +df_weekly['step_mean'] = df_daily.step_count.resample('W').mean() |
| 96 | +df_monthly['step_mean'] = df_daily.step_count.resample('M').mean() |
| 97 | +``` |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | +简短的附加说明:Pandas还可以做和我们所做相反的事情,称为上采样。如果你的项目需要的话,可以看看[这个文档](http://pandas.pydata.org/pandas-docs/version/0.17.0/generated/pandas.Panel.resample.html)。 |
| 103 | + |
| 104 | +### (稍微)更深入些 |
| 105 | + |
| 106 | + |
| 107 | + |
| 108 | +我很好奇,我在周末是不是会比工作日期间获得更多的步数。我们可以使用[Rodeo](https://www.yhat.com/products/rodeo)中的标签建议,来看看DateTimeIndex上可用的方法。 |
| 109 | + |
| 110 | +刚好有`weekday`和`weekday_name`方法,看起来有用。前者将返回一个对应每周中的一天的整数,而后者将返回那一天的字符串名称。在我们用那个信息作为一个新列后,对其应用一个辅助函数可以返回一个布尔值,用来判断它是否是周末。 |
| 111 | + |
| 112 | +```python |
| 113 | +def weekendBool(day): |
| 114 | + if day not in ['Saturday', 'Sunday']: |
| 115 | + return False |
| 116 | + else: |
| 117 | + return True |
| 118 | + |
| 119 | +df_daily['weekday'] = df_daily.index.weekday |
| 120 | +df_daily['weekday_name'] = df_daily.index.weekday_name |
| 121 | +df_daily['weekend'] = df_daily.weekday_name.apply(weekendBool) |
| 122 | +df_daily.head() |
| 123 | +``` |
| 124 | + |
| 125 | +start_time |step_count |weekday ||weekday_name ||weekend| |
| 126 | +---|---|---|---|--- |
| 127 | +2014-10-24 |2333 |4 |Friday |False |
| 128 | +2014-10-25 |3085 |5 |Saturday |True |
| 129 | +2014-10-26 |21636 |6 |Sunday |True |
| 130 | +2014-10-27 |13776 |0 |Monday |False |
| 131 | +2014-10-28 |5732 |1 |Tuesday |False |
| 132 | + |
| 133 | +ggplot有一个可用的stat_density绘图函数,对于比较周末和平日的总体非常适合。一探究竟: |
| 134 | + |
| 135 | +```python |
| 136 | +ggplot(aes(x='step_count', color='weekend'), data=df_daily) + \ |
| 137 | + stat_density() + \ |
| 138 | + ggtitle("Comparing Weekend vs. Weekday Daily Step Count") + \ |
| 139 | + xlab("Step Count") |
| 140 | +``` |
| 141 | + |
| 142 | + |
| 143 | + |
| 144 | +我们还可以基于这个weekend_bool对数据进行分组,并且运行一些聚合方法来看看数据的差异。看看我之前在[grouping in padas](http://blog.yhat.com/posts/grouping-pandas.html)上的一篇文章,获取关于这个功能的说明。 |
| 145 | + |
| 146 | +```python |
| 147 | +weekend_grouped = df_daily.groupby('weekend') |
| 148 | +weekend_grouped.describe() |
| 149 | + |
| 150 | + step_count weekday |
| 151 | +weekend |
| 152 | +False count 479.000000 479.000000 |
| 153 | + mean 10145.832985 1.997912 |
| 154 | + std 4962.913936 1.416429 |
| 155 | + min 847.000000 0.000000 |
| 156 | + 25% 6345.000000 1.000000 |
| 157 | + 50% 9742.000000 2.000000 |
| 158 | + 75% 13195.000000 3.000000 |
| 159 | + max 37360.000000 4.000000 |
| 160 | +True count 192.000000 192.000000 |
| 161 | + mean 11621.166667 5.500000 |
| 162 | + std 7152.197426 0.501307 |
| 163 | + min 641.000000 5.000000 |
| 164 | + 25% 6321.000000 5.000000 |
| 165 | + 50% 10228.000000 5.500000 |
| 166 | + 75% 15562.500000 6.000000 |
| 167 | + max 35032.000000 6.000000 |
| 168 | + |
| 169 | +weekend_grouped.median() |
| 170 | + step_count weekday |
| 171 | +weekend |
| 172 | +False 9742 2.0 |
| 173 | +True 10228 5.5 |
| 174 | +``` |
| 175 | + |
| 176 | +周末平均11,621步 (中位数是10,228) 对比工作日的10,146 (中位数是9,742),看起来周末有微弱的优势! |
| 177 | + |
| 178 | +### 现在,看趋势 |
| 179 | + |
| 180 | +让我们回到上升趋势 |
| 181 | + |
| 182 | +四月初,我从Charlotte, NC搬到了New York,在[Yhat](https://www.yhat.com/)当一个软件工程师。 |
| 183 | + |
| 184 | +我很好奇,这个位置的变化对我每天的步数有什么影响。我们可以应用与周末数据相同的方法,来看看。 |
| 185 | + |
| 186 | +我只是给你看点好东西: |
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | +上面的图看起来在搬到纽约市后,有显著的变化。比之位置的改变,还有更多的变量,像我刚开始更认真的跑步这个事实,这将贡献一些数据,但要控制其影响,需要更多的数据。也许在另一篇文章中会提到! |
| 193 | + |
| 194 | +### 最后的思考 |
| 195 | + |
| 196 | +希望这篇分析足以让你开始检查你的步数数据,使用[Rodeo](https://www.yhat.com/products/rodeo)进行一些数据科学,探索[pandas](http://pandas.pydata.org/)的时间序列功能!如果你想对源码一探究竟,那么可以看看我关于这个项目的[repo](https://github.com/rkipp1210/data-projects)。 |
| 197 | + |
| 198 | +现在,回到统计那些步数。 |
0 commit comments