<jupyter_start><jupyter_text>MultiLayer Perceptron Classification Example A data set that identifies different types of Iris's is used to demonstrate the use of multi layer perceptron in SAP HANA.  This data set is also used in a clustering example where the objective was to cluster the flowers into three clusters and the intuition was that the three clusters would correspond to the three types of Iris's in the data set.  Since we know the labels (i.e. the types of Iris's), we can use classification to create a model to predict the type of flower based on features or characteristics that are explained below. Iris Data SetThe data set used is from University of California, Irvine (https://archive.ics.uci.edu/ml/datasets/iris).  This data set contains attributes of a plant iris.  There are three species of Iris plants.Iris SetosaIris VersicolorIris VirginicaThe data contains the following attributes for various flowers:sepal length in cmsepal width in cmpetal length in cmpetal width in cmAlthough the flower is identified in the data set, we will cluster the data set into 3 clusters since we know there are three different flowers.  The hope is that the cluster will correspond to each of the flowers.A different notebook will use a classification algorithm to predict the type of flower based on the sepal and petal dimensions.<jupyter_code>%matplotlib inline
from hana_ml import dataframe
from hana_ml.algorithms.pal.neural_network import MLPClassifier, MLPRegressor
from hana_ml.algorithms.pal import metrics<jupyter_output><empty_output><jupyter_text>Load dataThe data is loaded into 4 tables - full set, test set, training set, and the validation set:IRIS_DATA_FULL_TBLIRIS_DATA_TRAIN_TBLIRIS_DATA_TEST_TBLIRIS_DATA_VALIDATION_TBLTo do that, a connection is created and passed to the loader.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.[hana]url=host.sjc.sap.corpuser=usernamepasswd=<PASSWORD>port=3xx15<jupyter_code>from data_load_utils import DataSets, Settings
import plotting_utils
url, port, user, pwd = Settings.load_config("../../config/e2edata.ini")
connection_context = dataframe.ConnectionContext(url, port, user, pwd)
full_tbl, training_tbl, validation_tbl, test_tbl = DataSets.load_iris_data(connection_context)<jupyter_output><empty_output><jupyter_text>Create Data FramesCreate the data frames for the full, test, training, and validation sets.Let us also do some data exploration.  Define Datasets - Training, validation, and test setsData frames are used keep references to data so computation on large data sets in HANA can happen in HANA.  Trying to bring the entire data set into the client will likely result in out of memory exceptions.The original/full dataset is split into training, test and validation sets.  In the example below, they reside in different tables.<jupyter_code>full_set = connection_context.table(full_tbl)
training_set = connection_context.table(training_tbl)
validation_set = connection_context.table(validation_tbl)
test_set = connection_context.table(test_tbl)<jupyter_output><empty_output><jupyter_text>Simple ExplorationLet us look at the number of rows in the data set<jupyter_code>print('Number of rows in full set: {}'.format(full_set.count()))
print('Number of rows in training set: {}'.format(training_set.count()))
print('Number of rows in validation set: {}'.format(validation_set.count()))
print('Number of rows in test set: {}'.format(test_set.count()))<jupyter_output>Number of rows in full set: 150
Number of rows in training set: 105
Number of rows in validation set: 105
Number of rows in test set: 45<jupyter_text>Let's look at the columns<jupyter_code>print(full_set.columns)<jupyter_output>['ID', 'SEPALLENGTHCM', 'SEPALWIDTHCM', 'PETALLENGTHCM', 'PETALWIDTHCM', 'SPECIES']<jupyter_text>Let us look at some rows<jupyter_code>full_set.head(5).collect()<jupyter_output><empty_output><jupyter_text>Let's look at the data types<jupyter_code>full_set.dtypes()<jupyter_output><empty_output><jupyter_text>Let's check how many SPECIES are in the data set.<jupyter_code>full_set.distinct("SPECIES").collect()<jupyter_output><empty_output><jupyter_text>Create ModelThe lines below show the ease with which clustering can be done. Set up the features and labels for the model and create the model<jupyter_code>%matplotlib inline
from plotting_utils import DrawNN
features = ['SEPALLENGTHCM','SEPALWIDTHCM','PETALLENGTHCM','PETALWIDTHCM']
label = 'SPECIES'<jupyter_output><empty_output><jupyter_text>Neural Network Architecture<jupyter_code>network = DrawNN( [1, 10, 1] )
network.draw(False)<jupyter_output><empty_output><jupyter_text>Model Creation<jupyter_code>mlpc = MLPClassifier(connection_context, hidden_layer_size=(10,), activation='TANH', output_activation='TANH',
                     training_style='batch', max_iter=100, normalization='z-transform',
                     weight_init='uniform', thread_ratio=1)
mlpc.fit(training_set, 'ID', features, label)<jupyter_output><empty_output><jupyter_text>Evaluation  AccuracyLet us compute the accuracy on our training and test sets<jupyter_code>accuracy = mlpc.score(training_set, 'ID', features, label)
print("Training set accuracy: %f" % accuracy)
print("Test set accuracy: %f" % mlpc.score(test_set, 'ID', features, label))<jupyter_output>Training set accuracy: 0.980952
Test set accuracy: 0.977778<jupyter_text>Precision, Recall, Confusion MatrixAccuracy is usually not a good metric to evaluate a model.  Above, we see that we do pretty well for both the training and test sets.Let us look at another metric.To do that we first inspect the results of our test_set predictions<jupyter_code>predictions_df, soft_max_df = mlpc.predict(test_set, 'ID', features)
print(soft_max_df.head(5).collect())<jupyter_output>ID            CLASS  SOFTMAX_VALUE
0   1      Iris-setosa       0.582557
1   1  Iris-versicolor       0.206906
2   1   Iris-virginica       0.210537
3   2      Iris-setosa       0.592538
4   2  Iris-versicolor       0.199749<jupyter_text>The function to get the confusion matrix takes in a single data frame with the true label and the predicted label.So, let us construct this data frame by joining on the ID column.<jupyter_code>ts = test_set.rename_columns({'ID': 'TID'}) #.cast('SPECIES', 'NVARCHAR(256)')
jsql = '{}."{}"={}."{}"'.format(predictions_df.quoted_name, 'ID', ts.quoted_name, 'TID')
results_df = predictions_df.join(ts, jsql, how='inner')
cm_df, classification_report_df = metrics.confusion_matrix(connection_context, results_df, key='ID', label_true='SPECIES', label_pred='TARGET') 
print("Confusion Matrix")
cm_df.collect()
import matplotlib.pyplot as plt
from hana_ml.visualizers.metrics import MetricsVisualizer
f, ax1 = plt.subplots(1,1)
mv1 = MetricsVisualizer(ax1)
ax1 = mv1.plot_confusion_matrix(cm_df, normalize=False)
print("Recall, precision, and F-measures")
classification_report_df.collect()<jupyter_output>Recall, precision, and F-measures
{'fraction_non_alphanumeric': 0.08193103448275862, 'fraction_numerical': 0.013655172413793104, 'mean_word_length': 6.0810546875, 'pattern_counts': {'":': 0, '<': 53, '<?xml version=': 0, '>': 53, 'https://': 1, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '14', 'dir': 'jupyter-structured-clean-dedup', 'id': '98089', 'license': 'BSD-Source-Code', 'n_tokens_mistral': 2271, 'n_tokens_neox': 2165, 'n_words': 759, 'path': 'Python-API/pal/notebooks/irisFlowerClassificationMLP.ipynb', 'repo_name': 'BrookZX/hana-ml-samples', 'size': '7252'}