Skip to content

Instantly share code, notes, and snippets.

@mgilliam
Created March 2, 2018 20:54
Show Gist options
  • Save mgilliam/1e666750ff9fda9d3c090c44a9b4e8e9 to your computer and use it in GitHub Desktop.
Save mgilliam/1e666750ff9fda9d3c090c44a9b4e8e9 to your computer and use it in GitHub Desktop.
Pandas Time Grouper
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, a pandas **[DatetimeIndex]** is generated. The index starts from the current time and comprises 360,000 periods of 1 second each.\n",
"\n",
"The index is then converted to a pandas **[Series]**.\n",
"\n",
"[DatetimeIndex]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DatetimeIndex.html\n",
"[Series]: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.html"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2018-02-21T19:56:33.898000Z",
"start_time": "2018-02-21T19:56:33.409000Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"2018-03-02 12:51:39.932344 2018-03-02 12:51:39.932344\n",
"2018-03-02 12:51:40.932344 2018-03-02 12:51:40.932344\n",
"2018-03-02 12:51:41.932344 2018-03-02 12:51:41.932344\n",
"2018-03-02 12:51:42.932344 2018-03-02 12:51:42.932344\n",
"2018-03-02 12:51:43.932344 2018-03-02 12:51:43.932344\n",
"Freq: S, dtype: datetime64[ns]"
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"import pandas as pd\n",
"\n",
"begin = pd.datetime.now()\n",
"dates = pd.date_range(begin, freq='S', periods=360000).to_series()\n",
"\n",
"dates.head()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"2018-03-06 16:51:34.932344 2018-03-06 16:51:34.932344\n",
"2018-03-06 16:51:35.932344 2018-03-06 16:51:35.932344\n",
"2018-03-06 16:51:36.932344 2018-03-06 16:51:36.932344\n",
"2018-03-06 16:51:37.932344 2018-03-06 16:51:37.932344\n",
"2018-03-06 16:51:38.932344 2018-03-06 16:51:38.932344\n",
"Freq: S, dtype: datetime64[ns]"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dates.tail()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The datetime values are rounded to the nearest second. From these, 36 values are taken via the **[sample]** method and sorted.\n",
"\n",
"To each of the `startDate` values, a random (integer) number of seconds is added to generate the `endDate` values. The **[timedelta]** here is constrained between zero and half the minimum of the [first discrete difference] of the `startDate` values (to guard against overlap).\n",
"\n",
"[sample]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.sample.html\n",
"[timedelta]: https://docs.python.org/3.6/library/datetime.html#timedelta-objects\n",
"[first discrete difference]: http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Series.diff.html"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2018-02-21T19:56:33.898000Z",
"start_time": "2018-02-21T19:56:33.409000Z"
}
},
"outputs": [],
"source": [
"from datetime import timedelta\n",
"import numpy as np\n",
"\n",
"startDate = dates.dt.round(freq='S').sample(n=36).sort_values()\n",
"dt_max = np.floor(startDate.diff().min().total_seconds() / 2)\n",
"endDate = startDate + timedelta(seconds=np.random.randint(0, dt_max))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, the synthetic data is assembled into a pandas **[DataFrame]** by [concatenating] the `startDate` and `endDate`.\n",
"\n",
"To this is added a `value` column for the step measurement (random) values for each \\[`startDate`, `endDate`\\] interval. The resultant **[DataFrame]** is then sorted by time, and the (integer) index is reset.\n",
"\n",
"[DataFrame]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.html\n",
"[concatenating]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.concat.html"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"ExecuteTime": {
"end_time": "2018-02-21T19:56:33.898000Z",
"start_time": "2018-02-21T19:56:33.409000Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>startDate</th>\n",
" <th>endDate</th>\n",
" <th>value</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>2018-03-02 14:08:12</td>\n",
" <td>2018-03-02 14:08:18</td>\n",
" <td>30</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>2018-03-02 19:41:24</td>\n",
" <td>2018-03-02 19:41:30</td>\n",
" <td>68</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>2018-03-02 20:33:13</td>\n",
" <td>2018-03-02 20:33:19</td>\n",
" <td>33</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>2018-03-03 15:03:05</td>\n",
" <td>2018-03-03 15:03:11</td>\n",
" <td>47</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>2018-03-03 18:26:16</td>\n",
" <td>2018-03-03 18:26:22</td>\n",
" <td>57</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" startDate endDate value\n",
"0 2018-03-02 14:08:12 2018-03-02 14:08:18 30\n",
"1 2018-03-02 19:41:24 2018-03-02 19:41:30 68\n",
"2 2018-03-02 20:33:13 2018-03-02 20:33:19 33\n",
"3 2018-03-03 15:03:05 2018-03-03 15:03:11 47\n",
"4 2018-03-03 18:26:16 2018-03-03 18:26:22 57"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cols = ['startDate', 'endDate']\n",
"\n",
"steps = pd.concat([startDate, endDate], axis=1, keys=cols)\n",
"steps['value'] = np.random.randint(0, 100, size=len(steps))\n",
"steps.sort_values(by=['startDate', 'endDate'], inplace=True)\n",
"steps.reset_index(drop=True, inplace=True)\n",
"\n",
"steps.head()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `steps` are [grouped] into daily bins according to the `startDate` column values. This results in a pandas **DataFrameGroupBy** object.\n",
"\n",
"[grouped]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.groupby.html"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"ExecuteTime": {
"end_time": "2018-02-21T19:57:35.436000Z",
"start_time": "2018-02-21T19:57:35.415000Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"<pandas.core.groupby.DataFrameGroupBy object at 0x00000254B675BB38>"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"daily = steps.groupby(pd.Grouper(key='startDate', freq='D'))\n",
"\n",
"daily"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The total daily steps can be calculated by applying the built-in `sum` [aggregation] to the **GroupBy** object. While `daily` remains a **GroupBy** object, applying an aggregation function yields a **DataFrame**.\n",
"\n",
"[aggregation]: https://pandas.pydata.org/pandas-docs/stable/groupby.html#aggregation"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr style=\"text-align: right;\">\n",
" <th></th>\n",
" <th>value</th>\n",
" </tr>\n",
" <tr>\n",
" <th>startDate</th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2018-03-02</th>\n",
" <td>131</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-03</th>\n",
" <td>185</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-04</th>\n",
" <td>645</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-05</th>\n",
" <td>329</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-06</th>\n",
" <td>338</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" value\n",
"startDate \n",
"2018-03-02 131\n",
"2018-03-03 185\n",
"2018-03-04 645\n",
"2018-03-05 329\n",
"2018-03-06 338"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"daily.sum()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This **DataFrame** can of course be [plotted].\n",
"\n",
"[plotted]: https://pandas.pydata.org/pandas-docs/stable/generated/pandas.DataFrame.plot.html"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<matplotlib.figure.Figure at 0x254b882f780>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"%matplotlib inline\n",
"\n",
"daily.sum().plot(figsize=(12, 8));"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this example -- due to the irregularity of the step value measurement reporting intervals -- many of the possible aggregations to the **GroupBy** object are not interesting at all. For example, the `max` function, if applied to the grouped data, would return the maximum value for all reported intervals within each daily group. Similarly for `min`, `mean`, and `std`."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {
"ExecuteTime": {
"end_time": "2018-02-21T20:00:10.778000Z",
"start_time": "2018-02-21T20:00:10.751000Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"<div>\n",
"<style scoped>\n",
" .dataframe tbody tr th:only-of-type {\n",
" vertical-align: middle;\n",
" }\n",
"\n",
" .dataframe tbody tr th {\n",
" vertical-align: top;\n",
" }\n",
"\n",
" .dataframe thead tr th {\n",
" text-align: left;\n",
" }\n",
"\n",
" .dataframe thead tr:last-of-type th {\n",
" text-align: right;\n",
" }\n",
"</style>\n",
"<table border=\"1\" class=\"dataframe\">\n",
" <thead>\n",
" <tr>\n",
" <th></th>\n",
" <th colspan=\"4\" halign=\"left\">value</th>\n",
" </tr>\n",
" <tr>\n",
" <th></th>\n",
" <th>min</th>\n",
" <th>max</th>\n",
" <th>mean</th>\n",
" <th>std</th>\n",
" </tr>\n",
" <tr>\n",
" <th>startDate</th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" <th></th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>2018-03-02</th>\n",
" <td>30</td>\n",
" <td>68</td>\n",
" <td>43.666667</td>\n",
" <td>21.126603</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-03</th>\n",
" <td>12</td>\n",
" <td>57</td>\n",
" <td>37.000000</td>\n",
" <td>22.704625</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-04</th>\n",
" <td>14</td>\n",
" <td>97</td>\n",
" <td>64.500000</td>\n",
" <td>28.336274</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-05</th>\n",
" <td>7</td>\n",
" <td>65</td>\n",
" <td>29.909091</td>\n",
" <td>19.408527</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2018-03-06</th>\n",
" <td>10</td>\n",
" <td>89</td>\n",
" <td>48.285714</td>\n",
" <td>31.393812</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" value \n",
" min max mean std\n",
"startDate \n",
"2018-03-02 30 68 43.666667 21.126603\n",
"2018-03-03 12 57 37.000000 22.704625\n",
"2018-03-04 14 97 64.500000 28.336274\n",
"2018-03-05 7 65 29.909091 19.408527\n",
"2018-03-06 10 89 48.285714 31.393812"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"daily.agg(['min', 'max', 'mean', 'std'])"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python (3.6-64)",
"language": "python",
"name": "py36-64"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.4"
},
"toc": {
"nav_menu": {},
"number_sections": true,
"sideBar": true,
"skip_h1_title": false,
"toc_cell": false,
"toc_position": {},
"toc_section_display": "block",
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment