Notebook originel: exam22.ipynb

Examen Science des données🔗

Date: 08 décembre 2022

Durée: 2 h

[1]:
import numpy as np
import matplotlib.pyplot as plt
[2]:
%matplotlib notebook

Consignes🔗

Créez un répertoire Exam22_NOM_Prenom dans lequel vous travaillerez, et où seront stockés

  1. le notebook jupyter d’analyse (nom_prenom.ipynb, copié à partir de ce notebook énoncé sans l’extension .orig), que vous complèterez progressivement en ajoutant une ou plusieurs cellules en dessous de chaque question;

  2. le package python en développement, selon les instructions ci-dessous.

Vous devez alors mettre ce répertoire sous contrôle git sur un projet dédié sur le serveur https://gitlab.in2p3.fr, et en transmettre l’adresse à y.copin@ipnl.in2p3.fr.

Si, par manque de temps ou de connaissance, vous ne pouvez pas créer un dépôt git, envoyez par mail le notebook et/ou le package (sous forme d’un fichier tar ou zip) à y.copin@ipnl.in2p3.fr (cette solution sera pénalisée dans la notation).

Tests🔗

Ce notebook inclut des tests unitaires vous permettant de tester a minima le code du notebook. Utilisez ces tests pour guider votre développement et vérifier vos résultats. Ne modifiez pas (a fortiori, n’effacez pas) ces tests.

Régression linéaire🔗

Soit un jeu de données de \(N\) points \(\{(x_i, y_i)\}\). La régression linéaire

\[y \equiv a + b x\]

est définie par

\[\begin{split}\begin{aligned} \hat{b} &= \frac{\mathrm{Cov}(x, y)}{\mathrm{Var}(x)} \\ \hat{a} &= \langle y\rangle - \hat{b}\langle x\rangle \end{aligned}\end{split}\]

\[\begin{split}\begin{aligned} \mathrm{Var}(x) &= \langle(x - \langle x\rangle)^2\rangle \\ \mathrm{Cov}(x, y) &= \langle(x - \langle x\rangle)(y - \langle y\rangle)\rangle \end{aligned}\end{split}\]

Le coefficient de corrélation linéaire est défini par:

\[r = \frac{\mathrm{Cov}(x, y)}{\sqrt{\mathrm{Var}(x)\mathrm{Var}(y)}}\]
  1. Sans détailler les calculs, quelles équations ont conduit à ces estimateurs?

  2. Dans le notebook, écrire une fonction linregress_1D(x, y) qui, en utilisant uniquement la fonction np.mean, retourne \(\hat{a}\), \(\hat{b}\) et \(r\) pour des vecteurs (1D) d’entrée \(x\) et \(y\).

  1. Tester explicitement sur le cas

>>> x = np.arange(10)
>>> y = 3. + 2. * x + np.round(np.sin(x * 10), 3)

et vérifier le résultat avec scipy.stats.linregress.

  1. Faire une figure illustrant les points de données \(\{(x, y)\}\) (scatter) et la régression linéaire (plot). Ajouter un label sur chacun des axes, un titre à la figure et une légende.

Detrending🔗

Le detrending permet de retirer une composant linéaire d’un jeu de données \(\{y_i\}\):

\[\tilde{y}_i = y_i - (\hat{a} + \hat{b} i)\]
  1. Écrire une fonction detrend_1D(y) retournant \(\tilde{y}\) (càd \(y\) duquel a été soustrait sa composante linéaire) et \(r\).

  1. Tester et faire une figure sur le vecteur y précédent.

Généralisation multi-dimensionnelle🔗

  1. Écrire la function de régression linéaire linregress(x, y, axis) pour retourner le résultat de la régression sur les tableaux x et y de rang arbitraire, le long de la dimension axis. La fonction doit retourner 3 tableaux a, b et r de même rang que les tableaux d’entrée.

    Par example:

    >>> x = np.arange(3*4).reshape((3, 4))
    >>> y = 3 + 2 * x
    >>> linregress(x, y, axis=0)
    (array([[3., 3., 3., 3.]]),
     array([[2., 2., 2., 2.]]),
     array([[1., 1., 1., 1.]]))
    >>> linregress(x, y, axis=1)
    (array([[3.],
            [3.],
            [3.]]),
     array([[2.],
            [2.],
            [2.]]),
     array([[1.],
            [1.],
            [1.]]))
    >>> linregress(x, y, axis=2)
    Traceback (most recent call last):
        ...
    AxisError: axis 2 is out of bounds for array of dimension 2
    
  1. De même, écrire la fonction detrend(y, axis). Vous pouvez utiliser les lignes suivantes pour générer un indice courant le long de la dimension axis:

    shape = np.ones_like(np.shape(y))
    shape[axis] = -1
    i = np.arange(np.shape(y)[axis]).reshape(shape)
    
  1. Ajouter des options suivantes à la fonction detrend (voir scipy.signal.detrend pour un modèle):

    • type='linear' pour soustraire la composante linéaire \(a + b\,i\) (type='linear'), la composante affine \(b\,i\) (type='affine'), ou uniquement la composante constante \(a\) (type='constant');

    • overwrite=False pour réaliser la soustraction sur un nouveau tableau (overwrite=False) ou sur place (overwrite=True)

  1. Si vous n’avez pas réussi à stocker votre package sous git, envoyer le notebook à y.copin@ipnl.in2p3.fr.

