{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Dask DataFrames\n", "\n", "\"Dask\n", " \n", "Dask Dataframes coordinate many Pandas dataframes, partitioned along an index. They support a large subset of the Pandas API." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Start Dask Client for Dashboard\n", "\n", "Starting the Dask Client is optional. It will provide a dashboard which \n", "is useful to gain insight on the computation. \n", "\n", "The link to the dashboard will become visible when you create the client below. We recommend having it open on one side of your screen while using your notebook on the other side. This can take some effort to arrange your windows, but seeing them both at the same is very useful when learning." ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:34.017752Z", "iopub.status.busy": "2021-01-14T10:42:34.017200Z", "iopub.status.idle": "2021-01-14T10:42:35.683269Z", "shell.execute_reply": "2021-01-14T10:42:35.683880Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "\n", "\n", "\n", "
\n", "

Client

\n", "\n", "
\n", "

Cluster

\n", "
    \n", "
  • Workers: 2
  • \n", "
  • Cores: 4
  • \n", "
  • Memory: 2.00 GB
  • \n", "
\n", "
" ], "text/plain": [ "" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from dask.distributed import Client, progress\n", "client = Client(n_workers=2, threads_per_worker=2, memory_limit='1GB')\n", "client" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Create Random Dataframe\n", "\n", "We create a random timeseries of data with the following attributes:\n", "\n", "1. It stores a record for every 10 seconds of the year 2000\n", "2. It splits that year by month, keeping every month as a separate Pandas dataframe\n", "3. Along with a datetime index it has columns for names, ids, and numeric values\n", "\n", "This is a small dataset of about 240 MB. Increase the number of days or reduce the frequency to practice with a larger dataset." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:35.686000Z", "iopub.status.busy": "2021-01-14T10:42:35.685603Z", "iopub.status.idle": "2021-01-14T10:42:35.854189Z", "shell.execute_reply": "2021-01-14T10:42:35.854979Z" } }, "outputs": [], "source": [ "import dask\n", "import dask.dataframe as dd\n", "df = dask.datasets.timeseries()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike Pandas, Dask DataFrames are lazy and so no data is printed here." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:35.857633Z", "iopub.status.busy": "2021-01-14T10:42:35.856788Z", "iopub.status.idle": "2021-01-14T10:42:35.871903Z", "shell.execute_reply": "2021-01-14T10:42:35.872613Z" } }, "outputs": [ { "data": { "text/html": [ "
Dask DataFrame Structure:
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idnamexy
npartitions=30
2000-01-01int64objectfloat64float64
2000-01-02............
...............
2000-01-30............
2000-01-31............
\n", "
\n", "
Dask Name: make-timeseries, 30 tasks
" ], "text/plain": [ "Dask DataFrame Structure:\n", " id name x y\n", "npartitions=30 \n", "2000-01-01 int64 object float64 float64\n", "2000-01-02 ... ... ... ...\n", "... ... ... ... ...\n", "2000-01-30 ... ... ... ...\n", "2000-01-31 ... ... ... ...\n", "Dask Name: make-timeseries, 30 tasks" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "But the column names and dtypes are known." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:35.875249Z", "iopub.status.busy": "2021-01-14T10:42:35.874339Z", "iopub.status.idle": "2021-01-14T10:42:35.880257Z", "shell.execute_reply": "2021-01-14T10:42:35.880879Z" } }, "outputs": [ { "data": { "text/plain": [ "id int64\n", "name object\n", "x float64\n", "y float64\n", "dtype: object" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.dtypes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some operations will automatically display the data." ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:35.883264Z", "iopub.status.busy": "2021-01-14T10:42:35.882456Z", "iopub.status.idle": "2021-01-14T10:42:35.886030Z", "shell.execute_reply": "2021-01-14T10:42:35.886580Z" } }, "outputs": [], "source": [ "import pandas as pd\n", "pd.options.display.precision = 2\n", "pd.options.display.max_rows = 10" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:35.889044Z", "iopub.status.busy": "2021-01-14T10:42:35.888194Z", "iopub.status.idle": "2021-01-14T10:42:36.262879Z", "shell.execute_reply": "2021-01-14T10:42:36.263454Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idnamexy
timestamp
2000-01-01 00:00:001058Norbert0.140.21
2000-01-01 00:00:011012Ingrid0.96-0.60
2000-01-01 00:00:02987Norbert-0.97-0.39
\n", "
" ], "text/plain": [ " id name x y\n", "timestamp \n", "2000-01-01 00:00:00 1058 Norbert 0.14 0.21\n", "2000-01-01 00:00:01 1012 Ingrid 0.96 -0.60\n", "2000-01-01 00:00:02 987 Norbert -0.97 -0.39" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.head(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Use Standard Pandas Operations\n", "\n", "Most common Pandas operations operate identically on Dask dataframes" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:36.272361Z", "iopub.status.busy": "2021-01-14T10:42:36.270694Z", "iopub.status.idle": "2021-01-14T10:42:36.298437Z", "shell.execute_reply": "2021-01-14T10:42:36.299281Z" } }, "outputs": [ { "data": { "text/plain": [ "Dask Series Structure:\n", "npartitions=1\n", " float64\n", " ...\n", "Name: x, dtype: float64\n", "Dask Name: sqrt, 157 tasks" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df2 = df[df.y > 0]\n", "df3 = df2.groupby('name').x.std()\n", "df3" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Call `.compute()` when you want your result as a Pandas dataframe.\n", "\n", "If you started `Client()` above then you may want to watch the status page during computation." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:36.316781Z", "iopub.status.busy": "2021-01-14T10:42:36.312270Z", "iopub.status.idle": "2021-01-14T10:42:37.758476Z", "shell.execute_reply": "2021-01-14T10:42:37.758095Z" } }, "outputs": [ { "data": { "text/plain": [ "pandas.core.series.Series" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "computed_df = df3.compute()\n", "type(computed_df)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:37.762366Z", "iopub.status.busy": "2021-01-14T10:42:37.761908Z", "iopub.status.idle": "2021-01-14T10:42:37.767075Z", "shell.execute_reply": "2021-01-14T10:42:37.767687Z" } }, "outputs": [ { "data": { "text/plain": [ "name\n", "Alice 0.58\n", "Bob 0.58\n", "Charlie 0.58\n", "Dan 0.58\n", "Edith 0.58\n", " ... \n", "Victor 0.58\n", "Wendy 0.58\n", "Xavier 0.58\n", "Yvonne 0.58\n", "Zelda 0.58\n", "Name: x, Length: 26, dtype: float64" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "computed_df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Persist data in memory\n", "\n", "If you have the available RAM for your dataset then you can persist data in memory. \n", "\n", "This allows future computations to be much faster." ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:37.770245Z", "iopub.status.busy": "2021-01-14T10:42:37.769314Z", "iopub.status.idle": "2021-01-14T10:42:37.786927Z", "shell.execute_reply": "2021-01-14T10:42:37.787515Z" } }, "outputs": [], "source": [ "df = df.persist()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Time Series Operations\n", "\n", "Because we have a datetime index time-series operations work efficiently" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:37.790104Z", "iopub.status.busy": "2021-01-14T10:42:37.789290Z", "iopub.status.idle": "2021-01-14T10:42:40.153908Z", "shell.execute_reply": "2021-01-14T10:42:40.154257Z" } }, "outputs": [], "source": [ "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.163031Z", "iopub.status.busy": "2021-01-14T10:42:40.162172Z", "iopub.status.idle": "2021-01-14T10:42:40.211708Z", "shell.execute_reply": "2021-01-14T10:42:40.211326Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
xy
timestamp
2000-01-01 00:00:001.59e-03-7.11e-03
2000-01-01 01:00:00-6.15e-034.16e-03
2000-01-01 02:00:00-3.55e-03-1.47e-02
2000-01-01 03:00:001.10e-02-3.52e-03
2000-01-01 04:00:00-1.51e-025.70e-03
\n", "
" ], "text/plain": [ " x y\n", "timestamp \n", "2000-01-01 00:00:00 1.59e-03 -7.11e-03\n", "2000-01-01 01:00:00 -6.15e-03 4.16e-03\n", "2000-01-01 02:00:00 -3.55e-03 -1.47e-02\n", "2000-01-01 03:00:00 1.10e-02 -3.52e-03\n", "2000-01-01 04:00:00 -1.51e-02 5.70e-03" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[['x', 'y']].resample('1h').mean().head()" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.222460Z", "iopub.status.busy": "2021-01-14T10:42:40.218424Z", "iopub.status.idle": "2021-01-14T10:42:40.719917Z", "shell.execute_reply": "2021-01-14T10:42:40.719511Z" } }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "df[['x', 'y']].resample('24h').mean().compute().plot()" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.737730Z", "iopub.status.busy": "2021-01-14T10:42:40.737288Z", "iopub.status.idle": "2021-01-14T10:42:40.762789Z", "shell.execute_reply": "2021-01-14T10:42:40.763158Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
xy
timestamp
2000-01-01 00:00:000.140.21
2000-01-01 00:00:010.55-0.19
2000-01-01 00:00:020.05-0.26
2000-01-01 00:00:03-0.01-0.21
2000-01-01 00:00:04-0.04-0.11
\n", "
" ], "text/plain": [ " x y\n", "timestamp \n", "2000-01-01 00:00:00 0.14 0.21\n", "2000-01-01 00:00:01 0.55 -0.19\n", "2000-01-01 00:00:02 0.05 -0.26\n", "2000-01-01 00:00:03 -0.01 -0.21\n", "2000-01-01 00:00:04 -0.04 -0.11" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df[['x', 'y']].rolling(window='24h').mean().head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Random access is cheap along the index, but must still be computed." ] }, { "cell_type": "code", "execution_count": 15, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.766306Z", "iopub.status.busy": "2021-01-14T10:42:40.765532Z", "iopub.status.idle": "2021-01-14T10:42:40.780576Z", "shell.execute_reply": "2021-01-14T10:42:40.780888Z" } }, "outputs": [ { "data": { "text/html": [ "
Dask DataFrame Structure:
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idnamexy
npartitions=1
2000-01-05 00:00:00.000000000int64objectfloat64float64
2000-01-05 23:59:59.999999999............
\n", "
\n", "
Dask Name: loc, 31 tasks
" ], "text/plain": [ "Dask DataFrame Structure:\n", " id name x y\n", "npartitions=1 \n", "2000-01-05 00:00:00.000000000 int64 object float64 float64\n", "2000-01-05 23:59:59.999999999 ... ... ... ...\n", "Dask Name: loc, 31 tasks" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.loc['2000-01-05']" ] }, { "cell_type": "code", "execution_count": 16, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.782916Z", "iopub.status.busy": "2021-01-14T10:42:40.782407Z", "iopub.status.idle": "2021-01-14T10:42:40.838474Z", "shell.execute_reply": "2021-01-14T10:42:40.839023Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 13.5 ms, sys: 11.9 ms, total: 25.3 ms\n", "Wall time: 42.2 ms\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idnamexy
timestamp
2000-01-05 00:00:00990Charlie-0.390.87
2000-01-05 00:00:011034Wendy-0.610.25
2000-01-05 00:00:02990George-0.620.57
2000-01-05 00:00:031096Zelda0.220.58
2000-01-05 00:00:041011Jerry-0.330.16
...............
2000-01-05 23:59:55945Ray-0.670.26
2000-01-05 23:59:561000Michael0.170.46
2000-01-05 23:59:57981George0.45-0.26
2000-01-05 23:59:58956Oliver0.300.69
2000-01-05 23:59:591030Edith0.610.39
\n", "

86400 rows × 4 columns

\n", "
" ], "text/plain": [ " id name x y\n", "timestamp \n", "2000-01-05 00:00:00 990 Charlie -0.39 0.87\n", "2000-01-05 00:00:01 1034 Wendy -0.61 0.25\n", "2000-01-05 00:00:02 990 George -0.62 0.57\n", "2000-01-05 00:00:03 1096 Zelda 0.22 0.58\n", "2000-01-05 00:00:04 1011 Jerry -0.33 0.16\n", "... ... ... ... ...\n", "2000-01-05 23:59:55 945 Ray -0.67 0.26\n", "2000-01-05 23:59:56 1000 Michael 0.17 0.46\n", "2000-01-05 23:59:57 981 George 0.45 -0.26\n", "2000-01-05 23:59:58 956 Oliver 0.30 0.69\n", "2000-01-05 23:59:59 1030 Edith 0.61 0.39\n", "\n", "[86400 rows x 4 columns]" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%time df.loc['2000-01-05'].compute()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Set Index\n", "\n", "Data is sorted by the index column. This allows for faster access, joins, groupby-apply operations, etc.. However sorting data can be costly to do in parallel, so setting the index is both important to do, but only infrequently." ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:40.841172Z", "iopub.status.busy": "2021-01-14T10:42:40.840767Z", "iopub.status.idle": "2021-01-14T10:42:44.569186Z", "shell.execute_reply": "2021-01-14T10:42:44.569511Z" } }, "outputs": [ { "data": { "text/html": [ "
Dask DataFrame Structure:
\n", "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idxy
npartitions=30
Aliceint64float64float64
Alice.........
............
Zelda.........
Zelda.........
\n", "
\n", "
Dask Name: sort_index, 1140 tasks
" ], "text/plain": [ "Dask DataFrame Structure:\n", " id x y\n", "npartitions=30 \n", "Alice int64 float64 float64\n", "Alice ... ... ...\n", "... ... ... ...\n", "Zelda ... ... ...\n", "Zelda ... ... ...\n", "Dask Name: sort_index, 1140 tasks" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df = df.set_index('name')\n", "df" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because computing this dataset is expensive and we can fit it in our available RAM, we persist the dataset to memory." ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:44.578618Z", "iopub.status.busy": "2021-01-14T10:42:44.578056Z", "iopub.status.idle": "2021-01-14T10:42:44.647645Z", "shell.execute_reply": "2021-01-14T10:42:44.647222Z" } }, "outputs": [], "source": [ "df = df.persist()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dask now knows where all data lives, indexed cleanly by name. As a result oerations like random access are cheap and efficient" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:44.653511Z", "iopub.status.busy": "2021-01-14T10:42:44.653101Z", "iopub.status.idle": "2021-01-14T10:42:47.095894Z", "shell.execute_reply": "2021-01-14T10:42:47.096208Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "CPU times: user 331 ms, sys: 19.6 ms, total: 350 ms\n", "Wall time: 2.42 s\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
idxy
name
Alice1026-0.998.07e-01
Alice1003-0.988.48e-01
Alice986-0.86-1.51e-01
Alice9690.641.27e-01
Alice10070.789.35e-01
............
Alice9740.33-5.91e-01
Alice10020.458.60e-01
Alice10700.406.67e-03
Alice972-0.69-8.54e-01
Alice9900.897.59e-01
\n", "

99913 rows × 3 columns

\n", "
" ], "text/plain": [ " id x y\n", "name \n", "Alice 1026 -0.99 8.07e-01\n", "Alice 1003 -0.98 8.48e-01\n", "Alice 986 -0.86 -1.51e-01\n", "Alice 969 0.64 1.27e-01\n", "Alice 1007 0.78 9.35e-01\n", "... ... ... ...\n", "Alice 974 0.33 -5.91e-01\n", "Alice 1002 0.45 8.60e-01\n", "Alice 1070 0.40 6.67e-03\n", "Alice 972 -0.69 -8.54e-01\n", "Alice 990 0.89 7.59e-01\n", "\n", "[99913 rows x 3 columns]" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "%time df.loc['Alice'].compute()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Groupby Apply with Scikit-Learn" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that our data is sorted by name we can easily do operations like random access on name, or groupby-apply with custom functions.\n", "\n", "Here we train a different Scikit-Learn linear regression model on each name." ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:47.101181Z", "iopub.status.busy": "2021-01-14T10:42:47.100071Z", "iopub.status.idle": "2021-01-14T10:42:47.701373Z", "shell.execute_reply": "2021-01-14T10:42:47.702374Z" } }, "outputs": [], "source": [ "from sklearn.linear_model import LinearRegression\n", "\n", "def train(partition):\n", " est = LinearRegression()\n", " est.fit(partition[['x']].values, partition.y.values)\n", " return est" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "execution": { "iopub.execute_input": "2021-01-14T10:42:47.707446Z", "iopub.status.busy": "2021-01-14T10:42:47.706484Z", "iopub.status.idle": "2021-01-14T10:42:50.140881Z", "shell.execute_reply": "2021-01-14T10:42:50.141703Z" } }, "outputs": [ { "data": { "text/plain": [ "name\n", "Alice LinearRegression()\n", "Bob LinearRegression()\n", "Charlie LinearRegression()\n", "Dan LinearRegression()\n", "Edith LinearRegression()\n", " ... \n", "Victor LinearRegression()\n", "Wendy LinearRegression()\n", "Xavier LinearRegression()\n", "Yvonne LinearRegression()\n", "Zelda LinearRegression()\n", "Length: 26, dtype: object" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "df.groupby('name').apply(train, meta=object).compute()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Further Reading\n", "\n", "For a more in-depth introduction to Dask dataframes, see the [dask tutorial](https://github.com/dask/dask-tutorial), notebooks 04 and 07." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.8.6" } }, "nbformat": 4, "nbformat_minor": 2 }