{ "cells": [ { "cell_type": "markdown", "source": [ "# Hybrid Gradient Boosting Trees Example via Unified Classification\n", "\n", "A data set that identifies whether or not a pentient has diabetes is used to demonstrate the use of hybrid graident boosting classifier in SAP HANA.\n", "\n" ], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Pima Indians Diabetes Dataset\n", "\n", "Original data comes from National Institute of Diabetes and Digestive and Kidney Diseases. The collected dataset is aiming at, based on certain diagnostic measurements, diagnostically predicting whether or not a patient has diabetes. In particular, patients contained in the dataset are females of Pima Indian heritage, all above the age of 20. Dataset is form Kaggle, for tutorials use only.\n", "\n", "The dataset contains the following diagnositic attributes:
\n", "$\\rhd$ \"PREGNANCIES\" - Number of times pregnant,
\n", "$\\rhd$ \"GLUCOSE\" - Plasma glucose concentration a 2 hours in an oral glucose tolerance test,
\n", "$\\rhd$ \"BLOODPRESSURE\" - Diastolic blood pressure (mm Hg),
\n", "$\\rhd$ \"SKINTHICKNESS\" - Triceps skin fold thickness (mm),
\n", "$\\rhd$ \"INSULIN\" - 2-Hour serum insulin (mu U/ml),
\n", "$\\rhd$ \"BMI\" - Body mass index $(\\text{weight in kg})/(\\text{height in m})^2$,
\n", "$\\rhd$ \"PEDIGREE\" - Diabetes pedigree function,
\n", "$\\rhd$ \"AGE\" - Age (years),
\n", "$\\rhd$ \"CLASS\" - Class variable (0 or 1) 268 of 768 are 1(diabetes), the others are 0(non-diabetes).\n", "\n" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "import hana_ml\r\n", "from hana_ml import dataframe\r\n", "from hana_ml.algorithms.pal import metrics\r\n", "from hana_ml.algorithms.pal.unified_classification import UnifiedClassification" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Load Data\n", "\n", "The data is loaded into 3 tables - full set, training-validation set, and test set as follows:\n", "\n", "
  • PIMA_INDIANS_DIABETES_TBL
  • \n", "
  • PIMA_INDIANS_DIABETES_TRAIN_VALID_TBL
  • \n", "
  • PIMA_INDIANS_DIABETES_TEST_TBL
  • \n", "\n", "To do that, a connection is created and passed to the loader.\n", "\n", "There is a config file, config/e2edata.ini that controls the connection parameters and whether or not to reload the data from scratch. In case the data is already loaded, there would be no need to load the data. A sample section is below. If the config parameter, reload_data is true then the tables for test, training and validation are (re-)created and data inserted into them.\n", "\n", "#########################
    \n", "[hana]
    \n", "url=host.sjc.sap.corp
    \n", "user=username
    \n", "passwd=userpassword
    \n", "port=3xx15
    \n", "#########################
    " ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.algorithms.pal.utility import DataSets, Settings\r\n", "import plotting_utils\r\n", "url, port, user, pwd = Settings.load_config(\"../../config/e2edata.ini\")\r\n", "connection_context = dataframe.ConnectionContext(url, port, user, pwd)\r\n", "full_set, diabetes_train, diabetes_test, _ = DataSets.load_diabetes_data(connection_context)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.algorithms.pal.utility import Settings\r\n", "\r\n", "Settings.set_log_level()" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Simple Exploration\n", "\n", "Let us look at the number of rows in each dataset:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "print('Number of rows in training set: {}'.format(diabetes_train.count()))\r\n", "print('Number of rows in testing set: {}'.format(diabetes_test.count()))" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "Let us look at columns of the dataset:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "print(diabetes_train.columns)" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "Let us also look some (in this example, the top 6) rows of the dataset:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "diabetes_train.head(6).collect()" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "We can also check the data type of all columns:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "diabetes_train.dtypes()" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "We have a 'CLASS' column in the dataset, let us check how many classes are contained in this dataset:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "diabetes_train.distinct('CLASS').collect()" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "Two classes are available, assuring that this is a binary classification problem." ], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Model Creation & Model Selection\n", "The lines below show the ease with which classification can be done.\n", "\n", "Set up the label column, use default feature set and create the model:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "cv_values = {}\r\n", "cv_values['learning_rate'] = [0.1, 0.4, 0.7, 1.0]\r\n", "cv_values['n_estimators'] = [4, 6, 8, 10]\r\n", "cv_values['split_threshold'] = [0.1, 0.4, 0.7, 1.0]\r\n", "hgc = UnifiedClassification(func='HybridGradientBoostingTree',\r\n", " param_search_strategy='grid',\r\n", " resampling_method='cv',\r\n", " evaluation_metric='error_rate',\r\n", " ref_metric=['auc'],\r\n", " fold_num=5,\r\n", " random_state=1,\r\n", " param_values=cv_values)\r\n", "hgc.fit(diabetes_train, key='ID', label='CLASS',\r\n", " partition_method='stratified',\r\n", " partition_random_state=1,\r\n", " stratified_column='CLASS')" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.model_storage import ModelStorage\r\n", "#from hana_ml.model_storage_services import ModelSavingServices\r\n", "\r\n", "\r\n", "# Creates an object called model_storage which must use the same connection with the model\r\n", "model_storage = ModelStorage(connection_context=connection_context)\r\n", "model_storage.clean_up()\r\n", "# Saves the model for the first time\r\n", "hgc.name = 'Model A' # The model name is mandatory\r\n", "hgc.version = 1\r\n", "model_storage.save_model(model=hgc)\r\n", "\r\n", "# Lists models\r\n", "model_storage.list_models()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "# plan the schedule\r\n", "\r\n", "model_storage.set_schedule(name='Model A',\r\n", " version=1,\r\n", " schedule_time='every 3 minutes',\r\n", " connection_userkey='raymondyao',\r\n", " init_params={\"func\" : 'HybridGradientBoostingTree',\r\n", " \"param_search_strategy\" : 'grid',\r\n", " \"resampling_method\" : 'cv',\r\n", " \"evaluation_metric\" : 'error_rate',\r\n", " \"ref_metric\" : ['auc'],\r\n", " \"fold_num\" : 5,\r\n", " \"random_state\" : 1,\r\n", " \"param_values\" : {'learning_rate': [0.1, 0.4, 0.7, 1],\r\n", " 'n_estimators': [4, 6, 8, 10],\r\n", " 'split_threshold': [0.1, 0.4, 0.7, 1]}},\r\n", " fit_params={\"key\" : 'ID',\r\n", " \"label\" : 'CLASS',\r\n", " \"partition_method\" : 'stratified',\r\n", " \"partition_random_state\" : 1,\r\n", " \"stratified_column\" : 'CLASS'},\r\n", " training_dataset_select_statement=\"SELECT * FROM DIABETES_TRAIN\"\r\n", " )" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "model_storage.start_schedule('Model A', 1)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "model_storage.list_models().iat[0, 7]" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "model_storage.terminate_schedule('Model A', 1)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "model_storage.list_models().iat[0, 7]" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.algorithms.pal.model_selection import GridSearchCV\r\n", "from hana_ml.algorithms.pal.model_selection import RandomSearchCV\r\n", "hgc2 = UnifiedClassification('HybridGradientBoostingTree')\r\n", "\r\n", "gscv = GridSearchCV(estimator=hgc2, \r\n", " param_grid={'learning_rate': [0.1, 0.4, 0.7, 1],\r\n", " 'n_estimators': [4, 6, 8, 10],\r\n", " 'split_threshold': [0.1, 0.4, 0.7, 1]},\r\n", " train_control=dict(fold_num=5,\r\n", " resampling_method='cv',\r\n", " random_state=1,\r\n", " ref_metric=['auc']),\r\n", " scoring='error_rate')\r\n", "gscv.fit(data=diabetes_train, key= 'ID',\r\n", " label='CLASS',\r\n", " partition_method='stratified',\r\n", " partition_random_state=1,\r\n", " stratified_column='CLASS',\r\n", " build_report=True)" ], "outputs": [], "metadata": {} }, { "cell_type": "markdown", "source": [ "# Evaluation\n", "\n", "Let us compare cross-validation accuracy and test accuracy:" ], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "cm = hgc.confusion_matrix_.collect()\n", "cm" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "gscv.estimator.confusion_matrix_.collect()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "train_accuracy = float(cm['COUNT'][cm['ACTUAL_CLASS']==cm['PREDICTED_CLASS']].sum())/cm['COUNT'].sum()\n", "train_accuracy" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "features = diabetes_train.columns\r\n", "features.remove('CLASS')\r\n", "features.remove('ID')\r\n", "print(features)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "pred_res = hgc.predict(diabetes_test, key='ID', features=features)\r\n", "pred_res.head(10).collect()\r\n", "pred_res.dtypes()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "ts = diabetes_test.rename_columns({'ID': 'TID'}) .cast('CLASS', 'NVARCHAR(256)')\r\n", "jsql = '{}.\"{}\"={}.\"{}\"'.format(pred_res.quoted_name, 'ID', ts.quoted_name, 'TID')\r\n", "results_df = pred_res.join(ts, jsql, how='inner')\r\n", "cm_df, classification_report_df = metrics.confusion_matrix(results_df, key='ID', label_true='CLASS', label_pred='SCORE') " ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "import matplotlib.pyplot as plt\r\n", "from hana_ml.visualizers.metrics import MetricsVisualizer\r\n", "f, ax1 = plt.subplots(1,1)\r\n", "mv1 = MetricsVisualizer(ax1)\r\n", "ax1 = mv1.plot_confusion_matrix(cm_df, normalize=False)" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "print(\"Recall, Precision and F_measures.\")\r\n", "classification_report_df.collect()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "_,_,_,metrics_res = hgc.score(data=diabetes_test, key='ID', label='CLASS')\r\n", "metrics_res.collect()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.model_storage import ModelStorage\r\n", "\r\n", "model_storage = ModelStorage(connection_context=connection_context)\r\n", "gscv.estimator.name = 'HGBT' \r\n", "gscv.estimator.version = 1\r\n", "model_storage.save_model(model=gscv.estimator)\r\n", "# Lists models\r\n", "model_storage.list_models()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "from hana_ml.visualizers.unified_report import UnifiedReport\r\n", "\r\n", "mymodel = model_storage.load_model('HGBT', 1)\r\n", "mymodel.fit(data=diabetes_train, key= 'ID',\r\n", " label='CLASS',\r\n", " partition_method='stratified',\r\n", " partition_random_state=1,\r\n", " stratified_column='CLASS',\r\n", " build_report=True)\r\n", "UnifiedReport(mymodel).display()" ], "outputs": [], "metadata": {} }, { "cell_type": "code", "execution_count": null, "source": [ "model_storage.delete_model('HGBT', 1)\r\n", "connection_context.close()" ], "outputs": [], "metadata": {} } ], "metadata": { "kernelspec": { "name": "python3", "display_name": "Python 3.9.1 64-bit ('base': conda)" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.1" }, "interpreter": { "hash": "9e8e26eb492012ce43ec3ea98c3fc2503d5495ecd40107dd94395e1e0d860e85" } }, "nbformat": 4, "nbformat_minor": 4 }