Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save jorisvandenbossche/3580f86fb9319a86f0af10c9112e67bd to your computer and use it in GitHub Desktop.
Save jorisvandenbossche/3580f86fb9319a86f0af10c9112e67bd to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Overview\n",
"\n",
"Based on a notebook of Jon Mease (https://anaconda.org/jonmmease/cx_benchmarking_pr/notebook), originally benchmarking this for the spatialpandas library.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import geopandas\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load dataset"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Building footprints from https://data.cityofnewyork.us/Housing-Development/Building-Footprints/nqwf-w8eh"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 1min 5s, sys: 3.34 s, total: 1min 8s\n",
"Wall time: 1min 8s\n"
]
},
{
"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>base_bbl</th>\n",
" <th>bin</th>\n",
" <th>cnstrct_yr</th>\n",
" <th>doitt_id</th>\n",
" <th>feat_code</th>\n",
" <th>geomsource</th>\n",
" <th>groundelev</th>\n",
" <th>heightroof</th>\n",
" <th>date_lstmo</th>\n",
" <th>time_lstmo</th>\n",
" <th>lststatype</th>\n",
" <th>mpluto_bbl</th>\n",
" <th>name</th>\n",
" <th>shape_area</th>\n",
" <th>shape_len</th>\n",
" <th>geometry</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>3044520815</td>\n",
" <td>3394646.0</td>\n",
" <td>2009.0</td>\n",
" <td>1212853.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>18.0</td>\n",
" <td>21.608508</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3044520815</td>\n",
" <td>None</td>\n",
" <td>854.662433</td>\n",
" <td>125.079796</td>\n",
" <td>POLYGON ((-73.87130 40.65717, -73.87136 40.657...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>4030640041</td>\n",
" <td>4548330.0</td>\n",
" <td>1930.0</td>\n",
" <td>1226227.0</td>\n",
" <td>5110.0</td>\n",
" <td>Photogramm</td>\n",
" <td>122.0</td>\n",
" <td>10.360000</td>\n",
" <td>2017-08-17</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>4030640041</td>\n",
" <td>None</td>\n",
" <td>217.594243</td>\n",
" <td>60.225858</td>\n",
" <td>POLYGON ((-73.87671 40.71425, -73.87677 40.714...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>4139430001</td>\n",
" <td>4460479.0</td>\n",
" <td>1960.0</td>\n",
" <td>581946.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>10.0</td>\n",
" <td>29.811570</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>4139430001</td>\n",
" <td>None</td>\n",
" <td>946.427476</td>\n",
" <td>123.141941</td>\n",
" <td>POLYGON ((-73.85195 40.66235, -73.85195 40.662...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3049720006</td>\n",
" <td>3355684.0</td>\n",
" <td>1920.0</td>\n",
" <td>858061.0</td>\n",
" <td>5110.0</td>\n",
" <td>Photogramm</td>\n",
" <td>32.0</td>\n",
" <td>11.200000</td>\n",
" <td>2017-08-17</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3049720006</td>\n",
" <td>None</td>\n",
" <td>248.678169</td>\n",
" <td>63.940817</td>\n",
" <td>POLYGON ((-73.94029 40.64108, -73.94034 40.641...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>3055100055</td>\n",
" <td>3131737.0</td>\n",
" <td>1915.0</td>\n",
" <td>568078.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>44.0</td>\n",
" <td>24.980000</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3055100055</td>\n",
" <td>None</td>\n",
" <td>1163.227669</td>\n",
" <td>165.608763</td>\n",
" <td>POLYGON ((-73.98999 40.62384, -73.98998 40.623...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" base_bbl bin cnstrct_yr doitt_id feat_code geomsource \\\n",
"0 3044520815 3394646.0 2009.0 1212853.0 2100.0 Photogramm \n",
"1 4030640041 4548330.0 1930.0 1226227.0 5110.0 Photogramm \n",
"2 4139430001 4460479.0 1960.0 581946.0 2100.0 Photogramm \n",
"3 3049720006 3355684.0 1920.0 858061.0 5110.0 Photogramm \n",
"4 3055100055 3131737.0 1915.0 568078.0 2100.0 Photogramm \n",
"\n",
" groundelev heightroof date_lstmo time_lstmo lststatype mpluto_bbl \\\n",
"0 18.0 21.608508 2017-08-22 00:00:00.000 Constructed 3044520815 \n",
"1 122.0 10.360000 2017-08-17 00:00:00.000 Constructed 4030640041 \n",
"2 10.0 29.811570 2017-08-22 00:00:00.000 Constructed 4139430001 \n",
"3 32.0 11.200000 2017-08-17 00:00:00.000 Constructed 3049720006 \n",
"4 44.0 24.980000 2017-08-22 00:00:00.000 Constructed 3055100055 \n",
"\n",
" name shape_area shape_len \\\n",
"0 None 854.662433 125.079796 \n",
"1 None 217.594243 60.225858 \n",
"2 None 946.427476 123.141941 \n",
"3 None 248.678169 63.940817 \n",
"4 None 1163.227669 165.608763 \n",
"\n",
" geometry \n",
"0 POLYGON ((-73.87130 40.65717, -73.87136 40.657... \n",
"1 POLYGON ((-73.87671 40.71425, -73.87677 40.714... \n",
"2 POLYGON ((-73.85195 40.66235, -73.85195 40.662... \n",
"3 POLYGON ((-73.94029 40.64108, -73.94034 40.641... \n",
"4 POLYGON ((-73.98999 40.62384, -73.98998 40.623... "
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%%time\n",
"buildings = geopandas.read_file(\"benchmark-data/Building Footprints/geo_export_e122dd5a-79ee-4afa-a717-e232a6fe1a72.shp\")\n",
"buildings.head()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset contains 1084749 (multi)polygons\n"
]
}
],
"source": [
"print(f\"Dataset contains {len(buildings)} (multi)polygons\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([-74.25549541, 40.49842932, -73.70006247, 40.91505011])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"buildings.total_bounds"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"ser = buildings.geometry"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3 POLYGON ((-73.94029 40.64108, -73.94034 40.641...\n",
"4 POLYGON ((-73.98999 40.62384, -73.98998 40.623...\n",
"8 POLYGON ((-73.94669 40.64494, -73.94689 40.644...\n",
"10 POLYGON ((-73.99238 40.62021, -73.99240 40.620...\n",
"11 POLYGON ((-73.95369 40.62343, -73.95366 40.623...\n",
" ... \n",
"1084686 POLYGON ((-73.92660 40.69698, -73.92664 40.696...\n",
"1084701 POLYGON ((-73.92774 40.67189, -73.92769 40.671...\n",
"1084715 POLYGON ((-73.97999 40.69009, -73.98005 40.690...\n",
"1084720 POLYGON ((-73.90890 40.68635, -73.90904 40.686...\n",
"1084743 POLYGON ((-73.95498 40.61268, -73.95502 40.612...\n",
"Name: geometry, Length: 207690, dtype: geometry"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ser.cx[slice(-74.0, -73.9), slice(40.6, 40.7)]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" \n",
"*** Profile stats marshalled to file '/tmp/tmpwbfr23qx'. \n",
"Opening SnakeViz in a new tab...\n"
]
}
],
"source": [
"%%snakeviz -t\n",
"ser.cxi[slice(-74.0, -73.9), slice(40.6, 40.7)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define regions to time"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"regions = [\n",
" (slice(-75.0, -73.0), slice(40.0, 41.0)),\n",
" (slice(-74.2, -73.7), slice(40.5, 40.9)),\n",
" (slice(-74.1, -73.8), slice(40.6, 40.8)),\n",
" (slice(-74.0, -73.9), slice(40.6, 40.65)),\n",
" (slice(-74.0, -73.99), slice(40.6, 40.61)),\n",
"]\n",
"region_names = [\"all\", \"most\", \"half\", \"small\", \"very small\"]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"all : 100.0\n",
"most : 98.21497876467275\n",
"half : 56.16285426398181\n",
"small : 11.031768639565467\n",
"very small : 0.2549898640146246\n"
]
}
],
"source": [
"for name, (slice_x, slice_y) in zip(region_names, regions):\n",
" sub = ser.cx[slice_x, slice_y]\n",
" print(name, \" : \", len(sub) / len(ser) * 100)\n",
" #sub.plot(figsize=(10, 8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Time `cx` for each region"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"179 ms ± 3.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"923 ms ± 13.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"176 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"904 ms ± 9.33 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"138 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"524 ms ± 7.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"104 ms ± 6.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"121 ms ± 6.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"78.5 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"3.74 ms ± 603 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"subset_times = []\n",
"ser = buildings.geometry\n",
"for name, (slice_x, slice_y) in zip(region_names, regions):\n",
" # Sanity check\n",
" assert(len(ser.cx[slice_x, slice_y]) == len(ser.cxi[slice_x, slice_y]))\n",
" \n",
" # Benchmark geopandas GeoSeries.cx\n",
" gp_timing = %timeit -o ser.cx[slice_x, slice_y]\n",
" subset_times.append(('geopandas', name, gp_timing.average))\n",
" \n",
" # Benchmark geopandas GeoSeries.cx using spatial index\n",
" # Benchmark spatialpandas GeometryArray.cx\n",
" sp_timing = %timeit -o ser.cxi[slice_x, slice_y]\n",
" subset_times.append(('geopandas+sindex', name, sp_timing.average))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Build timing results DataFrame"
]
},
{
"cell_type": "code",
"execution_count": 20,
"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>library</th>\n",
" <th>name</th>\n",
" <th>time</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>geopandas</td>\n",
" <td>all</td>\n",
" <td>0.179391</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>all</td>\n",
" <td>0.923043</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>geopandas</td>\n",
" <td>most</td>\n",
" <td>0.176028</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>most</td>\n",
" <td>0.903701</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>geopandas</td>\n",
" <td>half</td>\n",
" <td>0.138013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>half</td>\n",
" <td>0.523836</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>geopandas</td>\n",
" <td>small</td>\n",
" <td>0.103554</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>small</td>\n",
" <td>0.121244</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>geopandas</td>\n",
" <td>very small</td>\n",
" <td>0.078471</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>very small</td>\n",
" <td>0.003740</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" library name time\n",
"0 geopandas all 0.179391\n",
"1 geopandas+sindex all 0.923043\n",
"2 geopandas most 0.176028\n",
"3 geopandas+sindex most 0.903701\n",
"4 geopandas half 0.138013\n",
"5 geopandas+sindex half 0.523836\n",
"6 geopandas small 0.103554\n",
"7 geopandas+sindex small 0.121244\n",
"8 geopandas very small 0.078471\n",
"9 geopandas+sindex very small 0.003740"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"timing_df = pd.DataFrame(subset_times, columns=['library', 'name', 'time'])\n",
"timing_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot results"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"import seaborn\n",
"seaborn.set_context(\"talk\")\n",
"seaborn.set_style(\"ticks\")"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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kKdbrkVEREREnEnhWkRERETESRSuRUREREScROFaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnETjXIuIiIiIOIlarkVEREREnEThWkRERETESRSuRbJAvahERETkRhSus1H//v15/PHHAThx4gSBgYFs3LjR3KLktv3www8MGjTI7DJyndatW/Pyyy/f0TmmT59OtWrV7OsxMTEMHjyYWrVqUb9+fSIjI++0TMlG+l2YN+g+ixhczS5AJLdYu3Ytf/31l9llCPDxxx+zc+dOXn31VSpXrkypUqXMLklERARQuBaRXOjSpUsAPProo1gsFnOLERERSUfdQu5AXFwckyZNol27dtSoUYM6derwxBNP8Pvvv5td2j2tdevWzJo1i/Hjx9OgQQPq1avHG2+8QXx8PGFhYTRs2JCGDRvy8ssvk5CQABhhbPz48bRu3ZqaNWsSEhLC9u3bHc67d+9eHnnkEWrXrk39+vUZPHgwR44cAeCll15i7dq1nDx5ksDAQNatW3fXP3dulpSUxIQJE2jSpAn3338/TzzxhENXjtWrVxMSEsL9999PUFAQPXv25NNPP830XP379+fdd98FoEqVKrz00kt34yPcE3755Rcee+wx6tatS+3atXn88cf58ccfAeO/8UGDBrF8+XJat25NrVq1eOKJJzh37hxr166lTZs29mNOnDhhP2de/j04evRomjdvTmpqqsP2MWPG0Lp1a/szGt999x19+/alVq1aNGzYkLFjx3L58mX7/uvWraNmzZqsWrWKJk2a0LJlS5YsWUJgYGCGLk8rV66kRo0a9i+Y17rRPQbdZ5G7QeH6DowcOZINGzYwaNAgFi5cyOjRozl8+DChoaF68C2bzZ8/n0uXLjFt2jR69erF8uXL6dmzJ6dPn2by5Mn07t2btWvXsnz5cuLj43n00Uf59NNPefbZZ5kxYwYVKlTgv//9Lxs2bAAgMjKSwYMHU6NGDWbPns2bb75JeHg4gwYNwmazMXjwYFq3bk3RokVZvXo1LVu2NPXz5zYff/wx4eHhhIWF8dprr/Hzzz8zYsQIAJYsWcK4ceNo164dc+fOZfLkybi6ujJixAjOnDmT4VyvvfYavXr1AoxQPnjw4Lv6WXKrmJgYnnzySQoVKsT06dN55513iI+P58knnyQmJgYwQuBHH33EK6+8wquvvsq+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RO6In59fhm3u7u6kpqYC4ObmxhdffMHOnTs5evQox48fJyoqCjD6Y6dXuHBhh3UXF5dMr+Hi4mI/NiIiAoAXXnjhujVevHgRf3//rHwsERGR26JwLSJ3JP1Dhdey2Wy8+OKLbN68mbp161K7dm169epF/fr1eeyxxzLsf73W5bSHHjOTFuLHjx9P6dKlM92nQIECN/oIIiIiTqNwLSLZZv/+/WzevJnBgwczdOhQ+/bk5GQuXbpEmTJl7vgapUqVAozW7SZNmji89+2335Kamoq7u/sdX0dERORWaJxrEck2ly5dAqBSpUoO2z/88EPi4+NJTk6+42s0adIEDw8P5s+f79C3+8yZMwwePJjJkyffsOVbRETEmdRyLSLZpnbt2vj4+PD2229z6tQpfH19+fbbb9myZQseHh7Exsbe8TX8/PwYPnw4b7/9Nr169aJbt24kJyezYsUKEhISGDVqlBM+iYiIyK1RuBaRbFOkSBHmzZvH5MmTmTVrFu7u7pQvX56pU6fy008/sWTJEs6fP0+RIkXu6DqPP/44xYoV44MPPuCdd97B09OT6tWrM2nSJOrWreukTyMiInJzGudaRERERMRJ1OdaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnEThWkRERETESRSuRUREREScROFaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnOT/AXUqn7IRQkxhAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 738.775x360 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"g = seaborn.relplot(data=timing_df, x=\"name\", y=\"time\", hue=\"library\", kind=\"line\", height=5, aspect=1.5)\n",
"g.ax.grid()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Overview\n",
"\n",
"Based on a notebook of Jon Mease (https://anaconda.org/jonmmease/cx_benchmarking_pr/notebook), originally benchmarking this for the spatialpandas library.\n"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import geopandas\n",
"import numpy as np\n",
"import pandas as pd\n",
"\n",
"%matplotlib inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load dataset"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Building footprints from https://data.cityofnewyork.us/Housing-Development/Building-Footprints/nqwf-w8eh"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"CPU times: user 1min 5s, sys: 3.34 s, total: 1min 8s\n",
"Wall time: 1min 8s\n"
]
},
{
"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>base_bbl</th>\n",
" <th>bin</th>\n",
" <th>cnstrct_yr</th>\n",
" <th>doitt_id</th>\n",
" <th>feat_code</th>\n",
" <th>geomsource</th>\n",
" <th>groundelev</th>\n",
" <th>heightroof</th>\n",
" <th>date_lstmo</th>\n",
" <th>time_lstmo</th>\n",
" <th>lststatype</th>\n",
" <th>mpluto_bbl</th>\n",
" <th>name</th>\n",
" <th>shape_area</th>\n",
" <th>shape_len</th>\n",
" <th>geometry</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>3044520815</td>\n",
" <td>3394646.0</td>\n",
" <td>2009.0</td>\n",
" <td>1212853.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>18.0</td>\n",
" <td>21.608508</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3044520815</td>\n",
" <td>None</td>\n",
" <td>854.662433</td>\n",
" <td>125.079796</td>\n",
" <td>POLYGON ((-73.87130 40.65717, -73.87136 40.657...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>4030640041</td>\n",
" <td>4548330.0</td>\n",
" <td>1930.0</td>\n",
" <td>1226227.0</td>\n",
" <td>5110.0</td>\n",
" <td>Photogramm</td>\n",
" <td>122.0</td>\n",
" <td>10.360000</td>\n",
" <td>2017-08-17</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>4030640041</td>\n",
" <td>None</td>\n",
" <td>217.594243</td>\n",
" <td>60.225858</td>\n",
" <td>POLYGON ((-73.87671 40.71425, -73.87677 40.714...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>4139430001</td>\n",
" <td>4460479.0</td>\n",
" <td>1960.0</td>\n",
" <td>581946.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>10.0</td>\n",
" <td>29.811570</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>4139430001</td>\n",
" <td>None</td>\n",
" <td>946.427476</td>\n",
" <td>123.141941</td>\n",
" <td>POLYGON ((-73.85195 40.66235, -73.85195 40.662...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>3049720006</td>\n",
" <td>3355684.0</td>\n",
" <td>1920.0</td>\n",
" <td>858061.0</td>\n",
" <td>5110.0</td>\n",
" <td>Photogramm</td>\n",
" <td>32.0</td>\n",
" <td>11.200000</td>\n",
" <td>2017-08-17</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3049720006</td>\n",
" <td>None</td>\n",
" <td>248.678169</td>\n",
" <td>63.940817</td>\n",
" <td>POLYGON ((-73.94029 40.64108, -73.94034 40.641...</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>3055100055</td>\n",
" <td>3131737.0</td>\n",
" <td>1915.0</td>\n",
" <td>568078.0</td>\n",
" <td>2100.0</td>\n",
" <td>Photogramm</td>\n",
" <td>44.0</td>\n",
" <td>24.980000</td>\n",
" <td>2017-08-22</td>\n",
" <td>00:00:00.000</td>\n",
" <td>Constructed</td>\n",
" <td>3055100055</td>\n",
" <td>None</td>\n",
" <td>1163.227669</td>\n",
" <td>165.608763</td>\n",
" <td>POLYGON ((-73.98999 40.62384, -73.98998 40.623...</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" base_bbl bin cnstrct_yr doitt_id feat_code geomsource \\\n",
"0 3044520815 3394646.0 2009.0 1212853.0 2100.0 Photogramm \n",
"1 4030640041 4548330.0 1930.0 1226227.0 5110.0 Photogramm \n",
"2 4139430001 4460479.0 1960.0 581946.0 2100.0 Photogramm \n",
"3 3049720006 3355684.0 1920.0 858061.0 5110.0 Photogramm \n",
"4 3055100055 3131737.0 1915.0 568078.0 2100.0 Photogramm \n",
"\n",
" groundelev heightroof date_lstmo time_lstmo lststatype mpluto_bbl \\\n",
"0 18.0 21.608508 2017-08-22 00:00:00.000 Constructed 3044520815 \n",
"1 122.0 10.360000 2017-08-17 00:00:00.000 Constructed 4030640041 \n",
"2 10.0 29.811570 2017-08-22 00:00:00.000 Constructed 4139430001 \n",
"3 32.0 11.200000 2017-08-17 00:00:00.000 Constructed 3049720006 \n",
"4 44.0 24.980000 2017-08-22 00:00:00.000 Constructed 3055100055 \n",
"\n",
" name shape_area shape_len \\\n",
"0 None 854.662433 125.079796 \n",
"1 None 217.594243 60.225858 \n",
"2 None 946.427476 123.141941 \n",
"3 None 248.678169 63.940817 \n",
"4 None 1163.227669 165.608763 \n",
"\n",
" geometry \n",
"0 POLYGON ((-73.87130 40.65717, -73.87136 40.657... \n",
"1 POLYGON ((-73.87671 40.71425, -73.87677 40.714... \n",
"2 POLYGON ((-73.85195 40.66235, -73.85195 40.662... \n",
"3 POLYGON ((-73.94029 40.64108, -73.94034 40.641... \n",
"4 POLYGON ((-73.98999 40.62384, -73.98998 40.623... "
]
},
"execution_count": 1,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"%%time\n",
"buildings = geopandas.read_file(\"benchmark-data/Building Footprints/geo_export_e122dd5a-79ee-4afa-a717-e232a6fe1a72.shp\")\n",
"buildings.head()"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset contains 1084749 (multi)polygons\n"
]
}
],
"source": [
"print(f\"Dataset contains {len(buildings)} (multi)polygons\")"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([-74.25549541, 40.49842932, -73.70006247, 40.91505011])"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"buildings.total_bounds"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
"ser = buildings.geometry"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"3 POLYGON ((-73.94029 40.64108, -73.94034 40.641...\n",
"4 POLYGON ((-73.98999 40.62384, -73.98998 40.623...\n",
"8 POLYGON ((-73.94669 40.64494, -73.94689 40.644...\n",
"10 POLYGON ((-73.99238 40.62021, -73.99240 40.620...\n",
"11 POLYGON ((-73.95369 40.62343, -73.95366 40.623...\n",
" ... \n",
"1084686 POLYGON ((-73.92660 40.69698, -73.92664 40.696...\n",
"1084701 POLYGON ((-73.92774 40.67189, -73.92769 40.671...\n",
"1084715 POLYGON ((-73.97999 40.69009, -73.98005 40.690...\n",
"1084720 POLYGON ((-73.90890 40.68635, -73.90904 40.686...\n",
"1084743 POLYGON ((-73.95498 40.61268, -73.95502 40.612...\n",
"Name: geometry, Length: 207690, dtype: geometry"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"ser.cx[slice(-74.0, -73.9), slice(40.6, 40.7)]"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
" \n",
"*** Profile stats marshalled to file '/tmp/tmpwbfr23qx'. \n",
"Opening SnakeViz in a new tab...\n"
]
}
],
"source": [
"%%snakeviz -t\n",
"ser.cxi[slice(-74.0, -73.9), slice(40.6, 40.7)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Define regions to time"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"regions = [\n",
" (slice(-75.0, -73.0), slice(40.0, 41.0)),\n",
" (slice(-74.2, -73.7), slice(40.5, 40.9)),\n",
" (slice(-74.1, -73.8), slice(40.6, 40.8)),\n",
" (slice(-74.0, -73.9), slice(40.6, 40.65)),\n",
" (slice(-74.0, -73.99), slice(40.6, 40.61)),\n",
"]\n",
"region_names = [\"all\", \"most\", \"half\", \"small\", \"very small\"]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"all : 100.0\n",
"most : 98.21497876467275\n",
"half : 56.16285426398181\n",
"small : 11.031768639565467\n",
"very small : 0.2549898640146246\n"
]
}
],
"source": [
"for name, (slice_x, slice_y) in zip(region_names, regions):\n",
" sub = ser.cx[slice_x, slice_y]\n",
" print(name, \" : \", len(sub) / len(ser) * 100)\n",
" #sub.plot(figsize=(10, 8))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Time `cx` for each region"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"179 ms ± 3.08 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"923 ms ± 13.3 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"176 ms ± 1.18 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"904 ms ± 9.33 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"138 ms ± 1.16 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"524 ms ± 7.41 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"104 ms ± 6.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"121 ms ± 6.04 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"78.5 ms ± 1.84 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n",
"3.74 ms ± 603 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
]
}
],
"source": [
"subset_times = []\n",
"ser = buildings.geometry\n",
"for name, (slice_x, slice_y) in zip(region_names, regions):\n",
" # Sanity check\n",
" assert(len(ser.cx[slice_x, slice_y]) == len(ser.cxi[slice_x, slice_y]))\n",
" \n",
" # Benchmark geopandas GeoSeries.cx\n",
" gp_timing = %timeit -o ser.cx[slice_x, slice_y]\n",
" subset_times.append(('geopandas', name, gp_timing.average))\n",
" \n",
" # Benchmark geopandas GeoSeries.cx using spatial index\n",
" # Benchmark spatialpandas GeometryArray.cx\n",
" sp_timing = %timeit -o ser.cxi[slice_x, slice_y]\n",
" subset_times.append(('geopandas+sindex', name, sp_timing.average))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Build timing results DataFrame"
]
},
{
"cell_type": "code",
"execution_count": 20,
"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>library</th>\n",
" <th>name</th>\n",
" <th>time</th>\n",
" </tr>\n",
" </thead>\n",
" <tbody>\n",
" <tr>\n",
" <th>0</th>\n",
" <td>geopandas</td>\n",
" <td>all</td>\n",
" <td>0.179391</td>\n",
" </tr>\n",
" <tr>\n",
" <th>1</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>all</td>\n",
" <td>0.923043</td>\n",
" </tr>\n",
" <tr>\n",
" <th>2</th>\n",
" <td>geopandas</td>\n",
" <td>most</td>\n",
" <td>0.176028</td>\n",
" </tr>\n",
" <tr>\n",
" <th>3</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>most</td>\n",
" <td>0.903701</td>\n",
" </tr>\n",
" <tr>\n",
" <th>4</th>\n",
" <td>geopandas</td>\n",
" <td>half</td>\n",
" <td>0.138013</td>\n",
" </tr>\n",
" <tr>\n",
" <th>5</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>half</td>\n",
" <td>0.523836</td>\n",
" </tr>\n",
" <tr>\n",
" <th>6</th>\n",
" <td>geopandas</td>\n",
" <td>small</td>\n",
" <td>0.103554</td>\n",
" </tr>\n",
" <tr>\n",
" <th>7</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>small</td>\n",
" <td>0.121244</td>\n",
" </tr>\n",
" <tr>\n",
" <th>8</th>\n",
" <td>geopandas</td>\n",
" <td>very small</td>\n",
" <td>0.078471</td>\n",
" </tr>\n",
" <tr>\n",
" <th>9</th>\n",
" <td>geopandas+sindex</td>\n",
" <td>very small</td>\n",
" <td>0.003740</td>\n",
" </tr>\n",
" </tbody>\n",
"</table>\n",
"</div>"
],
"text/plain": [
" library name time\n",
"0 geopandas all 0.179391\n",
"1 geopandas+sindex all 0.923043\n",
"2 geopandas most 0.176028\n",
"3 geopandas+sindex most 0.903701\n",
"4 geopandas half 0.138013\n",
"5 geopandas+sindex half 0.523836\n",
"6 geopandas small 0.103554\n",
"7 geopandas+sindex small 0.121244\n",
"8 geopandas very small 0.078471\n",
"9 geopandas+sindex very small 0.003740"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"timing_df = pd.DataFrame(subset_times, columns=['library', 'name', 'time'])\n",
"timing_df"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Plot results"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {},
"outputs": [],
"source": [
"import seaborn\n",
"seaborn.set_context(\"talk\")\n",
"seaborn.set_style(\"ticks\")"
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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kKdbrkVEREREnEnhWkRERETESRSuRUREREScROFaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnETjXIuIiIiIOIlarkVEREREnEThWkRERETESRSuRbJAvahERETkRhSus1H//v15/PHHAThx4gSBgYFs3LjR3KLktv3www8MGjTI7DJyndatW/Pyyy/f0TmmT59OtWrV7OsxMTEMHjyYWrVqUb9+fSIjI++0TMlG+l2YN+g+ixhczS5AJLdYu3Ytf/31l9llCPDxxx+zc+dOXn31VSpXrkypUqXMLklERARQuBaRXOjSpUsAPProo1gsFnOLERERSUfdQu5AXFwckyZNol27dtSoUYM6derwxBNP8Pvvv5td2j2tdevWzJo1i/Hjx9OgQQPq1avHG2+8QXx8PGFhYTRs2JCGDRvy8ssvk5CQABhhbPz48bRu3ZqaNWsSEhLC9u3bHc67d+9eHnnkEWrXrk39+vUZPHgwR44cAeCll15i7dq1nDx5ksDAQNatW3fXP3dulpSUxIQJE2jSpAn3338/TzzxhENXjtWrVxMSEsL9999PUFAQPXv25NNPP830XP379+fdd98FoEqVKrz00kt34yPcE3755Rcee+wx6tatS+3atXn88cf58ccfAeO/8UGDBrF8+XJat25NrVq1eOKJJzh37hxr166lTZs29mNOnDhhP2de/j04evRomjdvTmpqqsP2MWPG0Lp1a/szGt999x19+/alVq1aNGzYkLFjx3L58mX7/uvWraNmzZqsWrWKJk2a0LJlS5YsWUJgYGCGLk8rV66kRo0a9i+Y17rRPQbdZ5G7QeH6DowcOZINGzYwaNAgFi5cyOjRozl8+DChoaF68C2bzZ8/n0uXLjFt2jR69erF8uXL6dmzJ6dPn2by5Mn07t2btWvXsnz5cuLj43n00Uf59NNPefbZZ5kxYwYVKlTgv//9Lxs2bAAgMjKSwYMHU6NGDWbPns2bb75JeHg4gwYNwmazMXjwYFq3bk3RokVZvXo1LVu2NPXz5zYff/wx4eHhhIWF8dprr/Hzzz8zYsQIAJYsWcK4ceNo164dc+fOZfLkybi6ujJixAjOnDmT4VyvvfYavXr1AoxQPnjw4Lv6WXKrmJgYnnzySQoVKsT06dN55513iI+P58knnyQmJgYwQuBHH33EK6+8wquvvsq+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RO6In59fhm3u7u6kpqYC4ObmxhdffMHOnTs5evQox48fJyoqCjD6Y6dXuHBhh3UXF5dMr+Hi4mI/NiIiAoAXXnjhujVevHgRf3//rHwsERGR26JwLSJ3JP1Dhdey2Wy8+OKLbN68mbp161K7dm169epF/fr1eeyxxzLsf73W5bSHHjOTFuLHjx9P6dKlM92nQIECN/oIIiIiTqNwLSLZZv/+/WzevJnBgwczdOhQ+/bk5GQuXbpEmTJl7vgapUqVAozW7SZNmji89+2335Kamoq7u/sdX0dERORWaJxrEck2ly5dAqBSpUoO2z/88EPi4+NJTk6+42s0adIEDw8P5s+f79C3+8yZMwwePJjJkyffsOVbRETEmdRyLSLZpnbt2vj4+PD2229z6tQpfH19+fbbb9myZQseHh7Exsbe8TX8/PwYPnw4b7/9Nr169aJbt24kJyezYsUKEhISGDVqlBM+iYiIyK1RuBaRbFOkSBHmzZvH5MmTmTVrFu7u7pQvX56pU6fy008/sWTJEs6fP0+RIkXu6DqPP/44xYoV44MPPuCdd97B09OT6tWrM2nSJOrWreukTyMiInJzGudaRERERMRJ1OdaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnEThWkRERETESRSuRUREREScROFaRERERMRJFK5FRERERJxE4VpERERExEkUrkVEREREnOT/AXUqn7IRQkxhAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 738.775x360 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"g = seaborn.relplot(data=timing_df, x=\"name\", y=\"time\", hue=\"library\", kind=\"line\", height=5, aspect=1.5)\n",
"g.ax.grid()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"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.9.1"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment