{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<center>\n",
    "<a href=\"http://www.insa-toulouse.fr/\" ><img src=\"http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/logo-insa.jpg\" style=\"float:left; max-width: 120px; display: inline\" alt=\"INSA\"/></a> \n",
    "\n",
    "<a href=\"http://wikistat.fr/\" ><img src=\"http://www.math.univ-toulouse.fr/~besse/Wikistat/Images/wikistat.jpg\" style=\"float:right; max-width: 250px; display: inline\"  alt=\"Wikistat\"/></a>\n",
    "\n",
    "</center>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# [Scénarios d'Exploration Statistique](https://github.com/wikistat/Exploration)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Analyse de signaux  issus d'un *smartphone* en <a href=\"https://www.python.org/\"><img src=\"https://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/Python_logo_and_wordmark.svg/390px-Python_logo_and_wordmark.svg.png\" style=\"max-width: 120px; display: inline\" alt=\"Python\"/></a> avec <a href=\"http://scikit-learn.org/stable/#\"><img src=\"http://scikit-learn.org/stable/_static/scikit-learn-logo-small.png\" style=\"max-width: 100px; display: inline\" alt=\"Scikit-Learn\"/></a>\n",
    "## Données transformées (métier): exploration et première modélisation par [ACP](http://wikistat.fr/pdf/st-m-explo-acp.pdf), [AFD](http://wikistat.fr/pdf/st-m-explo-afd.pdf), [régression logistique](http://wikistat.fr/pdf/st-m-app-rlogit.pdf).\n",
    "\n",
    "### Résumé\n",
    "Ce cas d'usage de [reconnaissance d'activités humaines](https://archive.ics.uci.edu/ml/datasets/Human+Activity+Recognition+Using+Smartphones) à partir des enregistrements d'un smartphone (gyroscope, accéléromètre) est traité pour illustrer les principales étapes d'exploration et apprentissage communes en *science des données* et applicables à des signaux. Les données analysées sont obtenues après transformation \"métier\" des données brutes afin de caractériser au mieux les comportements. Exploration multidimensionnelle par méthodes factorielles, classification non supervisée, avant d'introduire le problème de classification supervisée pour prévoir l'activité. La régression logistique est testée avec succès."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1 Introduction\n",
    "### 1.1 Contexte\n",
    "Les données sont issues de la communauté qui vise la reconnaissance d'activités humaines (*Human activity recognition, HAR*) à partir d’enregistrements, par exemple du gyroscope et de l'accéléromètre d'un smartphone. Voir à ce propos l'[article](https://www.elen.ucl.ac.be/Proceedings/esann/esannpdf/es2013-11.pdf) relatant un colloque de 2013.  \n",
    "\n",
    "Les données publiques disponibles et largement étudiées ont été acquises, décrites et analysées par [Anguita et al. (2013)](). Elles sont accessibles sur le [dépôt](https://archive.ics.uci.edu/ml/datasets/Human+Activity+Recognition+Using+Smartphones) de l'University California Irvine (UCI) consacré à l'apprentissage machine ainsi que sur le site *Kaggle*.\n",
    "\n",
    "L'archive contient les données brutes: accélérations échantillonnnées à 64 htz pendant 2s. Les accélérations en x, y, et z, chacune de 128 colonnes, celles en y soustrayant la gravité naturelle ainsi que les accélérations angulaires (gyroscope) en x, y, et z soit en tout 9 fichiers.\n",
    "\n",
    "Il sagit donc d'un ensemble de signaux comme il est extrêmement fréquent d'en rencontrer en lien avec des objets connectés, ici un smartphone, ou dans tout environnement industriel ou scientifique. Les approches développées dans les calepins traitant de ces données sont tout à fait génériques.\n",
    "\n",
    "L'**archive contient également** deux fichiers `train` et `test` de 561 *features* ou variables \"métier\" calculées dans les domaines temporels et fréquentiels à partir des signaux bruts.\n",
    "\n",
    "Les données, chaque enregistrement échantilloné 128 fois, sont labellisées avec **6 activités** : debout, assis, couché, marche, monter ou descendre un escalier. Il s'agit donc d'un problème de classification supervisée (6 classes) avec 10 299 échantillons pour l'apprentissage, 2 947 pour le test, décrites par 561 variables métiers ou 768 mesures issues de l'échantillonnage des signaux.\n",
    "\n",
    "Voici une liste indicative des variables calculées sur chacune des variables initiales et couples de variables:\n",
    "\n",
    "Name|Signification\n",
    "-|-\n",
    "mean | Mean value\n",
    "std | Standard deviation\n",
    "mad | Median absolute value\n",
    "max | Largest values in array\n",
    "min | Smallest value in array\n",
    "sma | Signal magnitude area\n",
    "energy | Average sum of the squares\n",
    "iqr | Interquartile range\n",
    "entropy | Signal Entropy\n",
    "arCoeff | Autorregresion coefficients\n",
    "correlation | Correlation coefficient\n",
    "maxFreqInd | Largest frequency component\n",
    "meanFreq | Frequency signal weighted average\n",
    "skewness | Frequency signal Skewness\n",
    "kurtosis | Frequency signal Kurtosis\n",
    "energyBand | Energy of a frequency interval\n",
    "angle | Angle between two vectors\n",
    "\n",
    "### 1.2 Objectifs\n",
    "Ce calepin s'intéresse aux seules variables construites à partir des connaissances *a priori* du comportement des capteurs en fonction des types d'activité humaine. IL propose une exploration et une modélisation, des 561 variables métier. Il s'agit de répondre à la question : est-il possible d'identifier l'activité du porteur du smartphone à partir d'un enregistrement? \n",
    "\n",
    "\n",
    "Un [autre calepin]()  s'intéresse aux données brutes afin d'économiser le travail préliminaire de définition des variables métier en utilisant, par exemple, des décompositions systématiques sur une base d'ondelettes ou, mieux, un algorithme d'apprentissage profond sur les seules données brutes. L'enjeu est d'obtenir une discrimination sur les données brutes donc moins énergivores qu'un calcul systématique des caractéristiques métier.\n",
    "\n",
    "Une *troisième étape* viserait à traiter les données à flux continu pour une application réelle de la reconnaissance d'activité afin, par exemple, de sécuriser des personnes dépendantes ou d'évaluer l'activité physique d'un assuré...\n",
    "\n",
    "Une optimisation poussée de la modélisation des méthodes d'apprentissage sur les données métiers comme le traitement direct des données bruts sont abordés dans d'autres calepins. L'objectif est d'abord une sensibilisation au traitement de données complexes temporelles."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Importation des principals librairies et\n",
    "# Affichage des graphiques dans le notebook\n",
    "\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import time\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1.3 Lecture des données métier\n",
    "\n",
    "Les données peuvent être préalablement téléchargées ou directement lues. Ce sont celles originales du dépôt de l'[UCI](https://archive.ics.uci.edu/ml/datasets/Human+Activity+Recognition+Using+Smartphones). "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "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>0</th>\n",
       "      <th>1</th>\n",
       "      <th>2</th>\n",
       "      <th>3</th>\n",
       "      <th>4</th>\n",
       "      <th>5</th>\n",
       "      <th>6</th>\n",
       "      <th>7</th>\n",
       "      <th>8</th>\n",
       "      <th>9</th>\n",
       "      <th>...</th>\n",
       "      <th>551</th>\n",
       "      <th>552</th>\n",
       "      <th>553</th>\n",
       "      <th>554</th>\n",
       "      <th>555</th>\n",
       "      <th>556</th>\n",
       "      <th>557</th>\n",
       "      <th>558</th>\n",
       "      <th>559</th>\n",
       "      <th>560</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>0.288585</td>\n",
       "      <td>-0.020294</td>\n",
       "      <td>-0.132905</td>\n",
       "      <td>-0.995279</td>\n",
       "      <td>-0.983111</td>\n",
       "      <td>-0.913526</td>\n",
       "      <td>-0.995112</td>\n",
       "      <td>-0.983185</td>\n",
       "      <td>-0.923527</td>\n",
       "      <td>-0.934724</td>\n",
       "      <td>...</td>\n",
       "      <td>-0.074323</td>\n",
       "      <td>-0.298676</td>\n",
       "      <td>-0.710304</td>\n",
       "      <td>-0.112754</td>\n",
       "      <td>0.030400</td>\n",
       "      <td>-0.464761</td>\n",
       "      <td>-0.018446</td>\n",
       "      <td>-0.841247</td>\n",
       "      <td>0.179941</td>\n",
       "      <td>-0.058627</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>0.278419</td>\n",
       "      <td>-0.016411</td>\n",
       "      <td>-0.123520</td>\n",
       "      <td>-0.998245</td>\n",
       "      <td>-0.975300</td>\n",
       "      <td>-0.960322</td>\n",
       "      <td>-0.998807</td>\n",
       "      <td>-0.974914</td>\n",
       "      <td>-0.957686</td>\n",
       "      <td>-0.943068</td>\n",
       "      <td>...</td>\n",
       "      <td>0.158075</td>\n",
       "      <td>-0.595051</td>\n",
       "      <td>-0.861499</td>\n",
       "      <td>0.053477</td>\n",
       "      <td>-0.007435</td>\n",
       "      <td>-0.732626</td>\n",
       "      <td>0.703511</td>\n",
       "      <td>-0.844788</td>\n",
       "      <td>0.180289</td>\n",
       "      <td>-0.054317</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>0.279653</td>\n",
       "      <td>-0.019467</td>\n",
       "      <td>-0.113462</td>\n",
       "      <td>-0.995380</td>\n",
       "      <td>-0.967187</td>\n",
       "      <td>-0.978944</td>\n",
       "      <td>-0.996520</td>\n",
       "      <td>-0.963668</td>\n",
       "      <td>-0.977469</td>\n",
       "      <td>-0.938692</td>\n",
       "      <td>...</td>\n",
       "      <td>0.414503</td>\n",
       "      <td>-0.390748</td>\n",
       "      <td>-0.760104</td>\n",
       "      <td>-0.118559</td>\n",
       "      <td>0.177899</td>\n",
       "      <td>0.100699</td>\n",
       "      <td>0.808529</td>\n",
       "      <td>-0.848933</td>\n",
       "      <td>0.180637</td>\n",
       "      <td>-0.049118</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>0.279174</td>\n",
       "      <td>-0.026201</td>\n",
       "      <td>-0.123283</td>\n",
       "      <td>-0.996091</td>\n",
       "      <td>-0.983403</td>\n",
       "      <td>-0.990675</td>\n",
       "      <td>-0.997099</td>\n",
       "      <td>-0.982750</td>\n",
       "      <td>-0.989302</td>\n",
       "      <td>-0.938692</td>\n",
       "      <td>...</td>\n",
       "      <td>0.404573</td>\n",
       "      <td>-0.117290</td>\n",
       "      <td>-0.482845</td>\n",
       "      <td>-0.036788</td>\n",
       "      <td>-0.012892</td>\n",
       "      <td>0.640011</td>\n",
       "      <td>-0.485366</td>\n",
       "      <td>-0.848649</td>\n",
       "      <td>0.181935</td>\n",
       "      <td>-0.047663</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>0.276629</td>\n",
       "      <td>-0.016570</td>\n",
       "      <td>-0.115362</td>\n",
       "      <td>-0.998139</td>\n",
       "      <td>-0.980817</td>\n",
       "      <td>-0.990482</td>\n",
       "      <td>-0.998321</td>\n",
       "      <td>-0.979672</td>\n",
       "      <td>-0.990441</td>\n",
       "      <td>-0.942469</td>\n",
       "      <td>...</td>\n",
       "      <td>0.087753</td>\n",
       "      <td>-0.351471</td>\n",
       "      <td>-0.699205</td>\n",
       "      <td>0.123320</td>\n",
       "      <td>0.122542</td>\n",
       "      <td>0.693578</td>\n",
       "      <td>-0.615971</td>\n",
       "      <td>-0.847865</td>\n",
       "      <td>0.185151</td>\n",
       "      <td>-0.043892</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "<p>5 rows × 561 columns</p>\n",
       "</div>"
      ],
      "text/plain": [
       "        0         1         2         3         4         5         6    \\\n",
       "0  0.288585 -0.020294 -0.132905 -0.995279 -0.983111 -0.913526 -0.995112   \n",
       "1  0.278419 -0.016411 -0.123520 -0.998245 -0.975300 -0.960322 -0.998807   \n",
       "2  0.279653 -0.019467 -0.113462 -0.995380 -0.967187 -0.978944 -0.996520   \n",
       "3  0.279174 -0.026201 -0.123283 -0.996091 -0.983403 -0.990675 -0.997099   \n",
       "4  0.276629 -0.016570 -0.115362 -0.998139 -0.980817 -0.990482 -0.998321   \n",
       "\n",
       "        7         8         9    ...       551       552       553       554  \\\n",
       "0 -0.983185 -0.923527 -0.934724  ... -0.074323 -0.298676 -0.710304 -0.112754   \n",
       "1 -0.974914 -0.957686 -0.943068  ...  0.158075 -0.595051 -0.861499  0.053477   \n",
       "2 -0.963668 -0.977469 -0.938692  ...  0.414503 -0.390748 -0.760104 -0.118559   \n",
       "3 -0.982750 -0.989302 -0.938692  ...  0.404573 -0.117290 -0.482845 -0.036788   \n",
       "4 -0.979672 -0.990441 -0.942469  ...  0.087753 -0.351471 -0.699205  0.123320   \n",
       "\n",
       "        555       556       557       558       559       560  \n",
       "0  0.030400 -0.464761 -0.018446 -0.841247  0.179941 -0.058627  \n",
       "1 -0.007435 -0.732626  0.703511 -0.844788  0.180289 -0.054317  \n",
       "2  0.177899  0.100699  0.808529 -0.848933  0.180637 -0.049118  \n",
       "3 -0.012892  0.640011 -0.485366 -0.848649  0.181935 -0.047663  \n",
       "4  0.122542  0.693578 -0.615971 -0.847865  0.185151 -0.043892  \n",
       "\n",
       "[5 rows x 561 columns]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Lecture des données d'apprentissage\n",
    "# Attention, il peut y avoir plusieurs espaces comme séparateur dans le fichier\n",
    "Xtrain = pd.read_table(\"X_train.txt\", sep=\"\\s+\", header=None)\n",
    "Xtrain.head()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Variable cible\n",
    "ytrain = pd.read_table(\"y_train.txt\", sep=\"\\s+\", header=None, names=list(\"y\"))\n",
    "# Le type dataFrame est inutile et même gênant pour les la suite\n",
    "ytrain = ytrain[\"y\"]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(2947, 561)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Lecture des données de test\n",
    "Xtest = pd.read_table(\"X_test.txt\", sep=\"\\s+\", header=None)\n",
    "Xtest.shape\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "ytest = pd.read_table(\"y_test.txt\", sep=\"\\s+\", header=None, names=list(\"y\"))\n",
    "ytest = ytest[\"y\"]\n",
    "# Significaiton des codes de y\n",
    "label_dic = {\n",
    "    1: \"Marcher\",\n",
    "    2: \"Monter escalier\",\n",
    "    3: \"Descendre escalier\",\n",
    "    4: \"Assis\",\n",
    "    5: \"Debout\",\n",
    "    6: \"Couche\",\n",
    "}\n",
    "labels = label_dic.values()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 Exploration par [Analyse en composantes principales](http://wikistat.fr/pdf/st-m-explo-acp.pdf)\n",
    "### 2.1 Principe\n",
    "Il est important de se faire une idée précise de la structure des données.  Une analyse en composantes principales est adaptée à cet objectif. \n",
    "\n",
    "   - Elle recherche les axes de plus grande dispersion du nuages des individus dans $R^p$ avec $p=561$. Ces axes sont définis par les vecteurs propres de la matrice des covariances ou des corrélations si les variables sont réduites (divisées par l'écart-type).\n",
    "   - Les représentations graphiques des individus sont obtenues par projection sur les sous-espaces engendrés par les premiers vecteurs propres. Elles préservent au mieux les distances entre ceux-ci.\n",
    "   - Les coordonnées sont stockées dans la matrice des *composantes principales* qui sont aussi les combinaisons linéaires de plus grande variance des variables. Ce sont des variables décorrélées, orthogonales deux à deux.\n",
    "   - Les representations graphiques des variables initiales conservent au mieux les angles entre les vecteurs variables dans l'espace $R^n$ de façon à interpréter leurs corrélations qui, géométriquement, sont les cosinus de ces angles. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.decomposition import PCA\n",
    "from sklearn.preprocessing import scale\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La fonction définie ci-après affiche un nuage de points dans un plan factoriel."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_pca(X_R, fig, ax, nbc, nbc2):\n",
    "    for i in range(6):\n",
    "        xs = X_R[ytrain == i + 1, nbc - 1]\n",
    "        ys = X_R[ytrain == i + 1, nbc2 - 1]\n",
    "        label = label_dic[i + 1]\n",
    "        color = cmaps(i)\n",
    "        ax.scatter(xs, ys, color=color, alpha=0.8, s=1, label=label)\n",
    "        ax.set_xlabel(\n",
    "            \"PC%d : %.2f %%\" % (nbc, pca.explained_variance_ratio_[nbc - 1] * 100),\n",
    "            fontsize=10,\n",
    "        )\n",
    "        ax.set_ylabel(\n",
    "            \"PC%d : %.2f %%\" % (nbc2, pca.explained_variance_ratio_[nbc2 - 1] * 100),\n",
    "            fontsize=10,\n",
    "        )\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Calcul de la matrice des composantes principales. C'est aussi un changement (transformation) de base; de la base canonique dans la base des vecteurs propres. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "pca = PCA()\n",
    "X_r = pca.fit_transform(Xtrain)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2.2 Valeurs propres ou variances des composantes principales\n",
    "Représentation de la décroissance des valeurs propres, les variances des variables ou composantes principales."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 8932 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.plot(pca.explained_variance_ratio_[0:10])\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un graphique plus explicite décrit les distribution de ces composantes par des diagrames boîtes; seules les premières sont affichées. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 9620 characters]",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.boxplot(X_r[:, 0:10])\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Commenter la décroissance des variances, le choix éventuel d'une dimension ou nombre de composantes à retenir sur les 561.\n",
    "### 2.3 Représentation des individus ou \"activités\"\n",
    "Projection dans les principaux plans factoriels."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 435524 characters]",
      "text/plain": [
       "<Figure size 1440x1440 with 6 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "cmaps = plt.get_cmap(\"Accent\")\n",
    "fig = plt.figure(figsize=(20, 20))\n",
    "count = 0\n",
    "for nbc, nbc2, count in [\n",
    "    (1, 2, 1),\n",
    "    (1, 3, 2),\n",
    "    (1, 4, 3),\n",
    "    (2, 3, 5),\n",
    "    (2, 4, 6),\n",
    "    (3, 4, 9),\n",
    "]:\n",
    "    ax = fig.add_subplot(3, 3, count)\n",
    "    plot_pca(X_r, fig, ax, nbc, nbc2)\n",
    "plt.legend(loc=\"upper right\", bbox_to_anchor=(1.8, 0.5), markerscale=10)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Q** Commenter la séparation des deux types de situation par le premier axe.\n",
    "\n",
    "**Q** Que dire sur la forme des nuages?\n",
    "\n",
    "**Q** Que dire sur la plus ou moins bonne séparation des classes?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "### 2.4 Représentation des variables\n",
    "Lecture des libellés des variables et constitution d'une liste. Souci de la grande dimension (561), les représentations ne sont guère exploitables. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"features.txt\", \"r\") as content_file:\n",
    "    featuresNames = content_file.read()\n",
    "columnsNames = list(map(lambda x: x.split(\" \")[1], featuresNames.split(\"\\n\")[:-1]))\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Graphe illisible en mettant les libellés en clair. Seule une * est représentée."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 39912 characters]",
      "text/plain": [
       "<Figure size 576x576 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# coordonnées des variables\n",
    "coord1 = pca.components_[0] * np.sqrt(pca.explained_variance_[0])\n",
    "coord2 = pca.components_[1] * np.sqrt(pca.explained_variance_[1])\n",
    "fig = plt.figure(figsize=(8, 8))\n",
    "ax = fig.add_subplot(1, 1, 1)\n",
    "for i, j in zip(\n",
    "    coord1,\n",
    "    coord2,\n",
    "):\n",
    "    plt.text(i, j, \"*\")\n",
    "    plt.arrow(0, 0, i, j, color=\"r\")\n",
    "plt.axis((-1.2, 1.2, -1.2, 1.2))\n",
    "# cercle\n",
    "c = plt.Circle((0, 0), radius=1, color=\"b\", fill=False)\n",
    "ax.add_patch(c)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Identification des variables participant le plus au premier axe. Ce n'est pas plus clair ! Seule la réprésentation des individus apporte finalement des éléments de compréhension."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array(['tBodyAccJerk-entropy()-X', 'tBodyAccJerk-entropy()-Y',\n",
       "       'tBodyAccMag-entropy()', 'tGravityAccMag-entropy()',\n",
       "       'tBodyAccJerkMag-entropy()', 'tBodyGyroJerkMag-entropy()',\n",
       "       'fBodyAcc-entropy()-X', 'fBodyAcc-entropy()-Y',\n",
       "       'fBodyAcc-entropy()-Z', 'fBodyAccJerk-entropy()-X',\n",
       "       'fBodyAccJerk-entropy()-Y', 'fBodyAccJerk-entropy()-Z',\n",
       "       'fBodyAccMag-entropy()', 'fBodyBodyAccJerkMag-entropy()',\n",
       "       'fBodyBodyGyroJerkMag-entropy()'], dtype='<U36')"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.array(columnsNames)[abs(coord1) > 0.6]\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 Exploration par [Analyse Factorielle Discriminante (AFD)](http://wikistat.fr/pdf/st-m-explo-afd.pdf)\n",
    "### 3.1 Principe\n",
    "L'ACP ne prend pas en compte la présence de la variable qualitative à modéliser, contrairement à l'analyse factorielle discriminante (AFD). L'AFD est adaptée à ce contexte \"supervisé\" puisque l'activité est connue sur un échantillon d'apprentissage. L'AFD est une ACP des barycentres des classes munissant l'espace des indivudus d'une métrique spécifique dite de *Mahalanobis*. Métrique définie par l'inverse de la matrice de covariance intraclasse. L'objectif est alors de visualiser les capacités des variables à discriminer les classes.\n",
    "\n",
    "La librairie `scikit-learn` ne propose pas de fonction spécifique d'analyse factorielle discriminante mais les coordonnées des individus dans la base des vecteurs discriminants sont obtenues comme résultats de l'analyse discriminante linéaire décisionnnelle. Cette dernière sera utilisé avec une finalité prédictive dans un deuxième temps (voir section 4 de ce calepin). \n",
    "\n",
    "Les résultats de la fonction `LinearDiscriminantAnalysis` de `scikit-learn` sont identiques à ceux de la fonction `lda` de R. Elle est donc utilisée strictement de la même façon."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "from sklearn.discriminant_analysis import LinearDiscriminantAnalysis\n",
    "\n",
    "method = LinearDiscriminantAnalysis()\n",
    "lda = method.fit(Xtrain, ytrain)\n",
    "X_r2 = lda.transform(Xtrain)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3.2 Représentation des individus"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 296648 characters]",
      "text/plain": [
       "<Figure size 1440x1440 with 6 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(20, 20))\n",
    "count = 0\n",
    "for nbc, nbc2, count in [\n",
    "    (1, 2, 1),\n",
    "    (1, 3, 2),\n",
    "    (1, 4, 3),\n",
    "    (2, 3, 5),\n",
    "    (2, 4, 6),\n",
    "    (3, 4, 9),\n",
    "]:\n",
    "    ax = fig.add_subplot(3, 3, count)\n",
    "    plot_pca(X_r2, fig, ax, nbc, nbc2)\n",
    "plt.legend(loc=\"upper right\", bbox_to_anchor=(1.8, 0.5), markerscale=10)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Q** Que dire de la séparation des classes. Sont-elles toutes séparables deux à deux ?\n",
    "\n",
    "**Q** Que dire de la forme des nuages notamment dans le premier plan ? Critiquer l'hypothèse utilisée dans l'AFD.\n",
    "\n",
    "Comme pour l'ACP, la représentation des variables n'apporterait rien."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 Apprentissage et prévision de l'activité par Analyse Factorielle Discriminante (AFD)\n",
    "\n",
    "D'autres méthodes sont successivement testées dans les calepins complétant l'étude: SVM, $k$ plus proches voisins, forêts aléatoires, réseaux de neurones... Seule l'analyse discriminante décisionnelle et la régression logistique sont utilisées dans ce calepin pour illustrer la phase d'apprentissage / modélisation pour la prévision du comportement."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "On rappelle que l'analyse factorielle discriminante a deux facettes : exploratoire et prédictive. L'analyse exploratoire réalise une ACP des centres des classes avec la métrique de Mahalanobis (qui a pour effet de rendre les données 'sphériques'), cf section 3. La prédiction est obtenue en utilisant le centre le plus proche au sens de cette métrique, en tenant compte des fréquences de chaque classe. De façon équivalente, c'est la prévision bayésienne obtenue lorsque le prior est un mélange gaussien homoscédastique."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.1. Estimation du modèle"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "method = LinearDiscriminantAnalysis()\n",
    "ts = time.time()\n",
    "method.fit(Xtrain, ytrain)\n",
    "scoreLDA = method.score(Xtest, ytest)\n",
    "ypredLDA = method.predict(Xtest)\n",
    "te = time.time()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4.2. Prévision de l'activité pour l'échantillon test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Score : 0.962335, time running : 0 secondes\n"
     ]
    },
    {
     "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>Marcher</th>\n",
       "      <th>Monter escalier</th>\n",
       "      <th>Descendre escalier</th>\n",
       "      <th>Assis</th>\n",
       "      <th>Debout</th>\n",
       "      <th>Couche</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Marcher</th>\n",
       "      <td>490</td>\n",
       "      <td>6</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Monter escalier</th>\n",
       "      <td>11</td>\n",
       "      <td>460</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Descendre escalier</th>\n",
       "      <td>1</td>\n",
       "      <td>14</td>\n",
       "      <td>405</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Assis</th>\n",
       "      <td>0</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "      <td>434</td>\n",
       "      <td>56</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Debout</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>22</td>\n",
       "      <td>510</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Couche</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>537</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    Marcher  Monter escalier  Descendre escalier  Assis  \\\n",
       "Marcher                 490                6                   0      0   \n",
       "Monter escalier          11              460                   0      0   \n",
       "Descendre escalier        1               14                 405      0   \n",
       "Assis                     0                1                   0    434   \n",
       "Debout                    0                0                   0     22   \n",
       "Couche                    0                0                   0      0   \n",
       "\n",
       "                    Debout  Couche  \n",
       "Marcher                  0       0  \n",
       "Monter escalier          0       0  \n",
       "Descendre escalier       0       0  \n",
       "Assis                   56       0  \n",
       "Debout                 510       0  \n",
       "Couche                   0     537  "
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "print(\"Score : %f, time running : %d secondes\" % (scoreLDA, te - ts))\n",
    "pd.DataFrame(confusion_matrix(ytest, ypredLDA), index=labels, columns=labels)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Q** Quelles sont les classes qui restent difficiles à discriminer ?\n",
    "\n",
    "**Q** Commenter la qualité des résultats obtenus. Sont-ils cohérents avec l'approche exploratoire ?\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5 Apprentissage et prévision de l'activité par [Régression logistique](http://wikistat.fr/pdf/st-m-app-rlogit.pdf)\n",
    "\n",
    "\n",
    "Une méthode ancienne mais finalement efficace sur ces données. La régression logistique est adaptée à la prévision d'une variable binaire. Dans le cas multiclasse, la fonction logistique de la librairie `Scikit-learn` estime *par défaut* **un modèle par classe**: une classe contre les autres. \n",
    "\n",
    "La probabilité d'appartenance d'un individu à une classe est modélisée à l'aide d'une combinaison linéaire des variables explicatives. Pour transformer une combinaison linéaire à valeur dans $R$ en une probabilité à valeurs dans l'intervalle $[0, 1]$, une fonction de forme sigmoïdale, inverse de la fonction *logit*, est appliquée.  Ceci donne: $P(y_i=1)=\\frac{e^{Xb}}{1+e^{Xb}}$ ou encore, $\\log\\frac{P(y_i=1)}{1-P(y_i=1)}=Xb$\n",
    "\n",
    "\n",
    "### 5.1  Estimation du modèle sans optimisation\n",
    "Le modèle est estimé sans chercher à raffiner les valeurs de certains paramètres (pénalisation). Ce sera fait dans un deuxième temps."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/insa/anaconda/lib/python3.8/site-packages/sklearn/linear_model/_logistic.py:763: ConvergenceWarning: lbfgs failed to converge (status=1):\n",
      "STOP: TOTAL NO. of ITERATIONS REACHED LIMIT.\n",
      "\n",
      "Increase the number of iterations (max_iter) or scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "Please also refer to the documentation for alternative solver options:\n",
      "    https://scikit-learn.org/stable/modules/linear_model.html#logistic-regression\n",
      "  n_iter_i = _check_optimize_result(\n"
     ]
    }
   ],
   "source": [
    "from sklearn.linear_model import LogisticRegression\n",
    "\n",
    "ts = time.time()\n",
    "method = LogisticRegression()\n",
    "method.fit(Xtrain, ytrain)\n",
    "scoreLR = method.score(Xtest, ytest)\n",
    "ypredLR = method.predict(Xtest)\n",
    "te = time.time()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5.2. Prévision de l'activité pour l'échantillon test\n",
    "Une fois le modèle estimé, l'erreur de prévision est évaluée, sans biais optimiste, sur un autre échantillon, dit échantillon test, qui n'a pas participé à l'apprentissage du modèle."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Score : 0.958263, time running : 1 secondes\n"
     ]
    },
    {
     "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>Marcher</th>\n",
       "      <th>Monter escalier</th>\n",
       "      <th>Descendre escalier</th>\n",
       "      <th>Assis</th>\n",
       "      <th>Debout</th>\n",
       "      <th>Couche</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>Marcher</th>\n",
       "      <td>492</td>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Monter escalier</th>\n",
       "      <td>24</td>\n",
       "      <td>445</td>\n",
       "      <td>2</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Descendre escalier</th>\n",
       "      <td>4</td>\n",
       "      <td>13</td>\n",
       "      <td>403</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Assis</th>\n",
       "      <td>0</td>\n",
       "      <td>3</td>\n",
       "      <td>0</td>\n",
       "      <td>431</td>\n",
       "      <td>57</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Debout</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>16</td>\n",
       "      <td>516</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Couche</th>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>0</td>\n",
       "      <td>537</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "                    Marcher  Monter escalier  Descendre escalier  Assis  \\\n",
       "Marcher                 492                1                   3      0   \n",
       "Monter escalier          24              445                   2      0   \n",
       "Descendre escalier        4               13                 403      0   \n",
       "Assis                     0                3                   0    431   \n",
       "Debout                    0                0                   0     16   \n",
       "Couche                    0                0                   0      0   \n",
       "\n",
       "                    Debout  Couche  \n",
       "Marcher                  0       0  \n",
       "Monter escalier          0       0  \n",
       "Descendre escalier       0       0  \n",
       "Assis                   57       0  \n",
       "Debout                 516       0  \n",
       "Couche                   0     537  "
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from sklearn.metrics import confusion_matrix\n",
    "\n",
    "print(\"Score : %f, time running : %d secondes\" % (scoreLR, te - ts))\n",
    "pd.DataFrame(confusion_matrix(ytest, ypredLR), index=labels, columns=labels)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Q** Mêmes questions que pour le modèle précédent (AFD) : Quelles sont les classes qui restent difficiles à discriminer ? Commenter la qualité des résultats obtenus. Sont-ils cohérents avec l'approche exploratoire ?\n",
    "\n",
    "**Q** Comparer avec l'AFD. Qu'est-ce qui peut expliquer que, souvent, les résultats de l'AFD et de la régression logistique sont semblables ? Pourquoi les deux méthodes sont-elles complémentaires ?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un calepin suivant exploite d'autres méthodes d'apprentissage ainsi qu'une stratégie de hiérarchisation des modèles afin d'améliorer encore la prévision sur les données métiers. \n",
    "\n",
    "Un autre traite directement les signaux bruts en apprennant un réseau de neurones profond associant des couches convolutionnelles afin d'obtenir des résultats comparables sans prétraitement des données. Réseau intégrable à un équipement embarqué de faible consommation."
   ]
  }
 ],
 "metadata": {
  "hide_input": false,
  "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.8.10"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {
    "height": "244px",
    "width": "252px"
   },
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": "block",
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
