[c1ec9e]: / code / CNN_Impersonal_TransformedData.ipynb

Download this file

766 lines (765 with data), 52.3 kB

{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Imports the required libraries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "\"\"\" Imports the required libraries \"\"\"\n",
    "\n",
    "# import tensorflow as tf\n",
    "import keras\n",
    "from keras.models import Sequential\n",
    "from keras.optimizers import Adam\n",
    "from keras.layers import Dense, Activation, Conv1D, MaxPooling1D, MaxPooling2D\n",
    "from keras.layers import Flatten, Dropout, BatchNormalization, Reshape\n",
    "from keras.utils.vis_utils import plot_model\n",
    "from keras.wrappers.scikit_learn import KerasClassifier\n",
    "\n",
    "import os\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import seaborn as sns\n",
    "import matplotlib.pyplot as plt\n",
    "from mlxtend.plotting import plot_confusion_matrix\n",
    "\n",
    "import sklearn\n",
    "from sklearn.model_selection import train_test_split, cross_val_score, KFold\n",
    "from sklearn.preprocessing import StandardScaler, LabelEncoder\n",
    "from sklearn.metrics import classification_report, confusion_matrix\n",
    "from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Stores the path of the sensor files in the corresponding list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\" Stores the path of the sensor files in the corresponding list \"\"\"\n",
    "\n",
    "base_path = \"./data/transformed_data/\"\n",
    "phone_accel_file_paths = []\n",
    "phone_gyro_file_paths = []\n",
    "watch_accel_file_paths = []\n",
    "watch_gyro_file_paths = []\n",
    "\n",
    "for directories, subdirectories, files in os.walk(base_path):\n",
    "    for filename in files:\n",
    "        if \"phone\" in filename and \"accel\" in filename:\n",
    "            phone_accel_file_paths.append(f\"{base_path}phone/accel/{filename}\")\n",
    "        elif \"phone\" in filename and \"gyro\" in filename:\n",
    "            phone_gyro_file_paths.append(f\"{base_path}phone/gyro/{filename}\")\n",
    "        elif \"watch\" in filename and \"accel\" in filename:\n",
    "            watch_accel_file_paths.append(f\"{base_path}watch/accel/{filename}\")\n",
    "        elif \"watch\" in filename and \"gyro\" in filename:\n",
    "            watch_gyro_file_paths.append(f\"{base_path}watch/gyro/{filename}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Stores the actual name of each activity in the dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\" Stores the actual name of each activity in the dictionary \"\"\"\n",
    "\n",
    "activity_dict= {\"A\":\"Walking\",\n",
    "                \"B\":\"Jogging\",\n",
    "                \"C\":\"Stairs\",\n",
    "                \"D\":\"Sitting\",\n",
    "                \"E\":\"Standing\",\n",
    "                \"F\":\"Typing\",\n",
    "                \"G\":\"Brushing\",\n",
    "                \"H\":\"Eat Soup\",\n",
    "                \"I\":\"Eat Chips\",\n",
    "                \"J\":\"Eat Pasta\",\n",
    "                \"K\":\"Drinking\",\n",
    "                \"L\":\"Eat Sandwich\",\n",
    "                \"M\":\"Kicking\",\n",
    "                \"O\":\"Playing\",\n",
    "                \"P\":\"Dribblinlg\",\n",
    "                \"Q\":\"Writing\",\n",
    "                \"R\":\"Clapping\",\n",
    "                \"S\":\"Folding\"}\n",
    "\n",
    "def get_key(val): \n",
    "    for key, value in activity_dict.items(): \n",
    "        if val == value: \n",
    "            return key "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Plots the distribution of data among activities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_distribution(data):\n",
    "    \"\"\" Plots the distribution of data among activities \"\"\"\n",
    "    \n",
    "    activity_df = pd.DataFrame()\n",
    "    activity_df[\"Activity\"] = [activity_dict[item] for item in np.unique(data['ACTIVITY'])]\n",
    "    act_percentages = []\n",
    "\n",
    "    for act in activity_df[\"Activity\"]:\n",
    "        act_percentages.append(len(data[data[\"ACTIVITY\"] == get_key(act)])/len(data)*100)\n",
    "    activity_df[\"Distr. of Data Among Activities %\"] = act_percentages\n",
    "    \n",
    "    sns.set(style=\"whitegrid\")\n",
    "    fig, ax = plt.subplots(figsize=(10, 4))\n",
    "\n",
    "    act = sns.barplot(x=\"Activity\", y=\"Distr. of Data Among Activities %\", data=activity_df)\n",
    "    ax.set_xlabel(\"Activity\", fontsize = 14)\n",
    "    ax.set_ylabel(\"Distr. of Data Among Activities %\", fontsize = 13)\n",
    "#     ax.set_title(\"Distribution of Data Among Activities\", fontsize = 15)\n",
    "    plt.xticks(rotation=90);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Distribution of Data Among Activities"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "image/png": "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IiKigsqogmvDhg04e/YsSpcuDXt7e8THxyM+Ph729vZIS0tDRkYGlixZggYNGuR4/0mTJmH06NF48OBBnjaeiIiIqCAwquCqUqUKmjdvjqFDh+qvW7VqFa5fv45p06Zh3bp1mDlzJjZu3PjGfSMiImBvbw8nJyds3rz5vRt44cIFAEDDhg3f+74fIiYm5o3rmM1sZjOb2cxmNrPfJ/t1RhVc+/fvx59//mlwXd++feHs7Ixp06bBz88Pc+fOzfG+O3bswOPHj+Ht7Y2kpCSkpKRgxowZGD9+vDHRqFOnDiwtLY362bwg1y+H2cxmNrOZzWxmm052WlqavpMoJ0YVXDY2Njh+/DhcXV311504cUI/b+v+/fsoVqxYjvdduXKl/t+bN29GdHS00cUWERERkSkwquD6+uuvMXLkSLi6uqJMmTJ48OABjh07hu+//x7Xrl1Dv379MGTIENFtJSIiIiqQjCq4WrdujWrVqmHHjh149OgR6tati3HjxqF8+fJ48OABfvrpJ3zxxRfvfJwuXbqgS5cuH91oIiIiooLE6J3my5UrB19fX2i1Wv119+/fR9myZWFvby+kcURERESmwKiC6/fff0doaChevHihv06SJKhUKly6dElY44iIiIhMgVEF1+LFixEYGAgfHx9oNB90/CIRERHRJ8uo6unJkyfo06cPzMxkPXqRiIiIyCQYVUF5enoiMjJSdFuIiIiITJJRPVxPnz7F2LFjMX/+fJQoUcLgtk2bNglpGBEREZGpMKrg8vLygpeXl+i2EBEREZkkowquzp07AwBu3LiBhw8folSpUqhWrZrQhhERERGZCqMKrkePHiEwMBAXLlxA8eLFkZCQgOrVq2PJkiWws7MT3UYiIiKiAs2oSfNhYWGoVq0aTp06haNHjyI6Ohq1a9dGaGio6PYRERERFXhG9XBFR0fj4MGDsLS0BABYWVlhwoQJcHNzE9o4IiIiIlNgVA+XhYUFnj59anBdQkICrKyshDSKiIiIyJQYPWne398fAQEBsLe3x71797B48WL4+PgIbh4RERFRwWdUwRUQEACtVovp06fjyZMnKFu2LHx8fPDVV1+Jbh8RERFRgWdUwaVWqzFmzBiMGTNGdHuIiIiITI5RBdeVK1fw888/4/79+9BqtQa3cad5IiIiotwZVXB98803qFmzJvz8/HiANREREdF7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\n",
      "text/plain": [
       "<Figure size 720x288 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "data = pd.read_csv(\"./data/raw_data/all_data.csv\", verbose=False)\n",
    "plot_distribution(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### The data is slightly imbalanced\n",
    "#### In order to balance the data, the first 17 data rows of each activity are taken"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "def balance_data(dataframe):\n",
    "    \"\"\"  Takes only the first 17 data rows for each activity \"\"\"\n",
    "\n",
    "    A = dataframe[dataframe['ACTIVITY']=='A'].head(17).copy()\n",
    "    B = dataframe[dataframe['ACTIVITY']=='B'].head(17).copy()\n",
    "    C = dataframe[dataframe['ACTIVITY']=='C'].head(17).copy()\n",
    "    D = dataframe[dataframe['ACTIVITY']=='D'].head(17).copy()\n",
    "    E = dataframe[dataframe['ACTIVITY']=='E'].head(17).copy()\n",
    "    F = dataframe[dataframe['ACTIVITY']=='F'].head(17).copy()\n",
    "    G = dataframe[dataframe['ACTIVITY']=='G'].head(17).copy()\n",
    "    H = dataframe[dataframe['ACTIVITY']=='H'].head(17).copy()\n",
    "    I = dataframe[dataframe['ACTIVITY']=='I'].head(17).copy()\n",
    "    J = dataframe[dataframe['ACTIVITY']=='J'].head(17).copy()\n",
    "    K = dataframe[dataframe['ACTIVITY']=='K'].head(17).copy()\n",
    "    L = dataframe[dataframe['ACTIVITY']=='L'].head(17).copy()\n",
    "    M = dataframe[dataframe['ACTIVITY']=='M'].head(17).copy()\n",
    "    O = dataframe[dataframe['ACTIVITY']=='O'].head(17).copy()\n",
    "    P = dataframe[dataframe['ACTIVITY']=='P'].head(17).copy()\n",
    "    Q = dataframe[dataframe['ACTIVITY']=='Q'].head(17).copy()\n",
    "    R = dataframe[dataframe['ACTIVITY']=='R'].head(17).copy()\n",
    "    S = dataframe[dataframe['ACTIVITY']=='S'].head(17).copy()\n",
    "\n",
    "    balanced_data = pd.DataFrame()\n",
    "    balanced_data = balanced_data.append([A, B, C, D, E, F, G, H, I, J, K, L, M, O, P, Q, R, S], ignore_index=True)\n",
    "\n",
    "    return balanced_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Imports and merges all the dataframes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def import_data(file_path):\n",
    "    \"\"\" Imports and merges all the dataframes \"\"\"\n",
    "    \n",
    "    dataframes = []\n",
    "    \n",
    "    for subjectid, file in enumerate(file_path):\n",
    "        df = pd.read_csv(file, verbose=False)\n",
    "        balanced_data = balance_data(df)\n",
    "        dataframes.append(balanced_data)\n",
    "\n",
    "    merged_data = pd.concat(dataframes[:])\n",
    "\n",
    "    return merged_data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Takes only 43 important features of the dataframe"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "def clean_data(dataframe):\n",
    "    \"\"\" Removes the columns \"ACTIVITY\" and \"class\" from the dataframe \"\"\"\n",
    "    \"\"\" Takes only 43 important features of the dataframe  \"\"\"\n",
    "    \n",
    "    df = dataframe.drop(['ACTIVITY', 'class'], axis = 1).copy()\n",
    "    x1 = df.loc[:, \"X0\":\"ZSTANDDEV\"]\n",
    "    x2 = df.loc[:, \"RESULTANT\"]   \n",
    "    cleaned_df = pd.concat([x1, x2], axis=1, join='inner')\n",
    "    \n",
    "    return cleaned_df "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Normalizes the data using StandardScaler() function"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "def scale_data(data, labels):\n",
    "    \"\"\" Normalizes the data using StandardScaler() function \"\"\"\n",
    "\n",
    "    le = LabelEncoder()\n",
    "    activity_labels = le.fit_transform(labels)\n",
    "    \n",
    "    scaler = StandardScaler().fit(data)\n",
    "    scaled_data = scaler.transform(data)\n",
    "    \n",
    "    X_train = scaled_data\n",
    "    y_train = activity_labels\n",
    "    \n",
    "    return X_train, y_train"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Decodes the activity labels and stores them in a dictionary"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "def activity_dictionary(dataframe):    \n",
    "    \"\"\" Decodes the activity labels and stores them in a dictionary \"\"\"\n",
    "\n",
    "    activity_labels = dataframe[\"ACTIVITY\"]\n",
    "    le = LabelEncoder()\n",
    "    activity_indices = le.fit_transform(activity_labels)\n",
    "    mapped_labels = dict(zip(le.transform(le.classes_), le.classes_))\n",
    "    \n",
    "    return mapped_labels"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Preprocesses the data using clean() and scale() functions"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "def preprocess_data(dataframe):\n",
    "    \"\"\" Preprocesses the data using clean() and scale() functions \"\"\"\n",
    "\n",
    "    activity_labels = dataframe[\"ACTIVITY\"]\n",
    "    cleaned_df = clean_data(dataframe)\n",
    "    \n",
    "    return scale_data(cleaned_df, activity_labels)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Plots training & validation accuracy values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_learningCurve(history, epochs):\n",
    "    \"\"\" Plots training & validation accuracy values \"\"\"\n",
    "\n",
    "    epoch_range = range(1, epochs+1)\n",
    "    plt.plot(epoch_range, history.history['accuracy'])\n",
    "    plt.plot(epoch_range, history.history[\"val_accuracy\"])\n",
    "    plt.title('Model accuracy')\n",
    "    plt.ylabel('Accuracy')\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.legend(['Train', 'Val'], loc='lower right')\n",
    "    plt.show()\n",
    "    \n",
    "    \"\"\" Plots training & validation loss values \"\"\"\n",
    "    \n",
    "    plt.plot(epoch_range, history.history['loss'])\n",
    "    plt.plot(epoch_range, history.history['val_loss'])\n",
    "    plt.title('Model loss')\n",
    "    plt.ylabel('Loss')\n",
    "    plt.xlabel('Epoch')\n",
    "    plt.legend(['Train', 'Val'], loc='upper right')\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##### Builds the model (the Convolutional Neural Network)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_model():\n",
    "    \"\"\" Builds the model (the Convolutional Neural Network) \"\"\"\n",
    "    \n",
    "    # Defines model\n",
    "    model = Sequential()\n",
    "    model.add(Conv1D(filters=43, kernel_size=1, activation='relu', input_shape=(1,43)))\n",
    "#     model.add(Conv1D(filters=64, kernel_size=1, activation='relu'))\n",
    "#     model.add(Dropout(0.5))\n",
    "#     model.add(MaxPooling1D(pool_size=1))\n",
    "    model.add(Flatten())\n",
    "#     model.add(Dense(256, activation='relu',name='D1'))\n",
    "#     model.add(Dense(128, activation='relu'))\n",
    "#     model.add(Dense(128, activation='relu'))\n",
    "    model.add(Dense(64, activation='relu'))\n",
    "    model.add(Dense(64, activation='relu'))\n",
    "    model.add(Dropout(0.5))\n",
    "    model.add(Dense(18, activation='softmax'))\n",
    "\n",
    "    # Compiles model\n",
    "    model.compile(optimizer=Adam(learning_rate = 0.001), \n",
    "                  loss='sparse_categorical_crossentropy', \n",
    "                  metrics=['accuracy'])\n",
    "    \n",
    "    return model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phone Accelerometer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "\"\"\" Phone Accelerometer \"\"\"\n",
    "\n",
    "phone_accel_accuracy={}\n",
    "phone_accel_precision={}\n",
    "phone_accel_recall={}\n",
    "phone_accel_f1={}\n",
    "\n",
    "phone_accel_matrix = {}\n",
    "phone_accel_activity_accuracy = {}\n",
    "phone_accel_classification_reports={}\n",
    "\n",
    "df = pd.concat(map(pd.read_csv, phone_accel_file_paths))\n",
    "\n",
    "subjectIDs = df[\"class\"].unique()\n",
    "\n",
    "data = import_data(phone_accel_file_paths)\n",
    "\n",
    "for subjectid in subjectIDs:\n",
    "    activity_labels = list(activity_dictionary(data).values())\n",
    "    \n",
    "    train_data = data[data[\"class\"] != subjectid]\n",
    "    test_data = data[data[\"class\"] == subjectid]\n",
    "    \n",
    "    X_train, y_train = preprocess_data(train_data)\n",
    "    X_test, y_test = preprocess_data(test_data)\n",
    "    \n",
    "    # Makes the input data form 3-Dimensional\n",
    "    X_train = X_train.reshape(X_train.shape[0], 1, 43)\n",
    "    X_test = X_test.reshape(X_test.shape[0], 1, 43)\n",
    "    \n",
    "    model = get_model()\n",
    "        \n",
    "    history = model.fit(X_train, y_train, batch_size=1, epochs=70, verbose=1)\n",
    "\n",
    "    scores = model.evaluate(X_test, y_test, verbose=0)\n",
    "    \n",
    "    y_true = y_test\n",
    "    y_pred = model.predict_classes(X_test, verbose=0)\n",
    "    \n",
    "    # Accuracy: (tp + tn) / (p + n)\n",
    "    phone_accel_accuracy[subjectid] = accuracy_score(y_true, y_pred)\n",
    "\n",
    "    # Precision tp / (tp + fp)\n",
    "    precision = precision_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_accel_precision[subjectid] = dict(zip(activity_labels, precision))\n",
    "\n",
    "    # Recall: tp / (tp + fn)\n",
    "    recall = recall_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_accel_recall[subjectid] = dict(zip(activity_labels, recall))\n",
    "\n",
    "    # F1: 2 tp / (2 tp + fp + fn)\n",
    "    f1 = f1_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_accel_f1[subjectid] = dict(zip(activity_labels, f1))\n",
    "    \n",
    "    phone_accel_classification_reports[subjectid] = classification_report(y_test, y_pred, zero_division=1)\n",
    "    \n",
    "    matrix = confusion_matrix(y_test, y_pred)\n",
    "    phone_accel_matrix[subjectid] = matrix\n",
    "    \n",
    "    accu_per_class = matrix.diagonal()/ matrix.sum(axis=1)\n",
    "    phone_accel_activity_accuracy[subjectid] = dict(zip(activity_labels, accu_per_class))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Phone Gyroscope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\" Phone Gyroscope \"\"\"\n",
    "\n",
    "phone_gyro_accuracy={}\n",
    "phone_gyro_precision={}\n",
    "phone_gyro_recall={}\n",
    "phone_gyro_f1={}\n",
    "\n",
    "phone_gyro_matrix = {}\n",
    "phone_gyro_activity_accuracy = {}\n",
    "phone_gyro_classification_reports={}\n",
    "\n",
    "df = pd.concat(map(pd.read_csv, phone_gyro_file_paths))\n",
    "\n",
    "subjectIDs = df[\"class\"].unique()\n",
    "\n",
    "data = import_data(phone_gyro_file_paths)\n",
    "\n",
    "for subjectid in subjectIDs:\n",
    "    activity_labels = list(activity_dictionary(data).values())\n",
    "    \n",
    "    train_data = data[data[\"class\"] != subjectid]\n",
    "    test_data = data[data[\"class\"] == subjectid]\n",
    "    \n",
    "    X_train, y_train = preprocess_data(train_data)\n",
    "    X_test, y_test = preprocess_data(test_data)\n",
    "    \n",
    "    # Makes the input data form 3-Dimensional\n",
    "    X_train = X_train.reshape(X_train.shape[0], 1, 43)\n",
    "    X_test = X_test.reshape(X_test.shape[0], 1, 43)\n",
    "    \n",
    "    model = get_model()\n",
    "        \n",
    "    history = model.fit(X_train, y_train, batch_size=1, epochs=70, verbose=1)\n",
    "\n",
    "    scores = model.evaluate(X_test, y_test, verbose=0)\n",
    "    \n",
    "    y_true = y_test\n",
    "    y_pred = model.predict_classes(X_test, verbose=0)\n",
    "    \n",
    "    # Accuracy: (tp + tn) / (p + n)\n",
    "    phone_gyro_accuracy[subjectid] = accuracy_score(y_true, y_pred)\n",
    "\n",
    "    # Precision tp / (tp + fp)\n",
    "    precision = precision_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_gyro_precision[subjectid] = dict(zip(activity_labels, precision))\n",
    "\n",
    "    # Recall: tp / (tp + fn)\n",
    "    recall = recall_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_gyro_recall[subjectid] = dict(zip(activity_labels, recall))\n",
    "\n",
    "    # F1: 2 tp / (2 tp + fp + fn)\n",
    "    f1 = f1_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    phone_gyro_f1[subjectid] = dict(zip(activity_labels, f1))\n",
    "    \n",
    "    phone_gyro_classification_reports[subjectid] = classification_report(y_test, y_pred, zero_division=1)\n",
    "    \n",
    "    matrix = confusion_matrix(y_test, y_pred)\n",
    "    phone_gyro_matrix[subjectid] = matrix\n",
    "    \n",
    "    accu_per_class = matrix.diagonal()/ matrix.sum(axis=1)\n",
    "    phone_gyro_activity_accuracy[subjectid] = dict(zip(activity_labels, accu_per_class))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Watch Accelerometer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\" Watch Accelerometer \"\"\"\n",
    "\n",
    "watch_accel_accuracy={}\n",
    "watch_accel_precision={}\n",
    "watch_accel_recall={}\n",
    "watch_accel_f1={}\n",
    "\n",
    "watch_accel_matrix = {}\n",
    "watch_accel_activity_accuracy = {}\n",
    "watch_accel_classification_reports={}\n",
    "\n",
    "df = pd.concat(map(pd.read_csv, watch_accel_file_paths))\n",
    "\n",
    "subjectIDs = df[\"class\"].unique()\n",
    "\n",
    "data = import_data(watch_accel_file_paths)\n",
    "\n",
    "for subjectid in subjectIDs:\n",
    "    activity_labels = list(activity_dictionary(data).values())\n",
    "    \n",
    "    train_data = data[data[\"class\"] != subjectid]\n",
    "    test_data = data[data[\"class\"] == subjectid]\n",
    "    \n",
    "    X_train, y_train = preprocess_data(train_data)\n",
    "    X_test, y_test = preprocess_data(test_data)\n",
    "    \n",
    "    # Makes the input data form 3-Dimensional\n",
    "    X_train = X_train.reshape(X_train.shape[0], 1, 43)\n",
    "    X_test = X_test.reshape(X_test.shape[0], 1, 43)\n",
    "    \n",
    "    model = get_model()\n",
    "        \n",
    "    history = model.fit(X_train, y_train, batch_size=1, epochs=70, verbose=1)\n",
    "\n",
    "    scores = model.evaluate(X_test, y_test, verbose=0)\n",
    "    \n",
    "    y_true = y_test\n",
    "    y_pred = model.predict_classes(X_test, verbose=0)\n",
    "    \n",
    "    # Accuracy: (tp + tn) / (p + n)\n",
    "    watch_accel_accuracy[subjectid] = accuracy_score(y_true, y_pred)\n",
    "\n",
    "    # Precision tp / (tp + fp)\n",
    "    precision = precision_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_accel_precision[subjectid] = dict(zip(activity_labels, precision))\n",
    "\n",
    "    # Recall: tp / (tp + fn)\n",
    "    recall = recall_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_accel_recall[subjectid] = dict(zip(activity_labels, recall))\n",
    "\n",
    "    # F1: 2 tp / (2 tp + fp + fn)\n",
    "    f1 = f1_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_accel_f1[subjectid] = dict(zip(activity_labels, f1))\n",
    "    \n",
    "    watch_accel_classification_reports[subjectid] = classification_report(y_test, y_pred, zero_division=1)\n",
    "    \n",
    "    matrix = confusion_matrix(y_test, y_pred)\n",
    "    watch_accel_matrix[subjectid] = matrix\n",
    "    \n",
    "    accu_per_class = matrix.diagonal()/ matrix.sum(axis=1)\n",
    "    watch_accel_activity_accuracy[subjectid] = dict(zip(activity_labels, accu_per_class))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Watch Gyroscope"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [],
   "source": [
    "\"\"\" Watch Gyroscope \"\"\"\n",
    "\n",
    "watch_gyro_accuracy={}\n",
    "watch_gyro_precision={}\n",
    "watch_gyro_recall={}\n",
    "watch_gyro_f1={}\n",
    "\n",
    "watch_gyro_matrix = {}\n",
    "watch_gyro_activity_accuracy = {}\n",
    "watch_gyro_classification_reports={}\n",
    "\n",
    "df = pd.concat(map(pd.read_csv, watch_gyro_file_paths))\n",
    "\n",
    "subjectIDs = df[\"class\"].unique()\n",
    "\n",
    "data = import_data(watch_gyro_file_paths)\n",
    "\n",
    "for subjectid in subjectIDs:\n",
    "    activity_labels = list(activity_dictionary(data).values())\n",
    "    \n",
    "    train_data = data[data[\"class\"] != subjectid]\n",
    "    test_data = data[data[\"class\"] == subjectid]\n",
    "    \n",
    "    X_train, y_train = preprocess_data(train_data)\n",
    "    X_test, y_test = preprocess_data(test_data)\n",
    "    \n",
    "    # Makes the input data form 3-Dimensional\n",
    "    X_train = X_train.reshape(X_train.shape[0], 1, 43)\n",
    "    X_test = X_test.reshape(X_test.shape[0], 1, 43)\n",
    "    \n",
    "    model = get_model()\n",
    "        \n",
    "    history = model.fit(X_train, y_train, batch_size=1, epochs=70, verbose=1)\n",
    "\n",
    "    scores = model.evaluate(X_test, y_test, verbose=0)\n",
    "    \n",
    "    y_true = y_test\n",
    "    y_pred = model.predict_classes(X_test, verbose=0)\n",
    "    \n",
    "    # Accuracy: (tp + tn) / (p + n)\n",
    "    watch_gyro_accuracy[subjectid] = accuracy_score(y_true, y_pred)\n",
    "\n",
    "    # Precision tp / (tp + fp)\n",
    "    precision = precision_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_gyro_precision[subjectid] = dict(zip(activity_labels, precision))\n",
    "\n",
    "    # Recall: tp / (tp + fn)\n",
    "    recall = recall_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_gyro_recall[subjectid] = dict(zip(activity_labels, recall))\n",
    "\n",
    "    # F1: 2 tp / (2 tp + fp + fn)\n",
    "    f1 = f1_score(y_true, y_pred, average=None, zero_division=1)\n",
    "    watch_gyro_f1[subjectid] = dict(zip(activity_labels, f1))\n",
    "    \n",
    "    watch_gyro_classification_reports[subjectid] = classification_report(y_test, y_pred, zero_division=1)\n",
    "    \n",
    "    matrix = confusion_matrix(y_test, y_pred)\n",
    "    watch_gyro_matrix[subjectid] = matrix\n",
    "    \n",
    "    accu_per_class = matrix.diagonal()/ matrix.sum(axis=1)\n",
    "    watch_gyro_activity_accuracy[subjectid] = dict(zip(activity_labels, accu_per_class))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "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.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}