Skip to content

Instantly share code, notes, and snippets.

@khinsen
Created December 3, 2018 15:58
Show Gist options
  • Save khinsen/1ad7cd43a9e49a40da994b5f48e5fbb1 to your computer and use it in GitHub Desktop.
Save khinsen/1ad7cd43a9e49a40da994b5f48e5fbb1 to your computer and use it in GitHub Desktop.
Cours GSON du 4 décembre 2018 - exercices d'échauffement
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# NumPy 2 : exercices d'échauffement"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%matplotlib inline\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Combien gagne-t-on en temps CPU avec NumPy ?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python propose un module pour mesurer la durée d'exécution d'une commande, qui prend certaines précautions pour assurer des résultats fiables. Notamment, la commande est exécutée plusieurs fois afin d'obtenir un temps moyen qui est beaucoup moins sensible aux aléas de l'environnement qu'une mesure unique.\n",
"\n",
"Voici comment l'utiliser :"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.0032744540003477596\n"
]
}
],
"source": [
"import timeit\n",
"\n",
"print(timeit.timeit(\"len(range(10))\", number=10000))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le principe est simple: on fournit la commande sous forme d'une chaîne de caractères, et le nombre de répétition, et on obtient le temps d'exécution moyen en secondes.\n",
"\n",
"A la place d'une chaîne de caractères, on peut donner une fonction *sans arguments* :"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.007452745998307364\n"
]
}
],
"source": [
"def test():\n",
" return len(range(10))\n",
"\n",
"print(timeit.timeit(test, number=10000))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Le temps est plus long dans ce cas, parce que l'appel à la fonction a aussi un coût, qui est en fait de la même ordre de grandeur que le coût de la simple fonction `len`. Mais ce petit surcoût devient négligeable quand on mesure des calculs plus substantiels, ce que nous allons faire par la suite."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Exercice : temps d'exécution pour additioner deux listes ou deux tableaux\n",
"\n",
"Nous reprenons la génération de listes de nombres aléatoires de la semaine dernière :"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import random\n",
"\n",
"def liste_de_nombres_aleatoires(n):\n",
" return [random.uniform(0, 1) for _ in range(n)]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A vous de faire :\n",
"\n",
" 1. Ecrivez une fonction qui additionne deux listes élément par élément.\n",
" 2. Vérifiez que votre fonction donne le même résultat pour deux listes aléatoires que l'addition des deux listes converties en tableaux.\n",
" 3. Mesurez le temps d'exécution de votre fonction pour des listes aléatoires de tailles entre 10 et 1000.\n",
" 4. Mesures également le temps d'exécution de la somme après conversion en tableaux.\n",
" 5. Faites un plot des deux temps d'exécutions en fonction du nombre d'éléments.\n",
" 6. Faites un plot des deux temps d'exécutions *par élément* en fonction du nombre d'éléments."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pour vous aider avec les deux premières étapes, voici le code qui fait la vérification. Il vous reste à compléter la définition de la fonction `somme_de_listes`. Si tout va bien, le test produit `True` pour chaque itération de la boucle.\n",
"\n",
"Cet exemple illustre qu'un tableau peut aussi contenir de booléens, donc des valeurs `True` ou `False`. La comparaison `t1 == t2` compare `t1` et `t2` élément par élément et retourne un tel tableau de booléens. Avec `.all()` on teste si tous les éléments ont la valeur `True`."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"True\n",
"True\n",
"True\n",
"True\n",
"True\n"
]
}
],
"source": [
"def somme_de_listes(l1, l2):\n",
" ...\n",
"\n",
"for i in range(5):\n",
" l1 = liste_de_nombres_aleatoires(10)\n",
" l2 = liste_de_nombres_aleatoires(10)\n",
" somme_listes = somme_de_listes(l1, l2)\n",
" t1 = np.array(l1)\n",
" t2 = np.array(l2)\n",
" somme_tableaux = t1 + t2\n",
" print((np.array(somme_listes) == somme_tableaux).all())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Pour les mesures des étapes 4 à 6, il reste un astuce à connaître. Il faut contourner la contrainte de `timeit.timeit`, qui n'accepte qu'une fonction sans argument. Impossible donc de faire quelque chose comme\n",
"`timeit.timeit(somme_de_listes(l1, l2))`. L'astuce est de définir une fonction supplémentaire rien que pour mesurer le temps d'exécution. Voici un exemple :"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0.00013218300045991782\n"
]
}
],
"source": [
"l1 = liste_de_nombres_aleatoires(10)\n",
"l2 = liste_de_nombres_aleatoires(10)\n",
"def temps():\n",
" return somme_de_listes(l1, l2)\n",
"print(timeit.timeit(temps, number=100))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Vous pouvez faire cela même dans une boucle :"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"50 0.003870102998916991\n",
"100 0.0073099260007438716\n",
"500 0.0457768300002499\n"
]
}
],
"source": [
"for n in [50, 100, 500]:\n",
" l1 = liste_de_nombres_aleatoires(n)\n",
" l2 = liste_de_nombres_aleatoires(n)\n",
" def temps():\n",
" return somme_de_listes(l1, l2)\n",
" print(n, timeit.timeit(temps, number=1000))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A vous de jouer ! N'hésitez pas à consulter le notebook de la semaine dernière comme source d'inspiration."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"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.6.1"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment