From f88fcb81ddb36995e5ea2d636452c5744ee16930 Mon Sep 17 00:00:00 2001 From: Paddy Mullen Date: Wed, 4 Oct 2023 23:30:57 -0400 Subject: [PATCH] Chore/analysis management exercise (#35) released 0.3.21 --- buckaroo/buckaroo_widget.py | 2 +- introduction.ipynb | 527 ++++++------------------------------ package.json | 2 +- pyproject.toml | 2 +- 4 files changed, 90 insertions(+), 443 deletions(-) diff --git a/buckaroo/buckaroo_widget.py b/buckaroo/buckaroo_widget.py index 1da6f31b..8c5255de 100644 --- a/buckaroo/buckaroo_widget.py +++ b/buckaroo/buckaroo_widget.py @@ -191,7 +191,7 @@ def handle_operations(self, change): #self.operations, this makes sure that machine_gen #cleaning code shows up too results['generated_py_code'] = self.generate_code(new_ops) - results['transformed_df'] = json.loads(self.transformed_df.to_json(orient='table', indent=2)) + results['transformed_df'] = df_to_obj(self.transformed_df) results['transform_error'] = False self.run_post_processing() except Exception as e: diff --git a/introduction.ipynb b/introduction.ipynb index f0d1fe22..041e647d 100644 --- a/introduction.ipynb +++ b/introduction.ipynb @@ -2,18 +2,9 @@ "cells": [ { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Intel MKL WARNING: Support of Intel(R) Streaming SIMD Extensions 4.2 (Intel(R) SSE4.2) enabled only processors has been deprecated. Intel oneAPI Math Kernel Library 2025.0 will require Intel(R) Advanced Vector Extensions (Intel(R) AVX) instructions.\n", - "Intel MKL WARNING: Support of Intel(R) Streaming SIMD Extensions 4.2 (Intel(R) SSE4.2) enabled only processors has been deprecated. Intel oneAPI Math Kernel Library 2025.0 will require Intel(R) Advanced Vector Extensions (Intel(R) AVX) instructions.\n" - ] - } - ], + "outputs": [], "source": [ "import pandas as pd\n", "import numpy as np\n", @@ -27,77 +18,7 @@ "outputs": [], "source": [ "df = pd.read_csv('/Users/paddy/code/citibike-play/2014-01 - Citi Bike trip data.csv')\n", - "BuckarooWidget(df[:10_000])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def sample(df, sample_size=500, include_outliers=True):\n", - " \n", - " sample_size = np.min([sample_size, len(df)])\n", - " sdf = df.sample(sample_size)\n", - " \n", - " \n", - " if include_outliers:\n", - " outlier_idxs = []\n", - " for col in df.columns:\n", - " idxs = df[col].sort_values().index\n", - " outlier_idxs.extend(idxs[:5])\n", - " outlier_idxs.extend(idxs[-5:])\n", - " outlier_idxs.extend(sdf.index)\n", - " uniq_idx = np.unique(outlier_idxs)\n", - " #print(uniq_idx)\n", - " return df.iloc[uniq_idx]\n", - " return sdf\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%timeit sample(df, 500)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%timeit sample(df, 10)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%timeit sample(df, 5000)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "len(sample(df))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df.iloc[[23,58, 1023]]" + "df" ] }, { @@ -106,103 +27,76 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df = pd.read_csv('./examples/data/2014-01-citibike-tripdata.csv')\n", - "w = BuckarooWidget(df)\n", + "w = BuckarooWidget(df, showCommands=False)\n", "w" ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "ab = df['tripduration']\n", - "ab.sort_values()" - ] - }, - { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "sorted_ab = ab.sort_values()\n", - "sorted_ab.index[:5]" + "# Adding a summary stat" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import numpy as np" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "np.unique([2,2,3])" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "df['start station name'].sort_values()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "np.array([2,2,3]).unique()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "a = []\n", - "a.extend([23,45], [32,5])\n", - "a" + "from buckaroo.pluggable_analysis_framework import (ColAnalysis)\n", + "from scipy.stats import skew\n", + "class Skew(ColAnalysis):\n", + " provided_summary = [\"skew\"]\n", + " requires_summary = []\n", + " \n", + " @staticmethod\n", + " def summary(sampled_ser, summary_ser, ser):\n", + " if pd.api.types.is_integer_dtype(sampled_ser):\n", + " return dict(skew=skew(sampled_ser.astype('int64')))\n", + " elif pd.api.types.is_float_dtype(sampled_ser):\n", + " return dict(skew=skew(sampled_ser.astype('float64')))\n", + " else:\n", + " return dict(skew=\"NA\")\n", + " summary_stats_display = [\n", + " 'dtype',\n", + " 'length',\n", + " 'nan_count',\n", + " 'distinct_count',\n", + " 'empty_count',\n", + " 'empty_per',\n", + " 'unique_per',\n", + " 'nan_per',\n", + " 'is_numeric',\n", + " 'is_integer',\n", + " 'is_datetime',\n", + " 'mode',\n", + " 'min',\n", + " 'max',\n", + " 'mean',\n", + " # we must add skew to the list of summary_stats_display, otherwise our new stat won't be displayed\n", + " 'skew']\n", + "w.add_analysis(Skew)" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "df.columns" + "w.stats.presentation_sdf" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "bc = df.sample(300)" + "# Making a new default dataframe display function" ] }, { @@ -210,36 +104,61 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [ - "bc.index" - ] + "source": [] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "arr = [2,3]\n", - "arr.extend(df.index)" + "from buckaroo.widget_utils import disable\n", + "from IPython.core.getipython import get_ipython\n", + "from IPython.display import display\n", + "import warnings\n", + "\n", + "disable()\n", + "def my_display_as_buckaroo(df):\n", + " w = BuckarooWidget(df, showCommands=False)\n", + " #the analysis we added throws warnings, let's muffle that when used as the default display\n", + " warnings.filterwarnings('ignore')\n", + " w.add_analysis(Skew)\n", + " warnings.filterwarnings('default')\n", + " return display(w)\n", + "\n", + "def my_enable():\n", + " \"\"\"\n", + " Automatically use buckaroo to display all DataFrames\n", + " instances in the notebook.\n", + "\n", + " \"\"\"\n", + " ip = get_ipython()\n", + " if ip is None:\n", + " print(\"must be running inside ipython to enable default display via enable()\")\n", + " return\n", + " ip_formatter = ip.display_formatter.ipython_display_formatter\n", + " ip_formatter.for_type(pd.DataFrame, my_display_as_buckaroo)\n", + "my_enable()" ] }, { "cell_type": "code", "execution_count": null, - "metadata": {}, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "df.iloc[[137, 137, 138]]" + "df" ] }, { - "cell_type": "code", - "execution_count": null, + "cell_type": "markdown", "metadata": {}, - "outputs": [], "source": [ - "pd.concat([df.iloc[sorted_ab.index[:5]], df[20:50]])" + "# Adding a Command to the Low Code UI" ] }, { @@ -290,282 +209,10 @@ ] }, { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - }, - { - "cell_type": "code", - "execution_count": 2, + "cell_type": "markdown", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.98543491, 0.88189975, 0.8519125 , 0.34405232, 0.64923551,\n", - " 0.76498397, 0.08317026, 0.33898759, 0.8959272 , 0.84532194,\n", - " 0.61846565, 0.97065402, 0.33760845, 0.14928914, 0.46931127,\n", - " 0.44402314, 0.3851214 , 0.30878261, 0.15215036, 0.30283917,\n", - " 0.34619956, 0.94479008, 0.52277332, 0.46966805, 0.01990334,\n", - " 0.0090225 , 0.18186927, 0.67424679, 0.38775559, 0.48266829,\n", - " 0.83345845, 0.7639416 , 0.71366249, 0.40440437, 0.0687034 ,\n", - " 0.99350699, 0.02384897, 0.61694475, 0.16986129, 0.76552384,\n", - " 0.49479425, 0.50517121, 0.80248113, 0.38342123, 0.25053957,\n", - " 0.09369322, 0.53027412, 0.80884121, 0.96754405, 0.10643695,\n", - " 0.30732228, 0.09244387, 0.75280274, 0.66100238, 0.21485027,\n", - " 0.74945128, 0.45370822, 0.88729706, 0.18465771, 0.01511092,\n", - " 0.13943961, 0.68186614, 0.68525074, 0.90057088, 0.58703984,\n", - " 0.47070748, 0.85631468, 0.48696279, 0.94382412, 0.91341682,\n", - " 0.85296105, 0.05317179, 0.68182398, 0.13682457, 0.43423833,\n", - " 0.98276478, 0.26740801, 0.73420044, 0.80780702, 0.476105 ,\n", - " 0.587292 , 0.00186236, 0.81152695, 0.42044342, 0.13466556,\n", - " 0.76170374, 0.52000642, 0.93240774, 0.97551015, 0.65619746,\n", - " 0.81113788, 0.90734312, 0.76348578, 0.15419325, 0.56967834,\n", - " 0.89901476, 0.87296504, 0.6050323 , 0.87922915, 0.58874466])" - ] - }, - "execution_count": 2, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.random.rand(1,100)[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.12371643, 0.27411337, 0.44275076, 0.21505491, 0.57833314])" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "np.random.random_sample(5)" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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fvOb3xhJ5tlnnw2af+yxx0xSUpLZvHmz+eMf/2i+8IUvmKysLPO3v/3NWTNt2jRz7bXXml27dplXXnnFXHHFFebuu+/u5U66Lz8/36xfv94cPHjQ1NXVmdtuu82MGDHCnD592llz3333mczMTLNjxw6zd+9ec/3115vJkyc78925r0eS559/3rzwwgvmjTfeMEePHjXf+973TFxcnDl48KAxJvr6/SACTA9t3brVXH311ebQoUMdAsyPf/xjM2TIEOP3+52xhx56yFx11VXO9pe//GUzY8aMoGNOmjTJfPOb3wx77aHw3HPPGZfLZVpaWowx/aPn8vJyk5WV5WxHc8/r16/vNMBs3brVxMTEGJ/P54w9+eSTxuPxOD+HBx980IwZMyZov6985SsmPz8/rDWHysSJE01xcbGz3draajIyMsyyZcv6sKrQ+HCAaWtrM+np6ebxxx93xpqamozb7Ta/+MUvjDHGHD582Egye/bscda8+OKLxuVymXfffbfXav97NDQ0GEnm5ZdfNsZc6DEuLs4888wzzpojR44YSaa6utoY0737eqQbMmSI+bd/+7eo75eXkHqgvr5es2fP1r//+78rMTGxw3x1dbVuvvlmxcfHO2P5+fk6evSo3nvvPWdNbm5u0H75+fmqrq4Ob/Eh0NjYqI0bN2ry5MmKi4uTFP09S9KpU6eUkpLibPeHnj+surpa48aNC/ogyfz8fDU3N+vQoUPOGlt7bmlpUW1tbVD9MTExys3NtaL+njp27Jh8Pl9Qv0lJSZo0aZLTb3V1tZKTk5Wdne2syc3NVUxMjGpqanq95ktx6tQpSXIev7W1tQoEAkF9X3311RoxYkRQ3xe7r0eq1tZWPf300zpz5oxycnKivl8CTDcZY3TvvffqvvvuC3pAf5DP5+vwScHt2z6fr8s17fOR6KGHHtKgQYM0dOhQnThxQs8995wzF609t/vzn/+siooKffOb33TGor3nzvw9PTc3N+tvf/tb7xR6if73f/9Xra2tUXWbdaW9p6769fl8Sk1NDZofMGCAUlJSrPiZtLW1ae7cubrhhhs0duxYSRd6io+P7/A+rw/3fbH7eqQ5cOCALrvsMrndbt1333169tlnNXr06Kjtt12/DzDz58+Xy+Xq8utPf/qTKioq9P7776usrKyvS/67dbfndvPmzdO+fftUWVmp2NhYfe1rX5Ox7AOce9qzJL377ruaNm2avvSlL2n27Nl9VPmlu5SegWhRXFysgwcP6umnn+7rUsLuqquuUl1dnWpqanT//ferqKhIhw8f7uuywi5i/xZSb3nggQd07733drnmk5/8pHbu3Knq6uoOf0MiOztbhYWF+tnPfqb09PQO7+5u305PT3e+d7amfb43dLfndsOGDdOwYcP06U9/WqNGjVJmZqZ27dqlnJycqO355MmTuvXWWzV58mStW7cuaF209tyV9PT0DlfkdLdnj8ejgQMHdrPqvjFs2DDFxsb2+W3WW9p7qq+v1/Dhw53x+vp6jR8/3lnT0NAQtN/58+fV2NgY8T+TkpISbdmyRVVVVfrEJz7hjKenp6ulpUVNTU1Bz0p88Hbuzn090sTHx+uKK66QJE2YMEF79uzRE088oa985StR2a+jr9+EY4u33nrLHDhwwPnavn27kWR+/etfm7ffftsY8/9v7mx/g6sxxpSVlXV4c+fnP//5oGPn5ORE/Js727311ltGknnppZeMMdHZ8zvvvGOuvPJKU1BQYM6fP99hPhp7bnexN/F+8Iqcn/zkJ8bj8Zhz584ZYy68iXfs2LFB+919991WvYm3pKTE2W5tbTUf//jHo/pNvCtWrHDGTp061embePfu3eus2b59e0S/ibetrc0UFxebjIwM88Ybb3SYb39T669//Wtn7E9/+lOnb2rt6r4e6W699VZTVFQU9f0SYC7RsWPHOlyF1NTUZNLS0sw999xjDh48aJ5++mmTmJjY4fLaAQMGmBUrVpgjR46YRx55JGIvr921a5epqKgw+/btM8ePHzc7duwwkydPNp/61KecO3a09fzOO++YK664wkyZMsW888475r//+7+dr3bR1rMxF4Lpvn37zOLFi81ll11m9u3bZ/bt22fef/99Y8z/X2qZl5dn6urqzLZt28zHPvaxTi+jnjdvnjly5IhZs2aNdZdRu91us2HDBnP48GEzZ84ck5ycHHR1hk3ef/9953aUZFauXGn27dtn3nrrLWPMhcuok5OTzXPPPWf2799v7rjjjk4vo77uuutMTU2N+cMf/mCuvPLKiL6M+v777zdJSUnm97//fdBj9+zZs86a++67z4wYMcLs3LnT7N27t8NHQ3Tnvh5J5s+fb15++WVz7Ngxs3//fjN//nzjcrlMZWWlMSb6+v0gAswl6izAGGPMH//4R3PjjTcat9ttPv7xj5vHHnusw76/+tWvzKc//WkTHx9vxowZY1544YVeqrpn9u/fb2699VaTkpJi3G63ufzyy819991n3nnnnaB10dTz+vXrjaROvz4omno2xpiioqJOe25/ps0YY44fP26mT59uBg4caIYNG2YeeOABEwgEgo7z0ksvmfHjx5v4+HjzyU9+0qxfv753G/k7VVRUmBEjRpj4+HgzceJEs2vXrr4u6ZK99NJLnd6mRUVFxpgLz1YsWLDApKWlGbfbbaZMmWKOHj0adIy//vWv5u677zaXXXaZ8Xg85utf/7oTaiPRRz12P3g//Nvf/ma+9a1vmSFDhpjExERz1113Bf0PijHdu69Him984xtm5MiRJj4+3nzsYx8zU6ZMccKLMdHX7we5jLHs3ZgAAKDf6/dXIQEAAPsQYAAAgHUIMAAAwDoEGAAAYB0CDAAAsA4BBgAAWIcAAwAArEOAAQAA1iHAAAAA6xBgAACAdQgwAADAOgQYAABgnf8D9iExpIWQKPsAAAAASUVORK5CYII=", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "arr = np.random.standard_normal(5000) * 100\n", - "arr = arr.astype(int)\n", - "ser = pd.Series(arr)\n", - "ser.hist()" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([ 3, 17, 124, 501, 1079, 1483, 1123, 497, 156, 17])" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "populations, endpoints = np.histogram(arr, 10)\n", - "populations" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([-406. , -332.3, -258.6, -184.9, -111.2, -37.5, 36.2, 109.9,\n", - " 183.6, 257.3, 331. ])" - ] - }, - "execution_count": 32, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "endpoints" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['-406 -332',\n", - " '-332 -258',\n", - " '-258 -184',\n", - " '-184 -111',\n", - " '-111 -37',\n", - " '-37 36',\n", - " '36 109',\n", - " '109 183',\n", - " '183 257',\n", - " '257 331']" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "def histogram_labels(endpoints):\n", - " left = endpoints[0]\n", - " labels = []\n", - " for edge in endpoints[1:]:\n", - " labels.append(\"%d %d\" % (left, edge))\n", - " left = edge\n", - " return labels\n", - "histogram_labels(endpoints)" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "array([0.0006, 0.0034, 0.0248, 0.1002, 0.2158, 0.2966, 0.2246, 0.0994,\n", - " 0.0312, 0.0034])" - ] - }, - "execution_count": 42, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "normalized_pop = populations / populations.sum()\n", - "normalized_pop" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "{'-406 -332': 0.0006,\n", - " '-332 -258': 0.0034,\n", - " '-258 -184': 0.0248,\n", - " '-184 -111': 0.1002,\n", - " '-111 -37': 0.2158,\n", - " '-37 36': 0.2966,\n", - " '36 109': 0.2246,\n", - " '109 183': 0.0994,\n", - " '183 257': 0.0312,\n", - " '257 331': 0.0034}" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dict(zip( histogram_labels(endpoints), normalized_pop))" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": { - "tags": [] - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[{'name': '-406 -332', 'population': 0.0006},\n", - " {'name': '-332 -258', 'population': 0.0034},\n", - " {'name': '-258 -184', 'population': 0.0248},\n", - " {'name': '-184 -111', 'population': 0.1002},\n", - " {'name': '-111 -37', 'population': 0.2158},\n", - " {'name': '-37 36', 'population': 0.2966},\n", - " {'name': '36 109', 'population': 0.2246},\n", - " {'name': '109 183', 'population': 0.0994},\n", - " {'name': '183 257', 'population': 0.0312},\n", - " {'name': '257 331', 'population': 0.0034}]" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], "source": [ - "def histogram_formatted_dict(arr):\n", - " populations, endpoints = np.histogram(arr, 10)\n", - " labels = histogram_labels(endpoints)\n", - " normalized_pop = populations / populations.sum()\n", - " ret_histo = []\n", - " for label, pop in zip(labels, normalized_pop):\n", - " ret_histo.append({'name': label, 'population':pop})\n", - " return ret_histo\n", - "histogram_formatted_dict(arr)" + "Note that `groupby2` has been added to the commands" ] }, { diff --git a/package.json b/package.json index bdf4f5ed..4e04129d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "buckaroo", - "version": "0.2.28", + "version": "0.2.29", "description": "Fast Datagrid widget for the Jupyter Notebook and JupyterLab", "keywords": [ "jupyter", diff --git a/pyproject.toml b/pyproject.toml index 7e15146f..bebfe68f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ dependencies = [ "ipywidgets>=7.6.0,<9", "graphlib_backport>=1.0.0" ] -version = "0.3.20" +version = "0.3.21" [project.license] file = "LICENSE.txt"