{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Categorical Feature Encoding Techniques\n\nHere we explore methods for encoding binary, ordinal, and nominal categorical features.\n  \nCategorical data is a common type of non-numerical data that contains label values and not numbers.\n\n[Link](https://towardsdatascience.com/categorical-encoding-techniques-93ebd18e1f24) to Medium article with more information."},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# setting up default plotting parameters\n%matplotlib inline\n\nplt.rcParams['figure.figsize'] = [20.0, 7.0]\nplt.rcParams.update({'font.size': 22,})\n\nsns.set_palette('viridis')\nsns.set_style('white')\nsns.set_context('talk', font_scale=0.8)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_raw = pd.read_csv('../input/cat-in-the-dat-ii/train.csv')\ntest_raw = pd.read_csv('../input/cat-in-the-dat-ii/test.csv')\n\nprint(train_raw.shape, test_raw.shape)\ntrain_raw.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_raw.info()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# check for missing values\n# from https://www.kaggle.com/willkoehrsen/start-here-a-gentle-introduction\ndef missing_values_table(df):\n        # Total missing values\n        mis_val = df.isnull().sum()\n        \n        # Percentage of missing values\n        mis_val_percent = 100 * df.isnull().sum() / len(df)\n        \n        # Make a table with the results\n        mis_val_table = pd.concat([mis_val, mis_val_percent], axis=1)\n        \n        # Rename the columns\n        mis_val_table_ren_columns = mis_val_table.rename(\n        columns = {0 : 'Missing Values', 1 : '% of Total Values'})\n        \n        # Sort the table by percentage of missing descending\n        mis_val_table_ren_columns = mis_val_table_ren_columns[\n            mis_val_table_ren_columns.iloc[:,1] != 0].sort_values(\n        '% of Total Values', ascending=False).round(1)\n        \n        # Print some summary information\n        print (\"Your selected dataframe has \" + str(df.shape[1]) + \" columns.\\n\"      \n            \"There are \" + str(mis_val_table_ren_columns.shape[0]) +\n              \" columns that have missing values.\")\n        \n        # Return the dataframe with missing information\n        return mis_val_table_ren_columns","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"missing_values_table(train_raw).head(10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# using seaborns countplot to show distribution of questions in dataset\nfig, ax = plt.subplots()\ng = sns.countplot(train_raw.target, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\n\n# function to show values on bars\ndef show_values_on_bars(axs):\n    def _show_on_single_plot(ax):        \n        for p in ax.patches:\n            _x = p.get_x() + p.get_width() / 2\n            _y = p.get_y() + p.get_height()\n            value = '{:.0f}'.format(p.get_height())\n            ax.text(_x, _y, value, ha=\"center\") \n\n    if isinstance(axs, np.ndarray):\n        for idx, ax in np.ndenumerate(axs):\n            _show_on_single_plot(ax)\n    else:\n        _show_on_single_plot(axs)\nshow_values_on_bars(ax)\n\nsns.despine(left=True, bottom=True)\nplt.xlabel('')\nplt.ylabel('')\nplt.title('Distribution of Target', fontsize=30)\nplt.tick_params(axis='x', which='major', labelsize=15)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Binary Features\nBinary features are those with only two possible values.\n  \nWe have five binary features.  The first three are already numeric and don't require encoding,  `bin_3` and `bin_4` are strings that will need to be encoded.  "},{"metadata":{"trusted":true},"cell_type":"code","source":"binary_features = train_raw[['bin_0', 'bin_1', 'bin_2', 'bin_3', 'bin_4']].copy()\nbinary_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def encode_binary_features(df):\n    df['bin_3'] = df['bin_3'].replace({'T':1, 'F':0})\n    df['bin_4'] = df['bin_4'].replace({'Y':1, 'N':0})\n    return df\n\nbinary_features = encode_binary_features(binary_features)\nbinary_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# using seaborns countplot to show distribution of binary features\nfig, ax = plt.subplots()\nax = plt.subplot(231)\ng = sns.countplot(binary_features.bin_0, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\nplt.title('Distribution of bin_0', fontsize=20)\nshow_values_on_bars(ax)\nplt.xlabel('')\nplt.ylabel('')\n\nax = plt.subplot(232)\ng = sns.countplot(binary_features.bin_1, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\nplt.title('Distribution of bin_1', fontsize=20)\nshow_values_on_bars(ax)\nplt.xlabel('')\nplt.ylabel('')\n\nax = plt.subplot(233)\ng = sns.countplot(binary_features.bin_2, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\nplt.title('Distribution of bin_2', fontsize=20)\nshow_values_on_bars(ax)\nplt.xlabel('')\nplt.ylabel('')\n\nax = plt.subplot(234)\ng = sns.countplot(binary_features.bin_3, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\nplt.title('Distribution of bin_3', fontsize=20)\nshow_values_on_bars(ax)\nplt.xlabel('')\nplt.ylabel('')\n\nax = plt.subplot(235)\ng = sns.countplot(binary_features.bin_4, palette='viridis')\ng.set_xticklabels(['0', '1'])\ng.set_yticklabels([])\nplt.title('Distribution of bin_5', fontsize=20)\nshow_values_on_bars(ax)\nplt.xlabel('')\nplt.ylabel('')\n\nplt.subplots_adjust(hspace = 0.3, wspace=.3)\nsns.despine(left=True, bottom=True)\nplt.tick_params(axis='x', which='major', labelsize=15)\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Ordinal Features  \n\nOrdinal features are those with some order associated with them. We can tell from the sample of ordinal features below these features have an order that may be important. \n  \nThe machine learning model may be able to use the order information to make better predictions and we want to preserve it."},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.preprocessing import LabelEncoder\n\n#label encoder can't handle missing values\nordinal_features['ord_1'] = ordinal_features['ord_1'].fillna('None')\n\n# Label encode ord_1 feature\nlabel_encoder = LabelEncoder()\nordinal_features['ord_1'] = label_encoder.fit_transform(ordinal_features['ord_1'])\n\n# Print sample of dataset\nordinal_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"ordinal_features = train_raw[['ord_0', 'ord_1', 'ord_2', 'ord_3', 'ord_4', 'ord_5']].copy()\nordinal_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def encode_ordinal_features(df):\n    ord_1 = {'Novice':1, \n            'Contributor':2, \n            'Expert':4, \n            'Master':5, \n            'Grandmaster':6}\n    df['ord_1'] = df.ord_1.map(ord_1)\n    ord_2 = {'Freezing':1, \n            'Cold':2, \n            'Warm':3, \n            'Hot':4, \n            'Boiling Hot':5, \n            'Lava Hot':6}\n    df['ord_2'] = df.ord_2.map(ord_2)\n    return df\n\n\nordinal_features = encode_ordinal_features(ordinal_features)\nordinal_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# start over with a clean copy from our raw data\nordinal_features = train_raw[['ord_0', 'ord_1', 'ord_2', 'ord_3', 'ord_4', 'ord_5']].copy()\nordinal_features.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Nominal Features\n\nNominal features are categorical features that have no numerical importance. Order does not matter."},{"metadata":{"trusted":true},"cell_type":"code","source":"nominal_features = pd.get_dummies(nominal_features, drop_first=True)\nnominal_features.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nominal_features = train_raw[['nom_0','nom_1','nom_2','nom_3','nom_4','nom_5','nom_6','nom_7','nom_8','nom_9']].copy()\nnominal_features.head()","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}