Packaging🔗

  1. Extraire les 4 fonctions précédentes (linregress_1D, detrend_1D, linregress et detrend) et les inclure dans un fichier detrend.py. Il constituera le module de votre package.

  2. Documenter (succinctement) le module et les fonctions par des docstrings.

  3. Créer un package Exam22_Nom_Prenom constitué du seul module detrend.py, avec l’arborescence suivante:

    Exam22_Nom_Prenom/
    ├── detrend_nom_prenom
    │   ├── detrend.py
    │   └── __init__.py
    ├── LICENSE
    ├── README
    ├── setup.cfg
    └── setup.py
    

    avec les fichiers suivants (à adapter à votre contexte):

  4. Ajouter un répertoire doc/ pour configurer et générer la documentation Sphinx du package (voir documentation pyyc). Y inclure votre notebook (sous doc/notebooks/) dans une section dédiée.

  5. Si vous n’avez pas réussi à stocker votre package sous git, générer un tarball des sources de votre package (duquel vous aurez effacé les répertoires _build/, dist/ s’ils existent),

    $ tar cvzf Exam22_NOM_Prenom.tgz Exam22_NOM_Prenom/
    

    et envoyer le tarball résultant à nouveau à y.copin@ipnl.in2p3.fr.

Tests🔗

Tests unitaires🔗

[3]:
import unittest
import numpy as np

class TestNotebook(unittest.TestCase):

    def test_linregress_1D(self):
        x = np.arange(10)
        self.assertEqual(linregress_1D(x, 3 + 2 * x), (3.0, 2.0, 1.0))
        self.assertAlmostEqual(linregress_1D(x, 3 + 2 * x + np.round(np.sin(x * 10), 3)),
                               (2.8803090909090923, 2.0317757575757573, 0.9925669351010524))

    def test_detrend_1D(self):
        x = np.arange(5)
        np.testing.assert_allclose(detrend_1D(1 + 2 * x), [0., 0., 0., 0., 0.])
        np.testing.assert_allclose(
            detrend_1D(x**0.5),
            [-0.28284271,  0.24395221,  0.18496069,  0.02959285, -0.17566304])

    def test_linregress(self):
        x = np.arange(3*4).reshape((3, 4))
        y = 3 + 2 * x
        np.testing.assert_allclose(
            linregress(x, y, axis=0),
            ([[3., 3., 3., 3.]],
             [[2., 2., 2., 2.]],
             [[1., 1., 1., 1.]]))
        np.testing.assert_allclose(
            linregress(x, y, axis=0),
            ([[3., 3., 3., 3.]],
             [[2., 2., 2., 2.]],
             [[1., 1., 1., 1.]]))
        np.testing.assert_allclose(
            linregress(x, y, axis=1),
            ([[3.], [3.], [3.]],
             [[2.], [2.], [2.]],
             [[1.], [1.], [1.]]))
        with self.assertRaises(np.AxisError):
            linregress(x, y, axis=2)

    def test_detrend(self):
        x = np.arange(3*4).reshape((3, 4))
        y = 3 + 2 * x
        np.testing.assert_allclose(detrend(y, axis=0), 0.)
        np.testing.assert_allclose(detrend(y, axis=1), 0.)
        with self.assertRaises(IndexError):
            detrend(y, axis=2)

unittest.main(argv=[''], verbosity=2, exit=False)
test_detrend (__main__.TestNotebook) ... ERROR
test_detrend_1D (__main__.TestNotebook) ... ERROR
test_linregress (__main__.TestNotebook) ... ERROR
test_linregress_1D (__main__.TestNotebook) ... ERROR

======================================================================
ERROR: test_detrend (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_364400/4254163955.py", line 43, in test_detrend
    np.testing.assert_allclose(detrend(y, axis=0), 0.)
NameError: name 'detrend' is not defined

======================================================================
ERROR: test_detrend_1D (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_364400/4254163955.py", line 14, in test_detrend_1D
    np.testing.assert_allclose(detrend_1D(1 + 2 * x), [0., 0., 0., 0., 0.])
NameError: name 'detrend_1D' is not defined

======================================================================
ERROR: test_linregress (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_364400/4254163955.py", line 23, in test_linregress
    linregress(x, y, axis=0),
NameError: name 'linregress' is not defined

======================================================================
ERROR: test_linregress_1D (__main__.TestNotebook)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/ipykernel_364400/4254163955.py", line 8, in test_linregress_1D
    self.assertEqual(linregress_1D(x, 3 + 2 * x), (3.0, 2.0, 1.0))
NameError: name 'linregress_1D' is not defined

----------------------------------------------------------------------
Ran 4 tests in 0.004s

FAILED (errors=4)
[3]:
<unittest.main.TestProgram at 0x7efbd41636d0>
[ ]:

Cette page a été générée à partir de exam22.ipynb.