4610 lines
139 KiB
Plaintext
4610 lines
139 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c59f6ef8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#| eval: false\n",
|
|
"! [ -e /content ] && pip install -Uqq fastai # upgrade fastai on colab"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "866a6043",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| default_exp tabular.core"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "7bf25495",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"from fastai.torch_basics import *\n",
|
|
"from fastai.data.all import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "7bd0e630",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"from nbdev.showdoc import *"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2638ab5a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"pd.set_option('mode.chained_assignment','raise')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "e1b505e9",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Tabular core\n",
|
|
"\n",
|
|
"> Basic function to preprocess tabular data before assembling it in a `DataLoaders`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "33f21224",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Initial preprocessing"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0bbabf95",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def make_date(df, date_field):\n",
|
|
" \"Make sure `df[date_field]` is of the right date type.\"\n",
|
|
" field_dtype = df[date_field].dtype\n",
|
|
" if isinstance(field_dtype, pd.core.dtypes.dtypes.DatetimeTZDtype):\n",
|
|
" field_dtype = np.datetime64\n",
|
|
" if not isinstance(field_dtype, np.dtype) or not np.issubdtype(field_dtype, np.datetime64):\n",
|
|
" df[date_field] = pd.to_datetime(df[date_field])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "fc4c8e6d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"df = pd.DataFrame({'date': ['2019-12-04', '2019-11-29', '2019-11-15', '2019-10-24']})\n",
|
|
"make_date(df, 'date')\n",
|
|
"test_eq(df['date'].dtype, np.dtype('datetime64[us]'))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2731eac6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def add_datepart(df, field_name, prefix=None, drop=True, time=False):\n",
|
|
" \"Helper function that adds columns relevant to a date in the column `field_name` of `df`.\"\n",
|
|
" make_date(df, field_name)\n",
|
|
" field = df[field_name]\n",
|
|
" prefix = ifnone(prefix, re.sub('[Dd]ate$', '', field_name))\n",
|
|
" attr = ['Year', 'Month', 'Week', 'Day', 'Dayofweek', 'Dayofyear', 'Is_month_end', 'Is_month_start',\n",
|
|
" 'Is_quarter_end', 'Is_quarter_start', 'Is_year_end', 'Is_year_start']\n",
|
|
" if time: attr = attr + ['Hour', 'Minute', 'Second']\n",
|
|
" # Pandas removed `dt.week` in v1.1.10\n",
|
|
" week = field.dt.isocalendar().week.astype(field.dt.day.dtype) if hasattr(field.dt, 'isocalendar') else field.dt.week\n",
|
|
" for n in attr: df[prefix + n] = getattr(field.dt, n.lower()) if n != 'Week' else week\n",
|
|
" mask = ~field.isna()\n",
|
|
" df[prefix + 'Elapsed'] = np.where(mask,field.values.astype(np.int64) // 10 ** 9,np.nan)\n",
|
|
" if drop: df.drop(field_name, axis=1, inplace=True)\n",
|
|
" return df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3d9ae5e0",
|
|
"metadata": {},
|
|
"source": [
|
|
"For example if we have a series of dates we can then generate features such as `Year`, `Month`, `Day`, `Dayofweek`, `Is_month_start`, etc as shown below:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "f24190a5",
|
|
"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>Year</th>\n",
|
|
" <th>Month</th>\n",
|
|
" <th>Week</th>\n",
|
|
" <th>Day</th>\n",
|
|
" <th>Dayofweek</th>\n",
|
|
" <th>Dayofyear</th>\n",
|
|
" <th>Is_month_end</th>\n",
|
|
" <th>Is_month_start</th>\n",
|
|
" <th>Is_quarter_end</th>\n",
|
|
" <th>Is_quarter_start</th>\n",
|
|
" <th>Is_year_end</th>\n",
|
|
" <th>Is_year_start</th>\n",
|
|
" <th>Elapsed</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>2019.0</td>\n",
|
|
" <td>12.0</td>\n",
|
|
" <td>49.0</td>\n",
|
|
" <td>4.0</td>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>338.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>1575417.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>2019.0</td>\n",
|
|
" <td>11.0</td>\n",
|
|
" <td>46.0</td>\n",
|
|
" <td>15.0</td>\n",
|
|
" <td>4.0</td>\n",
|
|
" <td>319.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>1573776.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>2019.0</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>43.0</td>\n",
|
|
" <td>24.0</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>297.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>1571875.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" Year Month Week ... Is_year_end Is_year_start Elapsed\n",
|
|
"0 2019.0 12.0 49.0 ... False False 1575417.0\n",
|
|
"1 NaN NaN NaN ... False False NaN\n",
|
|
"2 2019.0 11.0 46.0 ... False False 1573776.0\n",
|
|
"3 2019.0 10.0 43.0 ... False False 1571875.0\n",
|
|
"\n",
|
|
"[4 rows x 13 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df = pd.DataFrame({'date': ['2019-12-04', None, '2019-11-15', '2019-10-24']})\n",
|
|
"df = add_datepart(df, 'date')\n",
|
|
"df.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ebceaa3d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"test_eq(df.columns, ['Year', 'Month', 'Week', 'Day', 'Dayofweek', 'Dayofyear', 'Is_month_end', 'Is_month_start',\n",
|
|
" 'Is_quarter_end', 'Is_quarter_start', 'Is_year_end', 'Is_year_start', 'Elapsed'])\n",
|
|
"test_eq(df[df.Elapsed.isna()].shape,(1, 13))\n",
|
|
"\n",
|
|
"# Test that week dtype is consistent with other datepart fields\n",
|
|
"test_eq(df['Year'].dtype, df['Week'].dtype)\n",
|
|
"\n",
|
|
"test_eq(pd.api.types.is_numeric_dtype(df['Elapsed']), True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0f87626f",
|
|
"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>f1</th>\n",
|
|
" <th>f2</th>\n",
|
|
" <th>f3</th>\n",
|
|
" <th>f4</th>\n",
|
|
" <th>Year</th>\n",
|
|
" <th>Month</th>\n",
|
|
" <th>Week</th>\n",
|
|
" <th>Day</th>\n",
|
|
" <th>Dayofweek</th>\n",
|
|
" <th>Dayofyear</th>\n",
|
|
" <th>Is_month_end</th>\n",
|
|
" <th>Is_month_start</th>\n",
|
|
" <th>Is_quarter_end</th>\n",
|
|
" <th>Is_quarter_start</th>\n",
|
|
" <th>Is_year_end</th>\n",
|
|
" <th>Is_year_start</th>\n",
|
|
" <th>Elapsed</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>2.0</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>4.0</td>\n",
|
|
" <td>2019</td>\n",
|
|
" <td>12</td>\n",
|
|
" <td>49</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>338</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>1575417.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" f1 f2 f3 f4 ... Is_quarter_start Is_year_end Is_year_start Elapsed\n",
|
|
"0 1.0 2.0 3.0 4.0 ... False False False 1575417.0\n",
|
|
"\n",
|
|
"[1 rows x 17 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df = pd.DataFrame({'f1': [1.],'f2': [2.],'f3': [3.],'f4': [4.],'date':['2019-12-04']})\n",
|
|
"df = add_datepart(df, 'date')\n",
|
|
"df.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "edcd1107",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"# Test Order of columns when date isn't in first position\n",
|
|
"test_eq(df.columns, ['f1', 'f2', 'f3', 'f4', 'Year', 'Month', 'Week', 'Day',\n",
|
|
" 'Dayofweek', 'Dayofyear', 'Is_month_end', 'Is_month_start',\n",
|
|
" 'Is_quarter_end', 'Is_quarter_start', 'Is_year_end', 'Is_year_start', 'Elapsed'])\n",
|
|
"\n",
|
|
"# Test that week dtype is consistent with other datepart fields\n",
|
|
"test_eq(df['Year'].dtype, df['Week'].dtype)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4d78de59",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def _get_elapsed(df,field_names, date_field, base_field, prefix):\n",
|
|
" for f in field_names:\n",
|
|
" day1 = np.timedelta64(1, 'D')\n",
|
|
" last_date,last_base,res = np.datetime64(),None,[]\n",
|
|
" for b,v,d in zip(df[base_field].values, df[f].values, df[date_field].values):\n",
|
|
" if last_base is None or b != last_base:\n",
|
|
" last_date,last_base = np.datetime64(),b\n",
|
|
" if v: last_date = d\n",
|
|
" res.append(((d-last_date).astype('timedelta64[D]') / day1))\n",
|
|
" df[prefix + f] = res\n",
|
|
" return df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e3901ffe",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def add_elapsed_times(df, field_names, date_field, base_field):\n",
|
|
" \"Add in `df` for each event in `field_names` the elapsed time according to `date_field` grouped by `base_field`\"\n",
|
|
" field_names = list(L(field_names))\n",
|
|
" #Make sure date_field is a date and base_field a bool\n",
|
|
" df[field_names] = df[field_names].astype('bool')\n",
|
|
" make_date(df, date_field)\n",
|
|
"\n",
|
|
" work_df = df[field_names + [date_field, base_field]]\n",
|
|
" work_df = work_df.sort_values([base_field, date_field])\n",
|
|
" work_df = _get_elapsed(work_df, field_names, date_field, base_field, 'After')\n",
|
|
" work_df = work_df.sort_values([base_field, date_field], ascending=[True, False])\n",
|
|
" work_df = _get_elapsed(work_df, field_names, date_field, base_field, 'Before')\n",
|
|
"\n",
|
|
" for a in ['After' + f for f in field_names] + ['Before' + f for f in field_names]:\n",
|
|
" work_df[a] = work_df[a].fillna(0).astype(int)\n",
|
|
"\n",
|
|
" for a,s in zip([True, False], ['_bw', '_fw']):\n",
|
|
" work_df = work_df.set_index(date_field)\n",
|
|
" tmp = (work_df[[base_field] + field_names].sort_index(ascending=a)\n",
|
|
" .groupby(base_field).rolling(7, min_periods=1).sum())\n",
|
|
" if base_field in tmp: tmp.drop(base_field, axis=1,inplace=True)\n",
|
|
" tmp.reset_index(inplace=True)\n",
|
|
" work_df.reset_index(inplace=True)\n",
|
|
" work_df = work_df.merge(tmp, 'left', [date_field, base_field], suffixes=['', s])\n",
|
|
" work_df.drop(field_names, axis=1, inplace=True)\n",
|
|
" return df.merge(work_df, 'left', [date_field, base_field])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "a8cf138e",
|
|
"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>date</th>\n",
|
|
" <th>event</th>\n",
|
|
" <th>base</th>\n",
|
|
" <th>Afterevent</th>\n",
|
|
" <th>Beforeevent</th>\n",
|
|
" <th>event_bw</th>\n",
|
|
" <th>event_fw</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>2019-12-04</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>0.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>2019-11-29</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>2019-11-15</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>22</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>0.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>2019-10-24</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" <td>1.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" date event base Afterevent Beforeevent event_bw event_fw\n",
|
|
"0 2019-12-04 False 1 5 0 1.0 0.0\n",
|
|
"1 2019-11-29 True 1 0 0 1.0 1.0\n",
|
|
"2 2019-11-15 False 2 22 0 1.0 0.0\n",
|
|
"3 2019-10-24 True 2 0 0 1.0 1.0"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df = pd.DataFrame({'date': ['2019-12-04', '2019-11-29', '2019-11-15', '2019-10-24'],\n",
|
|
" 'event': [False, True, False, True], 'base': [1,1,2,2]})\n",
|
|
"df = add_elapsed_times(df, ['event'], 'date', 'base')\n",
|
|
"df.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6086b66b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def cont_cat_split(df, max_card=20, dep_var=None):\n",
|
|
" \"Helper function that returns column names of cont and cat variables from given `df`.\"\n",
|
|
" cont_names, cat_names = [], []\n",
|
|
" for label in df:\n",
|
|
" if label in L(dep_var): continue\n",
|
|
" if ((pd.api.types.is_integer_dtype(df[label].dtype) and\n",
|
|
" df[label].unique().shape[0] > max_card) or\n",
|
|
" pd.api.types.is_float_dtype(df[label].dtype)):\n",
|
|
" cont_names.append(label)\n",
|
|
" else: cat_names.append(label)\n",
|
|
" return cont_names, cat_names"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "03b5fefd",
|
|
"metadata": {},
|
|
"source": [
|
|
"This function works by determining if a column is continuous or categorical based on the cardinality of its values. If it is above the `max_card` parameter (or a `float` datatype) then it will be added to the `cont_names` else `cat_names`. An example is below:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0b252f06",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Example with simple numpy types\n",
|
|
"df = pd.DataFrame({'cat1': [1, 2, 3, 4], 'cont1': [1., 2., 3., 2.], 'cat2': ['a', 'b', 'b', 'a'],\n",
|
|
" 'i8': pd.Series([1, 2, 3, 4], dtype='int8'),\n",
|
|
" 'u8': pd.Series([1, 2, 3, 4], dtype='uint8'),\n",
|
|
" 'f16': pd.Series([1, 2, 3, 4], dtype='float16'),\n",
|
|
" 'y1': [1, 0, 1, 0], 'y2': [2, 1, 1, 0]})\n",
|
|
"cont_names, cat_names = cont_cat_split(df)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e573e687",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"cont_names: ['cont1', 'f16']\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"cat_names: ['cat1', 'cat2', 'i8', 'u8', 'y1', 'y2']`\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| echo: false\n",
|
|
"print(f'cont_names: {cont_names}\\ncat_names: {cat_names}`')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2ce5de4d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"# Test all columns\n",
|
|
"cont, cat = cont_cat_split(df)\n",
|
|
"test_eq((cont, cat), (['cont1', 'f16'], ['cat1', 'cat2', 'i8', 'u8', 'y1', 'y2']))\n",
|
|
"\n",
|
|
"# Test exclusion of dependent variable\n",
|
|
"cont, cat = cont_cat_split(df, dep_var='y1')\n",
|
|
"test_eq((cont, cat), (['cont1', 'f16'], ['cat1', 'cat2', 'i8', 'u8', 'y2']))\n",
|
|
"\n",
|
|
"# Test exclusion of multi-label dependent variables\n",
|
|
"cont, cat = cont_cat_split(df, dep_var=['y1', 'y2'])\n",
|
|
"test_eq((cont, cat), (['cont1', 'f16'], ['cat1', 'cat2', 'i8', 'u8']))\n",
|
|
"\n",
|
|
"# Test maximal cardinality bound for int variable\n",
|
|
"cont, cat = cont_cat_split(df, max_card=3)\n",
|
|
"test_eq((cont, cat), (['cat1', 'cont1', 'i8', 'u8', 'f16'], ['cat2', 'y1', 'y2']))\n",
|
|
"cont, cat = cont_cat_split(df, max_card=2)\n",
|
|
"test_eq((cont, cat), (['cat1', 'cont1', 'i8', 'u8', 'f16', 'y2'], ['cat2', 'y1']))\n",
|
|
"cont, cat = cont_cat_split(df, max_card=1)\n",
|
|
"test_eq((cont, cat), (['cat1', 'cont1', 'i8', 'u8', 'f16', 'y1', 'y2'], ['cat2']))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "bcde5c9a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Example with pandas types and generated columns\n",
|
|
"df = pd.DataFrame({'cat1': pd.Series(['l','xs','xl','s'], dtype='category'),\n",
|
|
" 'ui32': pd.Series([1, 2, 3, 4], dtype='UInt32'),\n",
|
|
" 'i64': pd.Series([1, 2, 3, 4], dtype='Int64'),\n",
|
|
" 'f16': pd.Series([1, 2, 3, 4], dtype='Float64'),\n",
|
|
" 'd1_date': ['2021-02-09', None, '2020-05-12', '2020-08-14'],\n",
|
|
" })\n",
|
|
"df = add_datepart(df, 'd1_date', drop=False)\n",
|
|
"df['cat1'] = df['cat1'].cat.set_categories(['xl','l','m','s','xs'], ordered=True)\n",
|
|
"cont_names, cat_names = cont_cat_split(df, max_card=0)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e5cdebe7",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"cont_names: ['ui32', 'i64', 'f16', 'd1_Year', 'd1_Month', 'd1_Week', 'd1_Day', 'd1_Dayofweek', 'd1_Dayofyear', 'd1_Elapsed']\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"cat_names: ['cat1', 'd1_date', 'd1_Is_month_end', 'd1_Is_month_start', 'd1_Is_quarter_end', 'd1_Is_quarter_start', 'd1_Is_year_end', 'd1_Is_year_start']\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| echo: false\n",
|
|
"print(f'cont_names: {cont_names}\\ncat_names: {cat_names}')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "8fcdf5b4",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"cont, cat = cont_cat_split(df, max_card=0)\n",
|
|
"test_eq((cont, cat), (\n",
|
|
" ['ui32', 'i64', 'f16', 'd1_Year', 'd1_Month', 'd1_Week', 'd1_Day', 'd1_Dayofweek', 'd1_Dayofyear', 'd1_Elapsed'],\n",
|
|
" ['cat1', 'd1_date', 'd1_Is_month_end', 'd1_Is_month_start', 'd1_Is_quarter_end', 'd1_Is_quarter_start', 'd1_Is_year_end', 'd1_Is_year_start']\n",
|
|
" ))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9a3b6c97",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def df_shrink_dtypes(df, skip=[], obj2cat=True, int2uint=False):\n",
|
|
" \"Return any possible smaller data types for DataFrame columns. Allows `object`->`category`, `int`->`uint`, and exclusion.\"\n",
|
|
"\n",
|
|
" # 1: Build column filter and typemap\n",
|
|
" excl_types, skip = {'category','datetime64[ns]','bool'}, set(skip)\n",
|
|
"\n",
|
|
" typemap = {'int' : [(np.dtype(x), np.iinfo(x).min, np.iinfo(x).max) for x in (np.int8, np.int16, np.int32, np.int64)],\n",
|
|
" 'uint' : [(np.dtype(x), np.iinfo(x).min, np.iinfo(x).max) for x in (np.uint8, np.uint16, np.uint32, np.uint64)],\n",
|
|
" 'float' : [(np.dtype(x), np.finfo(x).min, np.finfo(x).max) for x in (np.float32, np.float64, np.longdouble)]\n",
|
|
" }\n",
|
|
" if obj2cat: typemap['object'] = typemap['str'] = 'category'\n",
|
|
" else: excl_types.update({'object', 'str'})\n",
|
|
"\n",
|
|
" new_dtypes = {}\n",
|
|
" exclude = lambda dt: dt[1].name not in excl_types and dt[0] not in skip\n",
|
|
"\n",
|
|
" for c, old_t in filter(exclude, df.dtypes.items()):\n",
|
|
" t = next((v for k,v in typemap.items() if old_t.name.startswith(k)), None)\n",
|
|
"\n",
|
|
" if isinstance(t, list): # Find the smallest type that fits\n",
|
|
" if int2uint and t==typemap['int'] and df[c].min() >= 0: t=typemap['uint']\n",
|
|
" new_t = next((r[0] for r in t if r[1]<=df[c].min() and r[2]>=df[c].max()), None)\n",
|
|
" if new_t and new_t == old_t: new_t = None\n",
|
|
" else: new_t = t if isinstance(t, str) else None\n",
|
|
"\n",
|
|
" if new_t: new_dtypes[c] = new_t\n",
|
|
" return new_dtypes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2cf725eb",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/markdown": [
|
|
"---\n",
|
|
"\n",
|
|
"[source](https://github.com/fastai/fastai/blob/main/fastai/tabular/core.py#L99){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
|
|
"\n",
|
|
"### df_shrink_dtypes\n",
|
|
"\n",
|
|
"```python\n",
|
|
"\n",
|
|
"def df_shrink_dtypes(\n",
|
|
" df, skip:list=[], obj2cat:bool=True, int2uint:bool=False\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Return any possible smaller data types for DataFrame columns. Allows `object`->`category`, `int`->`uint`, and exclusion.*"
|
|
],
|
|
"text/plain": [
|
|
"```python\n",
|
|
"\n",
|
|
"def df_shrink_dtypes(\n",
|
|
" df, skip:list=[], obj2cat:bool=True, int2uint:bool=False\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Return any possible smaller data types for DataFrame columns. Allows `object`->`category`, `int`->`uint`, and exclusion.*"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"show_doc(df_shrink_dtypes, title_level=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "eb2e1776",
|
|
"metadata": {},
|
|
"source": [
|
|
"For example we will make a sample `DataFrame` with `int`, `float`, `bool`, and `object` datatypes:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "83c7879a",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"i int64\n",
|
|
"f float64\n",
|
|
"e bool\n",
|
|
"date str\n",
|
|
"dtype: object"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df = pd.DataFrame({'i': [-100, 0, 100], 'f': [-100.0, 0.0, 100.0], 'e': [True, False, True],\n",
|
|
" 'date':['2019-12-04','2019-11-29','2019-11-15',]})\n",
|
|
"df.dtypes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "fdf8e5cb",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can then call `df_shrink_dtypes` to find the smallest possible datatype that can support the data:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "aae29084",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'i': dtype('int8'), 'f': dtype('float32'), 'date': 'category'}"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"dt = df_shrink_dtypes(df)\n",
|
|
"dt"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1d33d1d8",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"test_eq(df['i'].dtype, 'int64')\n",
|
|
"test_eq(dt['i'], 'int8')\n",
|
|
"\n",
|
|
"test_eq(df['f'].dtype, 'float64')\n",
|
|
"test_eq(dt['f'], 'float32')\n",
|
|
"\n",
|
|
"test_eq(df['date'].dtype, 'str')\n",
|
|
"test_eq(dt['date'], 'category')\n",
|
|
"\n",
|
|
"dt2 = df_shrink_dtypes(df, obj2cat=False)\n",
|
|
"test_eq('date' not in dt2, True)\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "a97f5143",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def df_shrink(df, skip=[], obj2cat=True, int2uint=False):\n",
|
|
" \"Reduce DataFrame memory usage, by casting to smaller types returned by `df_shrink_dtypes()`.\"\n",
|
|
" dt = df_shrink_dtypes(df, skip, obj2cat=obj2cat, int2uint=int2uint)\n",
|
|
" return df.astype(dt)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "663c5991",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/markdown": [
|
|
"---\n",
|
|
"\n",
|
|
"[source](https://github.com/fastai/fastai/blob/main/fastai/tabular/core.py#L128){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
|
|
"\n",
|
|
"### df_shrink\n",
|
|
"\n",
|
|
"```python\n",
|
|
"\n",
|
|
"def df_shrink(\n",
|
|
" df, skip:list=[], obj2cat:bool=True, int2uint:bool=False\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Reduce DataFrame memory usage, by casting to smaller types returned by `df_shrink_dtypes()`.*"
|
|
],
|
|
"text/plain": [
|
|
"```python\n",
|
|
"\n",
|
|
"def df_shrink(\n",
|
|
" df, skip:list=[], obj2cat:bool=True, int2uint:bool=False\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Reduce DataFrame memory usage, by casting to smaller types returned by `df_shrink_dtypes()`.*"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"show_doc(df_shrink, title_level=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b57d6f90",
|
|
"metadata": {},
|
|
"source": [
|
|
"`df_shrink(df)` attempts to make a DataFrame uses less memory, by fit numeric columns into smallest datatypes. In addition:\n",
|
|
"\n",
|
|
" * `boolean`, `category`, `datetime64[ns]` dtype columns are ignored.\n",
|
|
" * 'object' type columns are categorified, which can save a lot of memory in large dataset. It can be turned off by `obj2cat=False`.\n",
|
|
" * `int2uint=True`, to fit `int` types to `uint` types, if all data in the column is >= 0.\n",
|
|
" * columns can be excluded by name using `excl_cols=['col1','col2']`.\n",
|
|
"\n",
|
|
"To get only new column data types without actually casting a DataFrame,\n",
|
|
"use `df_shrink_dtypes()` with all the same parameters for `df_shrink()`."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "03986bdf",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"df = pd.DataFrame({'i': [-100, 0, 100], 'f': [-100.0, 0.0, 100.0], 'u':[0, 10,254],\n",
|
|
" 'date':['2019-12-04','2019-11-29','2019-11-15']})\n",
|
|
"df2 = df_shrink(df, skip=['date'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "60ce3613",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's compare the two:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "de4b9958",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"i int64\n",
|
|
"f float64\n",
|
|
"u int64\n",
|
|
"date str\n",
|
|
"dtype: object"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df.dtypes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4cd57e5b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"i int8\n",
|
|
"f float32\n",
|
|
"u int16\n",
|
|
"date str\n",
|
|
"dtype: object"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df2.dtypes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b8999949",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can see that the datatypes changed, and even further we can look at their relative memory usages:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "470b8e60",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Initial Dataframe: 228 bytes\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Reduced Dataframe: 177 bytes\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| echo: false\n",
|
|
"print(f'Initial Dataframe: {df.memory_usage().sum()} bytes')\n",
|
|
"print(f'Reduced Dataframe: {df2.memory_usage().sum()} bytes')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "caa0a883",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"test_eq(df['i'].dtype=='int64' and df2['i'].dtype=='int8', True)\n",
|
|
"test_eq(df['f'].dtype=='float64' and df2['f'].dtype=='float32', True)\n",
|
|
"test_eq(df['u'].dtype=='int64' and df2['u'].dtype=='int16', True)\n",
|
|
"test_eq(df2['date'].dtype, 'str')\n",
|
|
"\n",
|
|
"test_eq(df2.memory_usage().sum() < df.memory_usage().sum(), True)\n",
|
|
"\n",
|
|
"# Test int => uint (when col.min() >= 0)\n",
|
|
"df3 = df_shrink(df, int2uint=True)\n",
|
|
"test_eq(df3['u'].dtype, 'uint8') # int64 -> uint8 instead of int16\n",
|
|
"\n",
|
|
"# Test excluding columns\n",
|
|
"df4 = df_shrink(df, skip=['i','u'])\n",
|
|
"test_eq(df['i'].dtype, df4['i'].dtype)\n",
|
|
"test_eq(df4['u'].dtype, 'int64')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f17bcf7d",
|
|
"metadata": {},
|
|
"source": [
|
|
"Here's another example using the `ADULT_SAMPLE` dataset:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d770bbbd",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = untar_data(URLs.ADULT_SAMPLE)\n",
|
|
"df = pd.read_csv(path/'adult.csv')\n",
|
|
"new_df = df_shrink(df, int2uint=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "92caa755",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Initial Dataframe: 3.907452 megabytes\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Reduced Dataframe: 0.814989 megabytes\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| echo: false\n",
|
|
"print(f'Initial Dataframe: {df.memory_usage().sum() / 1000000} megabytes')\n",
|
|
"print(f'Reduced Dataframe: {new_df.memory_usage().sum() / 1000000} megabytes')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "471a2a21",
|
|
"metadata": {},
|
|
"source": [
|
|
"We reduced the overall memory used by 79%!"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "21299434",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Tabular -"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d3046984",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class _TabIloc:\n",
|
|
" \"Get/set rows by iloc and cols by name\"\n",
|
|
" def __init__(self,to): self.to = to\n",
|
|
" def __getitem__(self, idxs):\n",
|
|
" df = self.to.items\n",
|
|
" if isinstance(idxs,tuple):\n",
|
|
" rows,cols = idxs\n",
|
|
" cols = df.columns.isin(cols) if is_listy(cols) else df.columns.get_loc(cols)\n",
|
|
" else: rows,cols = idxs,slice(None)\n",
|
|
" return self.to.new(df.iloc[rows, cols])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "498b3f92",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class Tabular(CollBase, GetAttr, FilteredBase):\n",
|
|
" \"A `DataFrame` wrapper that knows which cols are cont/cat/y, and returns rows in `__getitem__`\"\n",
|
|
" _default,with_cont='procs',True\n",
|
|
" def __init__(self, df, procs=None, cat_names=None, cont_names=None, y_names=None, y_block=None, splits=None,\n",
|
|
" do_setup=True, device=None, inplace=False, reduce_memory=True):\n",
|
|
" if inplace and splits is not None and pd.options.mode.chained_assignment is not None:\n",
|
|
" warn(\"Using inplace with splits will trigger a pandas error. Set `pd.options.mode.chained_assignment=None` to avoid it.\")\n",
|
|
" if not inplace: df = df.copy()\n",
|
|
" if reduce_memory: df = df_shrink(df)\n",
|
|
" if splits is not None: df = df.iloc[sum(splits, [])]\n",
|
|
" self.dataloaders = delegates(self._dl_type.__init__)(self.dataloaders)\n",
|
|
" super().__init__(df)\n",
|
|
"\n",
|
|
" self.y_names,self.device = L(y_names),device\n",
|
|
" if y_block is None and self.y_names:\n",
|
|
" # Make ys categorical if they're not numeric\n",
|
|
" ys = df[self.y_names]\n",
|
|
" if len(ys.select_dtypes(include='number').columns)!=len(ys.columns): y_block = CategoryBlock()\n",
|
|
" else: y_block = RegressionBlock()\n",
|
|
" if y_block is not None and do_setup:\n",
|
|
" if callable(y_block): y_block = y_block()\n",
|
|
" procs = L(procs) + y_block.type_tfms\n",
|
|
" self.cat_names,self.cont_names,self.procs = L(cat_names),L(cont_names),Pipeline(procs)\n",
|
|
" self.split = len(df) if splits is None else len(splits[0])\n",
|
|
" if do_setup: self.setup()\n",
|
|
"\n",
|
|
" def new(self, df, inplace=False):\n",
|
|
" return type(self)(df, do_setup=False, reduce_memory=False, y_block=TransformBlock(), inplace=inplace,\n",
|
|
" **attrdict(self, 'procs','cat_names','cont_names','y_names', 'device'))\n",
|
|
"\n",
|
|
" def subset(self, i): return self.new(self.items[slice(0,self.split) if i==0 else slice(self.split,len(self))])\n",
|
|
" def copy(self): self.items = self.items.copy(); return self\n",
|
|
" def decode(self): return self.procs.decode(self)\n",
|
|
" def decode_row(self, row): return self.new(pd.DataFrame(row).T).decode().items.iloc[0]\n",
|
|
" def show(self, max_n=10, **kwargs): display_df(self.new(self.all_cols[:max_n]).decode().items)\n",
|
|
" def setup(self): self.procs.setup(self)\n",
|
|
" def process(self): self.procs(self)\n",
|
|
" def loc(self): return self.items.loc\n",
|
|
" def iloc(self): return _TabIloc(self)\n",
|
|
" def targ(self): return self.items[self.y_names]\n",
|
|
" def x_names (self): return self.cat_names + self.cont_names\n",
|
|
" def n_subsets(self): return 2\n",
|
|
" def y(self): return self[self.y_names[0]]\n",
|
|
" def new_empty(self): return self.new(pd.DataFrame({}, columns=self.items.columns))\n",
|
|
" def to_device(self, d=None):\n",
|
|
" self.device = d\n",
|
|
" return self\n",
|
|
"\n",
|
|
" def all_col_names (self):\n",
|
|
" ys = [n for n in self.y_names if n in self.items.columns]\n",
|
|
" return self.x_names + self.y_names if len(ys) == len(self.y_names) else self.x_names\n",
|
|
"\n",
|
|
"properties(Tabular,'loc','iloc','targ','all_col_names','n_subsets','x_names','y')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c5a5cf34",
|
|
"metadata": {},
|
|
"source": [
|
|
"* `df`: A `DataFrame` of your data\n",
|
|
"* `cat_names`: Your categorical `x` variables\n",
|
|
"* `cont_names`: Your continuous `x` variables\n",
|
|
"* `y_names`: Your dependent `y` variables\n",
|
|
" * Note: Mixed y's such as Regression and Classification is not currently supported, however multiple regression or classification outputs is\n",
|
|
"* `y_block`: How to sub-categorize the type of `y_names` (`CategoryBlock` or `RegressionBlock`)\n",
|
|
"* `splits`: How to split your data\n",
|
|
"* `do_setup`: A parameter for if `Tabular` will run the data through the `procs` upon initialization\n",
|
|
"* `device`: `cuda` or `cpu`\n",
|
|
"* `inplace`: If `True`, `Tabular` will not keep a separate copy of your original `DataFrame` in memory. You should ensure `pd.options.mode.chained_assignment` is `None` before setting this\n",
|
|
"* `reduce_memory`: `fastai` will attempt to reduce the overall memory usage by the inputted `DataFrame` with `df_shrink`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e23698c9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class TabularPandas(Tabular):\n",
|
|
" \"A `Tabular` object with transforms\"\n",
|
|
" def transform(self, cols, f, all_col=True):\n",
|
|
" if not all_col: cols = [c for c in cols if c in self.items.columns]\n",
|
|
" if len(cols) > 0: self[cols] = self[cols].transform(f)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "efdb998b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def _add_prop(cls, nm):\n",
|
|
" @property\n",
|
|
" def f(o): return o[list(getattr(o,nm+'_names'))]\n",
|
|
" @f.setter\n",
|
|
" def fset(o, v): o[getattr(o,nm+'_names')] = v\n",
|
|
" setattr(cls, nm+'s', f)\n",
|
|
" setattr(cls, nm+'s', fset)\n",
|
|
"\n",
|
|
"_add_prop(Tabular, 'cat')\n",
|
|
"_add_prop(Tabular, 'cont')\n",
|
|
"_add_prop(Tabular, 'y')\n",
|
|
"_add_prop(Tabular, 'x')\n",
|
|
"_add_prop(Tabular, 'all_col')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "372c322d",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,0,2], 'b':[0,0,0,0,1]})\n",
|
|
"to = TabularPandas(df, cat_names='a')\n",
|
|
"t = pickle.loads(pickle.dumps(to))\n",
|
|
"test_eq(t.items,to.items)\n",
|
|
"test_eq(to.all_cols,to[['a']])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "089ce33e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"import gc"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "ff01aaac",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/1389180172.py:6: FutureWarning: `torch.distributed.reduce_op` is deprecated, please use `torch.distributed.ReduceOp` instead\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return len([x for x in objs if isinstance(x, pd.DataFrame)])\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"def _count_objs(o):\n",
|
|
" \"Counts number of instanes of class `o`\"\n",
|
|
" gc.collect() # Force garbage collection\n",
|
|
" objs = gc.get_objects()\n",
|
|
" return len([x for x in objs if isinstance(x, pd.DataFrame)])\n",
|
|
"\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,0,2], 'b':[0,0,0,0,1]})\n",
|
|
"df_b = pd.DataFrame({'a':[1,2,0,0,2], 'b':[1,0,3,0,1]})\n",
|
|
"\n",
|
|
"to = TabularPandas(df, cat_names='a', inplace=True)\n",
|
|
"\n",
|
|
"_init_count = _count_objs(pd.DataFrame)\n",
|
|
"to_new = to.new(df_b, inplace=True)\n",
|
|
"test_eq(_init_count, _count_objs(pd.DataFrame))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "5c7cd5ef",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class TabularProc(InplaceTransform):\n",
|
|
" \"Base class to write a non-lazy tabular processor for dataframes\"\n",
|
|
" def setup(self, items=None, train_setup=False): #TODO: properly deal with train_setup\n",
|
|
" super().setup(getattr(items,'train',items), train_setup=False)\n",
|
|
" # Procs are called as soon as data is available\n",
|
|
" return self(items.items if isinstance(items,Datasets) else items)\n",
|
|
"\n",
|
|
" @property\n",
|
|
" def name(self): return f\"{super().name} -- {getattr(self,'__stored_args__',{})}\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "80609ba3",
|
|
"metadata": {},
|
|
"source": [
|
|
"These transforms are applied as soon as the data is available rather than as data is called from the `DataLoader`"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "87389d74",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def _apply_cats (voc, add, c):\n",
|
|
" if not (hasattr(c, 'dtype') and isinstance(c.dtype, CategoricalDtype)):\n",
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n",
|
|
" return c.cat.codes+add #if is_categorical_dtype(c) else c.map(voc[c.name].o2i)\n",
|
|
"def _decode_cats(voc, c): return c.map(dict(enumerate(voc[c.name].items)))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "958b9760",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class Categorify(TabularProc):\n",
|
|
" \"Transform the categorical variables to something similar to `pd.Categorical`\"\n",
|
|
" order = 1\n",
|
|
" def setups(self, to):\n",
|
|
" store_attr(classes={n:CategoryMap(to.iloc[:,n].items, add_na=(n in to.cat_names)) for n in to.cat_names}, but='to')\n",
|
|
"\n",
|
|
" def encodes(self, to): to.transform(to.cat_names, partial(_apply_cats, self.classes, 1))\n",
|
|
" def decodes(self, to): to.transform(to.cat_names, partial(_decode_cats, self.classes))\n",
|
|
" def __getitem__(self,k): return self.classes[k]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1a858dde",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| exporti\n",
|
|
"@Categorize\n",
|
|
"def setups(self, to:Tabular):\n",
|
|
" if len(to.y_names) > 0:\n",
|
|
" if self.vocab is None:\n",
|
|
" self.vocab = CategoryMap(getattr(to, 'train', to).iloc[:,to.y_names[0]].items, strict=True)\n",
|
|
" else:\n",
|
|
" self.vocab = CategoryMap(self.vocab, sort=False, add_na=self.add_na)\n",
|
|
" self.c = len(self.vocab)\n",
|
|
" return self(to)\n",
|
|
"\n",
|
|
"@Categorize\n",
|
|
"def encodes(self, to:Tabular):\n",
|
|
" to.transform(to.y_names, partial(_apply_cats, {n: self.vocab for n in to.y_names}, 0), all_col=False)\n",
|
|
" return to\n",
|
|
"\n",
|
|
"@Categorize\n",
|
|
"def decodes(self, to:Tabular):\n",
|
|
" to.transform(to.y_names, partial(_decode_cats, {n: self.vocab for n in to.y_names}), all_col=False)\n",
|
|
" return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "81779533",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/markdown": [
|
|
"---\n",
|
|
"\n",
|
|
"[source](https://github.com/fastai/fastai/blob/main/fastai/tabular/core.py#L241){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
|
|
"\n",
|
|
"### Categorify\n",
|
|
"\n",
|
|
"```python\n",
|
|
"\n",
|
|
"def Categorify(\n",
|
|
" enc:NoneType=None, dec:NoneType=None, split_idx:NoneType=None, order:NoneType=None\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Transform the categorical variables to something similar to `pd.Categorical`*"
|
|
],
|
|
"text/plain": [
|
|
"```python\n",
|
|
"\n",
|
|
"def Categorify(\n",
|
|
" enc:NoneType=None, dec:NoneType=None, split_idx:NoneType=None, order:NoneType=None\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Transform the categorical variables to something similar to `pd.Categorical`*"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"show_doc(Categorify, title_level=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "3e434510",
|
|
"metadata": {},
|
|
"source": [
|
|
"While visually in the `DataFrame` you will not see a change, the classes are stored in `to.procs.categorify` as we can see below on a dummy `DataFrame`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6b1d8488",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>a</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>2</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"df = pd.DataFrame({'a':[0,1,2,0,2]})\n",
|
|
"to = TabularPandas(df, Categorify, 'a')\n",
|
|
"to.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "33dec0c8",
|
|
"metadata": {},
|
|
"source": [
|
|
"Each column's unique values are stored in a dictionary of `column:[values]`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3ab3e3cb",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'a': ['#na#', np.int8(0), np.int8(1), np.int8(2)]}"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"cat = to.procs.categorify\n",
|
|
"cat.classes"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6fdc3a77",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"def test_series(a,b): return test_eq(list(a), b)\n",
|
|
"test_series(cat['a'], ['#na#',0,1,2])\n",
|
|
"test_series(to['a'], [1,2,3,1,3])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "7d7de6b0",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df1 = pd.DataFrame({'a':[1,0,3,-1,2]})\n",
|
|
"to1 = to.new(df1)\n",
|
|
"to1.process()\n",
|
|
"#Values that weren't in the training df are sent to 0 (na)\n",
|
|
"test_series(to1['a'], [2,1,0,0,3])\n",
|
|
"to2 = cat.decode(to1)\n",
|
|
"test_series(to2['a'], [1,0,'#na#','#na#',2])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "4890eef4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#test with splits\n",
|
|
"cat = Categorify()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,2]})\n",
|
|
"to = TabularPandas(df, cat, 'a', splits=[[0,1,2],[3,4]])\n",
|
|
"test_series(cat['a'], ['#na#',0,1,2])\n",
|
|
"test_series(to['a'], [1,2,3,0,3])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "939d92fb",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df = pd.DataFrame({'a':pd.Categorical(['M','H','L','M'], categories=['H','M','L'], ordered=True)})\n",
|
|
"to = TabularPandas(df, Categorify, 'a')\n",
|
|
"cat = to.procs.categorify\n",
|
|
"test_series(cat['a'], ['#na#','H','M','L'])\n",
|
|
"test_series(to.items.a, [2,1,3,2])\n",
|
|
"to2 = cat.decode(to)\n",
|
|
"test_series(to2['a'], ['M','H','L','M'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "21145135",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#test with targets\n",
|
|
"cat = Categorify()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,2], 'b': ['a', 'b', 'a', 'b', 'b']})\n",
|
|
"to = TabularPandas(df, cat, 'a', splits=[[0,1,2],[3,4]], y_names='b')\n",
|
|
"test_series(to.vocab, ['a', 'b'])\n",
|
|
"test_series(to['b'], [0,1,0,1,1])\n",
|
|
"to2 = to.procs.decode(to)\n",
|
|
"test_series(to2['b'], ['a', 'b', 'a', 'b', 'b'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "47daf9db",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"cat = Categorify()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,2], 'b': ['a', 'b', 'a', 'b', 'b']})\n",
|
|
"to = TabularPandas(df, cat, 'a', splits=[[0,1,2],[3,4]], y_names='b')\n",
|
|
"test_series(to.vocab, ['a', 'b'])\n",
|
|
"test_series(to['b'], [0,1,0,1,1])\n",
|
|
"to2 = to.procs.decode(to)\n",
|
|
"test_series(to2['b'], ['a', 'b', 'a', 'b', 'b'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "1b6bed8e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#test with targets and train\n",
|
|
"cat = Categorify()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,2], 'b': ['a', 'b', 'a', 'c', 'b']})\n",
|
|
"to = TabularPandas(df, cat, 'a', splits=[[0,1,2],[3,4]], y_names='b')\n",
|
|
"test_series(to.vocab, ['a', 'b'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "87ad8404",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#test to ensure no copies of the dataframe are stored\n",
|
|
"cat = Categorify()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,4]})\n",
|
|
"to = TabularPandas(df, cat, cont_names='a', splits=[[0,1,2],[3,4]])\n",
|
|
"test_eq(hasattr(to.categorify, 'to'), False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c786be37",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| exporti\n",
|
|
"@Normalize\n",
|
|
"def setups(self, to:Tabular):\n",
|
|
" store_attr(but='to', means=dict(getattr(to, 'train', to).conts.mean()),\n",
|
|
" stds=dict(getattr(to, 'train', to).conts.std(ddof=0)+1e-7))\n",
|
|
" return self(to)\n",
|
|
"\n",
|
|
"@Normalize\n",
|
|
"def encodes(self, to:Tabular):\n",
|
|
" to.conts = (to.conts-self.means) / self.stds\n",
|
|
" return to\n",
|
|
"\n",
|
|
"@Normalize\n",
|
|
"def decodes(self, to:Tabular):\n",
|
|
" to.conts = (to.conts*self.stds ) + self.means\n",
|
|
" return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "242a0cd4",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"norm = Normalize()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,4]})\n",
|
|
"to = TabularPandas(df, norm, cont_names='a')\n",
|
|
"x = np.array([0,1,2,3,4])\n",
|
|
"m,s = x.mean(),x.std()\n",
|
|
"test_eq(norm.means['a'], m)\n",
|
|
"test_close(norm.stds['a'], s)\n",
|
|
"test_close(to['a'].values, (x-m)/s)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "87cb469f",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df1 = pd.DataFrame({'a':[5,6,7]})\n",
|
|
"to1 = to.new(df1)\n",
|
|
"to1.process()\n",
|
|
"test_close(to1['a'].values, (np.array([5,6,7])-m)/s)\n",
|
|
"to2 = norm.decode(to1)\n",
|
|
"test_close(to2['a'].values, [5,6,7])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3b539113",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"norm = Normalize()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,4]})\n",
|
|
"to = TabularPandas(df, norm, cont_names='a', splits=[[0,1,2],[3,4]])\n",
|
|
"x = np.array([0,1,2])\n",
|
|
"m,s = x.mean(),x.std()\n",
|
|
"test_eq(norm.means['a'], m)\n",
|
|
"test_close(norm.stds['a'], s)\n",
|
|
"test_close(to['a'].values, (np.array([0,1,2,3,4])-m)/s)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "8dd74ab5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"norm = Normalize()\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,3,4]})\n",
|
|
"to = TabularPandas(df, norm, cont_names='a', splits=[[0,1,2],[3,4]])\n",
|
|
"test_eq(hasattr(to.procs.normalize, 'to'), False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "76a90230",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class FillStrategy:\n",
|
|
" \"Namespace containing the various filling strategies.\"\n",
|
|
" def median (c,fill): return c.median()\n",
|
|
" def constant(c,fill): return fill\n",
|
|
" def mode (c,fill): return c.dropna().value_counts().idxmax()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b18e77f9",
|
|
"metadata": {},
|
|
"source": [
|
|
"Currently, filling with the `median`, a `constant`, and the `mode` are supported."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "e67b4128",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class FillMissing(TabularProc):\n",
|
|
" \"Fill the missing values in continuous columns.\"\n",
|
|
" def __init__(self, fill_strategy=FillStrategy.median, add_col=True, fill_vals=None):\n",
|
|
" if fill_vals is None: fill_vals = defaultdict(int)\n",
|
|
" store_attr()\n",
|
|
"\n",
|
|
" def setups(self, to):\n",
|
|
" missing = pd.isnull(to.conts).any()\n",
|
|
" store_attr(but='to', na_dict={n:self.fill_strategy(to[n], self.fill_vals[n])\n",
|
|
" for n in missing[missing].keys()})\n",
|
|
" self.fill_strategy = self.fill_strategy.__name__\n",
|
|
"\n",
|
|
" def encodes(self, to):\n",
|
|
" missing = pd.isnull(to.conts)\n",
|
|
" for n in missing.any()[missing.any()].keys():\n",
|
|
" assert n in self.na_dict, f\"nan values in `{n}` but not in setup training set\"\n",
|
|
" for n in self.na_dict.keys():\n",
|
|
" to[n] = to[n].fillna(self.na_dict[n])\n",
|
|
" if self.add_col:\n",
|
|
" to.loc[:,n+'_na'] = missing[n]\n",
|
|
" if n+'_na' not in to.cat_names: to.cat_names.append(n+'_na')"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c3778c41",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/markdown": [
|
|
"---\n",
|
|
"\n",
|
|
"[source](https://github.com/fastai/fastai/blob/main/fastai/tabular/core.py#L297){target=\"_blank\" style=\"float:right; font-size:smaller\"}\n",
|
|
"\n",
|
|
"### FillMissing\n",
|
|
"\n",
|
|
"```python\n",
|
|
"\n",
|
|
"def FillMissing(\n",
|
|
" fill_strategy:function=median, add_col:bool=True, fill_vals:NoneType=None\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Fill the missing values in continuous columns.*"
|
|
],
|
|
"text/plain": [
|
|
"```python\n",
|
|
"\n",
|
|
"def FillMissing(\n",
|
|
" fill_strategy:function=median, add_col:bool=True, fill_vals:NoneType=None\n",
|
|
"):\n",
|
|
"\n",
|
|
"\n",
|
|
"```\n",
|
|
"\n",
|
|
"*Fill the missing values in continuous columns.*"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"show_doc(FillMissing, title_level=3)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0a2c1296",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"fill1,fill2,fill3 = (FillMissing(fill_strategy=s)\n",
|
|
" for s in [FillStrategy.median, FillStrategy.constant, FillStrategy.mode])\n",
|
|
"df = pd.DataFrame({'a':[0,1,np.nan,1,2,3,4]})\n",
|
|
"df1 = df.copy(); df2 = df.copy()\n",
|
|
"tos = (TabularPandas(df, fill1, cont_names='a'),\n",
|
|
" TabularPandas(df1, fill2, cont_names='a'),\n",
|
|
" TabularPandas(df2, fill3, cont_names='a'))\n",
|
|
"test_eq(fill1.na_dict, {'a': 1.5})\n",
|
|
"test_eq(fill2.na_dict, {'a': 0})\n",
|
|
"test_eq(fill3.na_dict, {'a': 1.0})\n",
|
|
"\n",
|
|
"for t in tos: test_eq(t.cat_names, ['a_na'])\n",
|
|
"\n",
|
|
"for to_,v in zip(tos, [1.5, 0., 1.]):\n",
|
|
" test_eq(to_['a'].values, np.array([0, 1, v, 1, 2, 3, 4]))\n",
|
|
" test_eq(to_['a_na'].values, np.array([0, 0, 1, 0, 0, 0, 0]))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "bf0b9e5a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"fill = FillMissing()\n",
|
|
"df = pd.DataFrame({'a':[0,1,np.nan,1,2,3,4], 'b': [0,1,2,3,4,5,6]})\n",
|
|
"to = TabularPandas(df, fill, cont_names=['a', 'b'])\n",
|
|
"test_eq(fill.na_dict, {'a': 1.5})\n",
|
|
"test_eq(to.cat_names, ['a_na'])\n",
|
|
"test_eq(to['a'].values, np.array([0, 1, 1.5, 1, 2, 3, 4]))\n",
|
|
"test_eq(to['a_na'].values, np.array([0, 0, 1, 0, 0, 0, 0]))\n",
|
|
"test_eq(to['b'].values, np.array([0,1,2,3,4,5,6]))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "65c7be5e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"fill = FillMissing()\n",
|
|
"df = pd.DataFrame({'a':[0,1,np.nan,1,2,3,4], 'b': [0,1,2,3,4,5,6]})\n",
|
|
"to = TabularPandas(df, fill, cont_names=['a', 'b'])\n",
|
|
"test_eq(hasattr(to.procs.fill_missing, 'to'), False)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "46e09f6c",
|
|
"metadata": {},
|
|
"source": [
|
|
"## TabularPandas Pipelines -"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d15969b2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"procs = [Normalize, Categorify, FillMissing, noop]\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,1,1,2,0], 'b':[0,1,np.nan,1,2,3,4]})\n",
|
|
"to = TabularPandas(df, procs, cat_names='a', cont_names='b')\n",
|
|
"\n",
|
|
"#Test setup and apply on df_main\n",
|
|
"test_series(to.cat_names, ['a', 'b_na'])\n",
|
|
"test_series(to['a'], [1,2,3,2,2,3,1])\n",
|
|
"test_series(to['b_na'], [1,1,2,1,1,1,1])\n",
|
|
"x = np.array([0,1,1.5,1,2,3,4])\n",
|
|
"m,s = x.mean(),x.std()\n",
|
|
"test_close(to['b'].values, (x-m)/s)\n",
|
|
"test_eq(to.classes, {'a': ['#na#',0,1,2], 'b_na': ['#na#',False,True]})"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "fc5497b0",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"#Test apply on y_names\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,1,1,2,0], 'b':[0,1,np.nan,1,2,3,4], 'c': ['b','a','b','a','a','b','a']})\n",
|
|
"to = TabularPandas(df, procs, 'a', 'b', y_names='c')\n",
|
|
"\n",
|
|
"test_series(to.cat_names, ['a', 'b_na'])\n",
|
|
"test_series(to['a'], [1,2,3,2,2,3,1])\n",
|
|
"test_series(to['b_na'], [1,1,2,1,1,1,1])\n",
|
|
"test_series(to['c'], [1,0,1,0,0,1,0])\n",
|
|
"x = np.array([0,1,1.5,1,2,3,4])\n",
|
|
"m,s = x.mean(),x.std()\n",
|
|
"test_close(to['b'].values, (x-m)/s)\n",
|
|
"test_eq(to.classes, {'a': ['#na#',0,1,2], 'b_na': ['#na#',False,True]})\n",
|
|
"test_eq(to.vocab, ['a','b'])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "02ee4f62",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,1,1,2,0], 'b':[0,1,np.nan,1,2,3,4], 'c': ['b','a','b','a','a','b','a']})\n",
|
|
"to = TabularPandas(df, procs, 'a', 'b', y_names='c')\n",
|
|
"\n",
|
|
"test_series(to.cat_names, ['a', 'b_na'])\n",
|
|
"test_series(to['a'], [1,2,3,2,2,3,1])\n",
|
|
"test_eq(df.a.dtype, np.int64 if sys.platform == \"win32\" else int)\n",
|
|
"test_series(to['b_na'], [1,1,2,1,1,1,1])\n",
|
|
"test_series(to['c'], [1,0,1,0,0,1,0])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d2884d57",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/var/folders/51/b2_szf2945n072c0vj2cyty40000gn/T/ipymini_23754/3600165379.py:3: Pandas4Warning: Constructing a Categorical with a dtype and values containing non-null entries not in that dtype's categories is deprecated and will raise in a future version.\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" return pd.Categorical(c, categories=voc[c.name][add:]).codes+add\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"#| hide\n",
|
|
"df = pd.DataFrame({'a':[0,1,2,1,1,2,0], 'b':[0,np.nan,1,1,2,3,4], 'c': ['b','a','b','a','a','b','a']})\n",
|
|
"to = TabularPandas(df, procs, cat_names='a', cont_names='b', y_names='c', splits=[[0,1,4,6], [2,3,5]])\n",
|
|
"\n",
|
|
"test_series(to.cat_names, ['a', 'b_na'])\n",
|
|
"test_series(to['a'], [1,2,2,1,0,2,0])\n",
|
|
"test_eq(df.a.dtype, np.int64 if sys.platform == \"win32\" else int)\n",
|
|
"test_series(to['b_na'], [1,2,1,1,1,1,1])\n",
|
|
"test_series(to['c'], [1,0,0,0,1,0,1])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9be310e6",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"def _maybe_expand(o): return o[:,None] if o.ndim==1 else o"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "774acf79",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"class ReadTabBatch(ItemTransform):\n",
|
|
" \"Transform `TabularPandas` values into a `Tensor` with the ability to decode\"\n",
|
|
" def __init__(self, to): self.to = to.new_empty()\n",
|
|
"\n",
|
|
" def encodes(self, to):\n",
|
|
" if not to.with_cont: res = (tensor(to.cats).long(),)\n",
|
|
" else: res = (tensor(to.cats).long(),tensor(to.conts).float())\n",
|
|
" ys = [n for n in to.y_names if n in to.items.columns]\n",
|
|
" if len(ys) == len(to.y_names): res = res + (tensor(to.targ),)\n",
|
|
" if to.device is not None: res = to_device(res, to.device)\n",
|
|
" return res\n",
|
|
"\n",
|
|
" def decodes(self, o):\n",
|
|
" o = [_maybe_expand(o_) for o_ in to_np(o) if o_.size != 0]\n",
|
|
" vals = np.concatenate(o, axis=1)\n",
|
|
" try: df = pd.DataFrame(vals, columns=self.to.all_col_names)\n",
|
|
" except: df = pd.DataFrame(vals, columns=self.to.x_names)\n",
|
|
" to = self.to.new(df)\n",
|
|
" return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "063a6e8e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"@dispatch\n",
|
|
"def show_batch(x: Tabular, y, its, max_n=10, ctxs=None):\n",
|
|
" x.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "bcf9ce05",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"@delegates()\n",
|
|
"class TabDataLoader(TfmdDL):\n",
|
|
" \"A transformed `DataLoader` for Tabular data\"\n",
|
|
" def __init__(self, dataset, bs=16, shuffle=False, after_batch=None, num_workers=0, **kwargs):\n",
|
|
" if after_batch is None: after_batch = L(TransformBlock().batch_tfms)+ReadTabBatch(dataset)\n",
|
|
" super().__init__(dataset, bs=bs, shuffle=shuffle, after_batch=after_batch, num_workers=num_workers, **kwargs)\n",
|
|
"\n",
|
|
" def create_item(self, s): return self.dataset.iloc[s or 0]\n",
|
|
" def create_batch(self, b): return self.dataset.iloc[b]\n",
|
|
" def do_item(self, s): return 0 if s is None else s\n",
|
|
"\n",
|
|
"TabularPandas._dl_type = TabDataLoader"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "253b8d64",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| export\n",
|
|
"@delegates()\n",
|
|
"class TabWeightedDL(TabDataLoader):\n",
|
|
" \"A transformed `DataLoader` for Tabular Weighted data\"\n",
|
|
" def __init__(self, dataset, bs=16, wgts=None, shuffle=False, after_batch=None, num_workers=0, **kwargs):\n",
|
|
" wgts = np.array([1.]*len(dataset) if wgts is None else wgts)\n",
|
|
" self.wgts = wgts / wgts.sum()\n",
|
|
" super().__init__(dataset, bs=bs, shuffle=shuffle, after_batch=after_batch, num_workers=num_workers, **kwargs)\n",
|
|
" self.idxs = self.get_idxs()\n",
|
|
"\n",
|
|
" def get_idxs(self):\n",
|
|
" if self.n == 0: return []\n",
|
|
" if not self.shuffle: return super().get_idxs()\n",
|
|
" return list(np.random.choice(self.n, self.n, p=self.wgts))\n",
|
|
"\n",
|
|
"TabularPandas._dl_type = TabWeightedDL"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "62c9fd30",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Integration example\n",
|
|
"\n",
|
|
"For a more in-depth explanation, see the [tabular tutorial](http://docs.fast.ai/tutorial.tabular.html)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "774aa6d2",
|
|
"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>age</th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>sex</th>\n",
|
|
" <th>capital-gain</th>\n",
|
|
" <th>capital-loss</th>\n",
|
|
" <th>hours-per-week</th>\n",
|
|
" <th>native-country</th>\n",
|
|
" <th>salary</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>49</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>101320</td>\n",
|
|
" <td>Assoc-acdm</td>\n",
|
|
" <td>12.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1902</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>44</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>236746</td>\n",
|
|
" <td>Masters</td>\n",
|
|
" <td>14.0</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>10520</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>45</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>96185</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>32</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>112847</td>\n",
|
|
" <td>Prof-school</td>\n",
|
|
" <td>15.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>42</td>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>82297</td>\n",
|
|
" <td>7th-8th</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>50</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" age workclass fnlwgt ... hours-per-week native-country salary\n",
|
|
"0 49 Private 101320 ... 40 United-States >=50k\n",
|
|
"1 44 Private 236746 ... 45 United-States >=50k\n",
|
|
"2 38 Private 96185 ... 32 United-States <50k\n",
|
|
"3 38 Self-emp-inc 112847 ... 40 United-States >=50k\n",
|
|
"4 42 Self-emp-not-inc 82297 ... 50 United-States <50k\n",
|
|
"\n",
|
|
"[5 rows x 15 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"path = untar_data(URLs.ADULT_SAMPLE)\n",
|
|
"df = pd.read_csv(path/'adult.csv')\n",
|
|
"df_main,df_test = df.iloc[:10000].copy(),df.iloc[10000:].copy()\n",
|
|
"df_test.drop('salary', axis=1, inplace=True)\n",
|
|
"df_main.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "21345619",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']\n",
|
|
"cont_names = ['age', 'fnlwgt', 'education-num']\n",
|
|
"procs = [Categorify, FillMissing, Normalize]\n",
|
|
"splits = RandomSplitter()(range_of(df_main))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "5e2ff96b",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"to = TabularPandas(df_main, procs, cat_names, cont_names, y_names=\"salary\", splits=splits)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "57eb78ab",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"/Users/jhoward/aai-ws/fastai/fastai/torch_core.py:154: UserWarning: The given NumPy array is not writable, and PyTorch does not support non-writable tensors. This means writing to this tensor will result in undefined behavior. You may want to copy the array to protect its data or make it writable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at /Users/runner/work/pytorch/pytorch/pytorch/torch/csrc/utils/tensor_numpy.cpp:212.)\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stderr",
|
|
"output_type": "stream",
|
|
"text": [
|
|
" else as_tensor(x.values, **kwargs) if isinstance(x, (pd.Series, pd.DataFrame))\n"
|
|
]
|
|
},
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>age</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>salary</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>State-gov</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>23.000000</td>\n",
|
|
" <td>287987.999279</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>State-gov</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Tech-support</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>32.000000</td>\n",
|
|
" <td>131587.998019</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>58.000000</td>\n",
|
|
" <td>183810.000021</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>83.999998</td>\n",
|
|
" <td>172906.999298</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>Local-gov</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>31.000000</td>\n",
|
|
" <td>128016.002079</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>22.000001</td>\n",
|
|
" <td>58915.997617</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>6</th>\n",
|
|
" <td>?</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>26.000000</td>\n",
|
|
" <td>176966.999519</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>7</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Other-relative</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>23.999999</td>\n",
|
|
" <td>86744.998003</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>38.000000</td>\n",
|
|
" <td>123833.001583</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>9</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Farming-fishing</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>35.000000</td>\n",
|
|
" <td>168322.000103</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"dls = to.dataloaders()\n",
|
|
"dls.valid.show_batch()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b44bbe41",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>age</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>salary</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>3564</th>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>50.0</td>\n",
|
|
" <td>124793.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5802</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>30.0</td>\n",
|
|
" <td>205204.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1087</th>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Farming-fishing</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>55.0</td>\n",
|
|
" <td>149168.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1239</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>25.0</td>\n",
|
|
" <td>104193.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2234</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Handlers-cleaners</td>\n",
|
|
" <td>Other-relative</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>22.0</td>\n",
|
|
" <td>361138.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8032</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>54.0</td>\n",
|
|
" <td>391016.0</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4364</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>45.0</td>\n",
|
|
" <td>380922.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5404</th>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Farming-fishing</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>60.0</td>\n",
|
|
" <td>160062.0</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>693</th>\n",
|
|
" <td>State-gov</td>\n",
|
|
" <td>Masters</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>27.0</td>\n",
|
|
" <td>315640.0</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2684</th>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Farming-fishing</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>84.0</td>\n",
|
|
" <td>155057.0</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"to.show()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "d553e81a",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can decode any set of transformed data by calling `to.decode_row` with our raw data:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "2583c751",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"age 50.0\n",
|
|
"workclass Self-emp-not-inc\n",
|
|
"fnlwgt 124793.0\n",
|
|
"education HS-grad\n",
|
|
"education-num 9.0\n",
|
|
"marital-status Married-civ-spouse\n",
|
|
"occupation Craft-repair\n",
|
|
"relationship Husband\n",
|
|
"race White\n",
|
|
"sex Male\n",
|
|
"capital-gain 0\n",
|
|
"capital-loss 0\n",
|
|
"hours-per-week 30\n",
|
|
"native-country United-States\n",
|
|
"salary <50k\n",
|
|
"education-num_na False\n",
|
|
"Name: 3564, dtype: object"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"row = to.items.iloc[0]\n",
|
|
"to.decode_row(row)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f3c28624",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can make new test datasets based on the training data with the `to.new()`\n",
|
|
"\n",
|
|
":::{.callout-note}\n",
|
|
"\n",
|
|
"Since machine learning models can't magically understand categories it was never trained on, the data should reflect this. If there are different missing values in your test data you should address this before training\n",
|
|
"\n",
|
|
":::"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "aeaea7ed",
|
|
"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>age</th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>sex</th>\n",
|
|
" <th>capital-gain</th>\n",
|
|
" <th>capital-loss</th>\n",
|
|
" <th>hours-per-week</th>\n",
|
|
" <th>native-country</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>10000</th>\n",
|
|
" <td>0.470185</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>1.346422</td>\n",
|
|
" <td>10</td>\n",
|
|
" <td>1.165893</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>Philippines</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>10001</th>\n",
|
|
" <td>-0.923825</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>1.258980</td>\n",
|
|
" <td>12</td>\n",
|
|
" <td>-0.424752</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>15</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>4</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>10002</th>\n",
|
|
" <td>1.057137</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>0.150986</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>-1.220074</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>9</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>37</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>10003</th>\n",
|
|
" <td>0.543554</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>-0.284206</td>\n",
|
|
" <td>12</td>\n",
|
|
" <td>-0.424752</td>\n",
|
|
" <td>7</td>\n",
|
|
" <td>2</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>43</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>10004</th>\n",
|
|
" <td>0.763661</td>\n",
|
|
" <td>6</td>\n",
|
|
" <td>1.449451</td>\n",
|
|
" <td>9</td>\n",
|
|
" <td>0.370571</td>\n",
|
|
" <td>3</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>1</td>\n",
|
|
" <td>5</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>60</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>1</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" age workclass ... native-country education-num_na\n",
|
|
"10000 0.470185 5 ... Philippines 1\n",
|
|
"10001 -0.923825 5 ... United-States 1\n",
|
|
"10002 1.057137 5 ... United-States 1\n",
|
|
"10003 0.543554 5 ... United-States 1\n",
|
|
"10004 0.763661 6 ... United-States 1\n",
|
|
"\n",
|
|
"[5 rows x 15 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"to_tst = to.new(df_test)\n",
|
|
"to_tst.process()\n",
|
|
"to_tst.items.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "8d7c445c",
|
|
"metadata": {},
|
|
"source": [
|
|
"We can then convert it to a `DataLoader`:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6a85b936",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>age</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>45.0</td>\n",
|
|
" <td>338104.995686</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Transport-moving</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Other</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>26.0</td>\n",
|
|
" <td>328662.994908</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>53.0</td>\n",
|
|
" <td>209021.999974</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Widowed</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>46.0</td>\n",
|
|
" <td>162029.999608</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>Assoc-voc</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>49.0</td>\n",
|
|
" <td>349229.997552</td>\n",
|
|
" <td>11.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>Local-gov</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>34.0</td>\n",
|
|
" <td>124826.999041</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>6</th>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>53.0</td>\n",
|
|
" <td>290640.000020</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>7</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>19.0</td>\n",
|
|
" <td>106273.001990</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Protective-serv</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>72.0</td>\n",
|
|
" <td>53684.003204</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>9</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Sales</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>20.0</td>\n",
|
|
" <td>505979.987402</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"tst_dl = dls.valid.new(to_tst)\n",
|
|
"tst_dl.show_batch()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3473df5e",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>age</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>salary</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Widowed</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>58.000000</td>\n",
|
|
" <td>178644.000556</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Handlers-cleaners</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>21.000000</td>\n",
|
|
" <td>131811.002389</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>10th</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>#na#</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>16.999999</td>\n",
|
|
" <td>294485.002377</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Widowed</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>66.000001</td>\n",
|
|
" <td>98836.997894</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>28.000000</td>\n",
|
|
" <td>420054.007486</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>Federal-gov</td>\n",
|
|
" <td>Assoc-voc</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>43.000000</td>\n",
|
|
" <td>92774.997808</td>\n",
|
|
" <td>11.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>6</th>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>19.000000</td>\n",
|
|
" <td>234518.999208</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>7</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>35.000000</td>\n",
|
|
" <td>186009.000006</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8</th>\n",
|
|
" <td>Federal-gov</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>25.000000</td>\n",
|
|
" <td>144258.998968</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>9</th>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>20.000000</td>\n",
|
|
" <td>117788.996828</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td><50k</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"# Create a TabWeightedDL\n",
|
|
"train_ds = to.train\n",
|
|
"weights = np.random.random(len(train_ds))\n",
|
|
"train_dl = TabWeightedDL(train_ds, wgts=weights, bs=64, shuffle=True)\n",
|
|
"\n",
|
|
"train_dl.show_batch()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "49343d89",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"batch = next(iter(train_dl))\n",
|
|
"\n",
|
|
"x, y = batch[0].shape\n",
|
|
"\n",
|
|
"test_eq(x, 64)\n",
|
|
"test_eq(y, 7)\n",
|
|
"\n",
|
|
"assert hasattr(train_dl, 'wgts'), \"Weights attribute missing in DataLoader\""
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "2e8f4cfd",
|
|
"metadata": {},
|
|
"source": [
|
|
"TabDataLoader's create_item method"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "665057bd",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"age 35\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Name: 0, dtype: int8\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"df = pd.DataFrame([{'age': 35}])\n",
|
|
"to = TabularPandas(df)\n",
|
|
"dls = to.dataloaders()\n",
|
|
"print(dls.create_item(0))\n",
|
|
"# test_eq(dls.create_item(0).items.to_dict(), {'age': 0.5330614747286777, 'workclass': 5, 'fnlwgt': -0.26305443080666174, 'education': 10, 'education-num': 1.169790230219763, 'marital-status': 1, 'occupation': 13, 'relationship': 5, 'race': 3, 'sex': ' Female', 'capital-gain': 0, 'capital-loss': 0, 'hours-per-week': 35, 'native-country': 'United-States', 'salary': 1, 'education-num_na': 1})"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "b2f17bbd",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Other target types"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "be0b3f63",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Multi-label categories"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "035e521c",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### one-hot encoded label"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3ce5308e",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def _mock_multi_label(df):\n",
|
|
" sal,sex,white = [],[],[]\n",
|
|
" for row in df.itertuples():\n",
|
|
" sal.append(row.salary == '>=50k')\n",
|
|
" sex.append(row.sex == ' Male')\n",
|
|
" white.append(row.race == ' White')\n",
|
|
" df['salary'] = np.array(sal)\n",
|
|
" df['male'] = np.array(sex)\n",
|
|
" df['white'] = np.array(white)\n",
|
|
" return df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "c81c8277",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = untar_data(URLs.ADULT_SAMPLE)\n",
|
|
"df = pd.read_csv(path/'adult.csv')\n",
|
|
"df_main,df_test = df.iloc[:10000].copy(),df.iloc[10000:].copy()\n",
|
|
"df_main = _mock_multi_label(df_main)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "17c80776",
|
|
"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>age</th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>sex</th>\n",
|
|
" <th>capital-gain</th>\n",
|
|
" <th>capital-loss</th>\n",
|
|
" <th>hours-per-week</th>\n",
|
|
" <th>native-country</th>\n",
|
|
" <th>salary</th>\n",
|
|
" <th>male</th>\n",
|
|
" <th>white</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>49</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>101320</td>\n",
|
|
" <td>Assoc-acdm</td>\n",
|
|
" <td>12.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1902</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>44</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>236746</td>\n",
|
|
" <td>Masters</td>\n",
|
|
" <td>14.0</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>10520</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>45</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>96185</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>32</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>112847</td>\n",
|
|
" <td>Prof-school</td>\n",
|
|
" <td>15.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>42</td>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>82297</td>\n",
|
|
" <td>7th-8th</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>50</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" age workclass fnlwgt ... salary male white\n",
|
|
"0 49 Private 101320 ... True False True\n",
|
|
"1 44 Private 236746 ... True True True\n",
|
|
"2 38 Private 96185 ... False False False\n",
|
|
"3 38 Self-emp-inc 112847 ... True True False\n",
|
|
"4 42 Self-emp-not-inc 82297 ... False False False\n",
|
|
"\n",
|
|
"[5 rows x 17 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df_main.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "67f710b2",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| exporti\n",
|
|
"@EncodedMultiCategorize\n",
|
|
"def setups(self, to:Tabular):\n",
|
|
" self.c = len(self.vocab)\n",
|
|
" return self(to)\n",
|
|
"\n",
|
|
"@EncodedMultiCategorize\n",
|
|
"def encodes(self, to:Tabular): return to\n",
|
|
"\n",
|
|
"@EncodedMultiCategorize\n",
|
|
"def decodes(self, to:Tabular):\n",
|
|
" to.transform(to.y_names, lambda c: c==1)\n",
|
|
" return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "947ce02a",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']\n",
|
|
"cont_names = ['age', 'fnlwgt', 'education-num']\n",
|
|
"procs = [Categorify, FillMissing, Normalize]\n",
|
|
"splits = RandomSplitter()(range_of(df_main))\n",
|
|
"y_names=[\"salary\", \"male\", \"white\"]"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "b7e076f4",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 30.8 ms, sys: 774 us, total: 31.6 ms\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Wall time: 31.4 ms\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%time to = TabularPandas(df_main, procs, cat_names, cont_names, y_names=y_names, y_block=MultiCategoryBlock(encoded=True, vocab=y_names), splits=splits)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "04eecd3c",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>age</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>salary</th>\n",
|
|
" <th>male</th>\n",
|
|
" <th>white</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Machine-op-inspct</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>35.000000</td>\n",
|
|
" <td>110668.001907</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>51.000000</td>\n",
|
|
" <td>33303.995791</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>37.000000</td>\n",
|
|
" <td>38468.006454</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>?</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>63.999999</td>\n",
|
|
" <td>108082.000741</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>38.000000</td>\n",
|
|
" <td>187747.999948</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Tech-support</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>28.000000</td>\n",
|
|
" <td>375313.002386</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>6</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>#na#</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>36.000000</td>\n",
|
|
" <td>130199.998135</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>7</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>36.000000</td>\n",
|
|
" <td>123151.001427</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Adm-clerical</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>32.000000</td>\n",
|
|
" <td>107218.002435</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" <td>False</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>9</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>32.000000</td>\n",
|
|
" <td>185732.000241</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>True</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"dls = to.dataloaders()\n",
|
|
"dls.valid.show_batch()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "31084bed",
|
|
"metadata": {},
|
|
"source": [
|
|
"#### Not one-hot encoded"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "6d5344d1",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"def _mock_multi_label(df):\n",
|
|
" targ = []\n",
|
|
" for row in df.itertuples():\n",
|
|
" labels = []\n",
|
|
" if row.salary == '>=50k': labels.append('>50k')\n",
|
|
" if row.sex == ' Male': labels.append('male')\n",
|
|
" if row.race == ' White': labels.append('white')\n",
|
|
" targ.append(' '.join(labels))\n",
|
|
" df['target'] = np.array(targ)\n",
|
|
" return df"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "deaa4ec3",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = untar_data(URLs.ADULT_SAMPLE)\n",
|
|
"df = pd.read_csv(path/'adult.csv')\n",
|
|
"df_main,df_test = df.iloc[:10000].copy(),df.iloc[10000:].copy()\n",
|
|
"df_main = _mock_multi_label(df_main)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "eff30354",
|
|
"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>age</th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>sex</th>\n",
|
|
" <th>capital-gain</th>\n",
|
|
" <th>capital-loss</th>\n",
|
|
" <th>hours-per-week</th>\n",
|
|
" <th>native-country</th>\n",
|
|
" <th>salary</th>\n",
|
|
" <th>target</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>49</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>101320</td>\n",
|
|
" <td>Assoc-acdm</td>\n",
|
|
" <td>12.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>1902</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" <td>>50k white</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>44</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>236746</td>\n",
|
|
" <td>Masters</td>\n",
|
|
" <td>14.0</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>10520</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>45</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" <td>>50k male white</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>96185</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>32</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td><50k</td>\n",
|
|
" <td></td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>38</td>\n",
|
|
" <td>Self-emp-inc</td>\n",
|
|
" <td>112847</td>\n",
|
|
" <td>Prof-school</td>\n",
|
|
" <td>15.0</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>Asian-Pac-Islander</td>\n",
|
|
" <td>Male</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>40</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td>>=50k</td>\n",
|
|
" <td>>50k male</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>42</td>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>82297</td>\n",
|
|
" <td>7th-8th</td>\n",
|
|
" <td>NaN</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Wife</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>Female</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>0</td>\n",
|
|
" <td>50</td>\n",
|
|
" <td>United-States</td>\n",
|
|
" <td><50k</td>\n",
|
|
" <td></td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>\n",
|
|
"</div>"
|
|
],
|
|
"text/plain": [
|
|
" age workclass fnlwgt ... native-country salary target\n",
|
|
"0 49 Private 101320 ... United-States >=50k >50k white\n",
|
|
"1 44 Private 236746 ... United-States >=50k >50k male white\n",
|
|
"2 38 Private 96185 ... United-States <50k \n",
|
|
"3 38 Self-emp-inc 112847 ... United-States >=50k >50k male\n",
|
|
"4 42 Self-emp-not-inc 82297 ... United-States <50k \n",
|
|
"\n",
|
|
"[5 rows x 16 columns]"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"df_main.head()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d9766eec",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"@MultiCategorize\n",
|
|
"def encodes(self, to:Tabular):\n",
|
|
" #to.transform(to.y_names, partial(_apply_cats, {n: self.vocab for n in to.y_names}, 0))\n",
|
|
" return to\n",
|
|
"\n",
|
|
"@MultiCategorize\n",
|
|
"def decodes(self, to:Tabular):\n",
|
|
" #to.transform(to.y_names, partial(_decode_cats, {n: self.vocab for n in to.y_names}))\n",
|
|
" return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "fd5f38e5",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']\n",
|
|
"cont_names = ['age', 'fnlwgt', 'education-num']\n",
|
|
"procs = [Categorify, FillMissing, Normalize]\n",
|
|
"splits = RandomSplitter()(range_of(df_main))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3cd349cb",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 10.5 ms, sys: 201 us, total: 10.7 ms\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Wall time: 10.6 ms\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%time to = TabularPandas(df_main, procs, cat_names, cont_names, y_names=\"target\", y_block=MultiCategoryBlock(), splits=splits)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "cdd1400c",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"['-', '_', 'a', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n', 'o', 'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y']"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"to.procs[2].vocab"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "ededa205",
|
|
"metadata": {},
|
|
"source": [
|
|
"### Regression"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "d6b3e995",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| exporti\n",
|
|
"@RegressionSetup\n",
|
|
"def setups(self, to:Tabular):\n",
|
|
" if self.c is not None: return\n",
|
|
" self.c = len(to.y_names)\n",
|
|
" return to\n",
|
|
"\n",
|
|
"@RegressionSetup\n",
|
|
"def encodes(self, to:Tabular): return to\n",
|
|
"\n",
|
|
"@RegressionSetup\n",
|
|
"def decodes(self, to:Tabular): return to"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "0ab00801",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"path = untar_data(URLs.ADULT_SAMPLE)\n",
|
|
"df = pd.read_csv(path/'adult.csv')\n",
|
|
"df_main,df_test = df.iloc[:10000].copy(),df.iloc[10000:].copy()\n",
|
|
"df_main = _mock_multi_label(df_main)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "36253610",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"cat_names = ['workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race']\n",
|
|
"cont_names = ['fnlwgt', 'education-num']\n",
|
|
"procs = [Categorify, FillMissing, Normalize]\n",
|
|
"splits = RandomSplitter()(range_of(df_main))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "7d05a460",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"CPU times: user 21.8 ms, sys: 969 us, total: 22.7 ms\n"
|
|
]
|
|
},
|
|
{
|
|
"name": "stdout",
|
|
"output_type": "stream",
|
|
"text": [
|
|
"Wall time: 21.9 ms\n"
|
|
]
|
|
}
|
|
],
|
|
"source": [
|
|
"%time to = TabularPandas(df_main, procs, cat_names, cont_names, y_names='age', splits=splits)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "76c0315b",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/plain": [
|
|
"{'fnlwgt': np.float64(192511.077125),\n",
|
|
" 'education-num': np.float64(10.076749801635742)}"
|
|
]
|
|
},
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"output_type": "execute_result"
|
|
}
|
|
],
|
|
"source": [
|
|
"to.procs[-1].means"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "3ebfddc8",
|
|
"metadata": {},
|
|
"outputs": [
|
|
{
|
|
"data": {
|
|
"text/html": [
|
|
"<table border=\"1\" class=\"dataframe\">\n",
|
|
" <thead>\n",
|
|
" <tr style=\"text-align: right;\">\n",
|
|
" <th></th>\n",
|
|
" <th>workclass</th>\n",
|
|
" <th>education</th>\n",
|
|
" <th>marital-status</th>\n",
|
|
" <th>occupation</th>\n",
|
|
" <th>relationship</th>\n",
|
|
" <th>race</th>\n",
|
|
" <th>education-num_na</th>\n",
|
|
" <th>fnlwgt</th>\n",
|
|
" <th>education-num</th>\n",
|
|
" <th>age</th>\n",
|
|
" </tr>\n",
|
|
" </thead>\n",
|
|
" <tbody>\n",
|
|
" <tr>\n",
|
|
" <th>0</th>\n",
|
|
" <td>Local-gov</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-spouse-absent</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>216129.000726</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>38.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>1</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Protective-serv</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>Black</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>162814.000297</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>34.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>2</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>193881.999975</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>44.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>3</th>\n",
|
|
" <td>Local-gov</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Exec-managerial</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>144778.000789</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>43.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>4</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>HS-grad</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>304385.993937</td>\n",
|
|
" <td>9.0</td>\n",
|
|
" <td>24.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>5</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>5th-6th</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Craft-repair</td>\n",
|
|
" <td>Not-in-family</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>155621.001484</td>\n",
|
|
" <td>3.0</td>\n",
|
|
" <td>28.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>6</th>\n",
|
|
" <td>Self-emp-not-inc</td>\n",
|
|
" <td>7th-8th</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Other-service</td>\n",
|
|
" <td>Unmarried</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>385632.000374</td>\n",
|
|
" <td>4.0</td>\n",
|
|
" <td>56.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>7</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>Bachelors</td>\n",
|
|
" <td>Never-married</td>\n",
|
|
" <td>Prof-specialty</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>244365.998597</td>\n",
|
|
" <td>13.0</td>\n",
|
|
" <td>22.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>8</th>\n",
|
|
" <td>Private</td>\n",
|
|
" <td>11th</td>\n",
|
|
" <td>Divorced</td>\n",
|
|
" <td>Handlers-cleaners</td>\n",
|
|
" <td>Own-child</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>112262.998271</td>\n",
|
|
" <td>7.0</td>\n",
|
|
" <td>30.0</td>\n",
|
|
" </tr>\n",
|
|
" <tr>\n",
|
|
" <th>9</th>\n",
|
|
" <td>Local-gov</td>\n",
|
|
" <td>Some-college</td>\n",
|
|
" <td>Married-civ-spouse</td>\n",
|
|
" <td>Protective-serv</td>\n",
|
|
" <td>Husband</td>\n",
|
|
" <td>White</td>\n",
|
|
" <td>False</td>\n",
|
|
" <td>195258.000082</td>\n",
|
|
" <td>10.0</td>\n",
|
|
" <td>41.0</td>\n",
|
|
" </tr>\n",
|
|
" </tbody>\n",
|
|
"</table>"
|
|
],
|
|
"text/plain": [
|
|
"<IPython.core.display.HTML object>"
|
|
]
|
|
},
|
|
"metadata": {},
|
|
"output_type": "display_data"
|
|
}
|
|
],
|
|
"source": [
|
|
"dls = to.dataloaders()\n",
|
|
"dls.valid.show_batch()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "c94a9701",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Not being used now - for multi-modal"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "181bc611",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"class TensorTabular(fastuple):\n",
|
|
" def get_ctxs(self, max_n=10, **kwargs):\n",
|
|
" n_samples = min(self[0].shape[0], max_n)\n",
|
|
" df = pd.DataFrame(index = range(n_samples))\n",
|
|
" return [df.iloc[i] for i in range(n_samples)]\n",
|
|
"\n",
|
|
" def display(self, ctxs): display_df(pd.DataFrame(ctxs))\n",
|
|
"\n",
|
|
"class TabularLine(pd.Series):\n",
|
|
" \"A line of a dataframe that knows how to show itself\"\n",
|
|
" def show(self, ctx=None, **kwargs): return self if ctx is None else ctx.append(self)\n",
|
|
"\n",
|
|
"class ReadTabLine(ItemTransform):\n",
|
|
" def __init__(self, proc): self.proc = proc\n",
|
|
"\n",
|
|
" def encodes(self, row):\n",
|
|
" cats,conts = (o.map(row.__getitem__) for o in (self.proc.cat_names,self.proc.cont_names))\n",
|
|
" return TensorTabular(tensor(cats).long(),tensor(conts).float())\n",
|
|
"\n",
|
|
" def decodes(self, o):\n",
|
|
" to = TabularPandas(o, self.proc.cat_names, self.proc.cont_names, self.proc.y_names)\n",
|
|
" to = self.proc.decode(to)\n",
|
|
" return TabularLine(pd.Series({c: v for v,c in zip(to.items[0]+to.items[1], self.proc.cat_names+self.proc.cont_names)}))\n",
|
|
"\n",
|
|
"class ReadTabTarget(ItemTransform):\n",
|
|
" def __init__(self, proc): self.proc = proc\n",
|
|
" def encodes(self, row): return row[self.proc.y_names].astype(np.int64)\n",
|
|
" def decodes(self, o): return Category(self.proc.classes[self.proc.y_names][o])"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "463c71e3",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# tds = TfmdDS(to.items, tfms=[[ReadTabLine(proc)], ReadTabTarget(proc)])\n",
|
|
"# enc = tds[1]\n",
|
|
"# test_eq(enc[0][0], tensor([2,1]))\n",
|
|
"# test_close(enc[0][1], tensor([-0.628828]))\n",
|
|
"# test_eq(enc[1], 1)\n",
|
|
"\n",
|
|
"# dec = tds.decode(enc)\n",
|
|
"# assert isinstance(dec[0], TabularLine)\n",
|
|
"# test_close(dec[0], pd.Series({'a': 1, 'b_na': False, 'b': 1}))\n",
|
|
"# test_eq(dec[1], 'a')\n",
|
|
"\n",
|
|
"# test_stdout(lambda: print(show_at(tds, 1)), \"\"\"a 1\n",
|
|
"# b_na False\n",
|
|
"# b 1\n",
|
|
"# category a\n",
|
|
"# dtype: object\"\"\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"id": "f64980dc",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Export -"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"id": "9b8563f9",
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"#| hide\n",
|
|
"from nbdev import nbdev_export\n",
|
|
"nbdev_export()"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 5
|
|
}
|