Skip to content

Commit

Permalink
Box pour les notebooks ✨ (#256)
Browse files Browse the repository at this point in the history
* modif

* Automated changes

* Automated changes

* tweak md for notebooks

* Automated changes

* up

* Automated changes

* Automated changes

* change

* Automated changes

* also warning box

* Automated changes

* Automated changes

* tweak

* Automated changes

* Automated changes

* chack dir

* Automated changes

* Automated changes

* fenced div

* Automated changes

* Automated changes

* restaure

* restaure

* Automated changes

* Automated changes

* test sans espace

* box

* Automated changes

* Automated changes

* try christophe's solution

* pimp notebook

* Automated changes

* Automated changes

* check notebook

* Automated changes

* Automated changes

* partout

* Automated changes

* Automated changes

* notes

* avance

* avance

* footnotes ok?

* Automated changes

* Automated changes

* html tag

* html tag

* cell markdown

* Automated changes

* Automated changes

* build

* Automated changes

* Automated changes

* inverse typo

* Automated changes

* Automated changes

* wrap

* Automated changes

* Automated changes

* change

* restore

* buil

* Automated changes

* Automated changes

* pas retour ligne

* Automated changes

* Automated changes

* restre

* Automated changes

* Automated changes

* retire commentaire

* Automated changes

* Automated changes

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
  • Loading branch information
linogaliana and github-actions[bot] committed Aug 24, 2022
1 parent a8640e1 commit 8042a16
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 35 deletions.
15 changes: 10 additions & 5 deletions .github/workflows/netlify-test.yaml
Expand Up @@ -11,7 +11,7 @@ jobs:
blogdown:
name: Render-Blog
runs-on: ubuntu-latest
container: linogaliana/python-datascientist-vstudio:quarto
container: linogaliana/python-datascientist:latest
steps:
- uses: actions/checkout@v2
with:
Expand Down Expand Up @@ -65,7 +65,7 @@ jobs:
enonces:
name: Render-Blog
runs-on: ubuntu-latest
container: linogaliana/python-datascientist-vstudio:quarto
container: linogaliana/python-datascientist:latest
steps:
- uses: actions/checkout@v2
with:
Expand All @@ -79,13 +79,18 @@ jobs:
run: |
conda info
conda list
- name: Convert in ipynb with Jupytext
- name: Convert in ipynb with Quarto
run: |
git diff --name-only origin/master origin/${GITHUB_HEAD_REF} >> diff
python build/tweak_render.py
python build/pimp_notebook.py
quarto render content --to ipynb
mkdir -p notebooks
python build/move_files.py notebooks
- uses: actions/upload-artifact@v2
with:
name: Source enonce
path: content/
- uses: actions/upload-artifact@v2
with:
name: Enonces
Expand All @@ -108,7 +113,7 @@ jobs:
corrections:
name: Render-Blog
runs-on: ubuntu-latest
container: linogaliana/python-datascientist-vstudio:quarto
container: linogaliana/python-datascientist:latest
steps:
- uses: actions/checkout@v2
with:
Expand All @@ -122,7 +127,7 @@ jobs:
run: |
conda info
conda list
- name: Convert in ipynb with Jupytext
- name: Convert in ipynb with Quarto
run: |
git diff --name-only origin/master origin/${GITHUB_HEAD_REF} >> diff
python build/tweak_render.py
Expand Down
48 changes: 48 additions & 0 deletions build/pimp_notebook.py
@@ -0,0 +1,48 @@
import glob
import re

from tweak_markdown import read_file, write_file

def transform_note_reference(re_find, content_note=False):
num_note=re.findall(r'\d+', re_find.group())[0]
if content_note is False:
note_html = f"<a name=\"cite_ref-{num_note}\"></a>[<sup>[{num_note}]</sup>](#cite_note-{num_note})"
else:
note_html = "```{=html}\n" + f"<a name=\"cite_note-{num_note}\"></a>{num_note}. [^](#cite_ref-{num_note})"+ "\n```\n"
return note_html


def change_box_markdown(fl):
content = read_file(fl)
content = re.sub(r"(“|”)",'"',content)
print(f"File: {fl}")
# BOXES
list_rows = content.split("\n")
corresp_boxes = {
"note": "::: {.cell .markdown}\n```{=html}\n<div class=\"alert alert-info\" role=\"alert\">\n```",
"warning": "::: {.cell .markdown}\n```{=html}\n<div class=\"alert alert-danger\" role=\"alert\">\n```",
"danger": "::: {.cell .markdown}\n```{=html}\n<div class=\"alert alert-danger\" role=\"alert\">\n```",
"exercise": "::: {.cell .markdown}\n```{=html}\n<div class=\"alert alert-success\" role=\"alert\">\n```",
"hint": "::: {.cell .markdown}\n```{=html}\n<div class=\"alert alert-warning\" role=\"alert\">\n```"}
tweak_md = [corresp_boxes[re.search('status=\"(.*?)\"',l).group(1)] if l.startswith("{{% box") else l for l in list_rows]
tweak_md = ["```{=html}\n</div>\n```\n:::" if l.startswith("{{% /box") else l for l in tweak_md]
tweak_md = "\n".join(tweak_md)
# FOOTNOTES
p = re.compile("\[\^[0-9]+\]:")
list_match = list(p.finditer(tweak_md))
for i in range(0, len(list_match)):
m = list_match[i]
tweak_md = tweak_md.replace(m.group(0), transform_note_reference(m, content_note=True))
# 2. REFERENCE TO THE FOOTNOTE
p = re.compile("\[\^[0-9]+\]")
list_match = list(p.finditer(tweak_md))
for i in range(0, len(list_match)):
m = list_match[i]
tweak_md = tweak_md.replace(m.group(0), transform_note_reference(m, content_note=False))

write_file(fl, tweak_md)

if __name__ == '__main__':
list_files = glob.glob("./content/course/**/index.qmd", recursive=True)
print(list_files)
[change_box_markdown(fl) for fl in list_files if not fl.endswith("_index.md")]
11 changes: 8 additions & 3 deletions build/tweak_markdown.py
Expand Up @@ -45,6 +45,11 @@ def clean_write_file(fl):
content = tweak_js_plotly(content)
write_file(fl, content)

list_files = glob.glob("./content/course/**/index.md", recursive=True)
print(list_files)
[clean_write_file(fl) for fl in list_files if not fl.endswith("_index.md")]

if __name__ == '__main__':
list_files = glob.glob("./content/course/**/index.md", recursive=True)
print(list_files)
[clean_write_file(fl) for fl in list_files if not fl.endswith("_index.md")]



63 changes: 36 additions & 27 deletions content/course/manipulation/02a_pandas_tutorial/index.qmd
Expand Up @@ -29,6 +29,7 @@ bibliography: ../../../../reference.bib

Pour essayer les exemples présents dans ce tutoriel :

::: {.cell .markdown}
```{python}
#| echo: false
#| output: asis
Expand All @@ -42,6 +43,7 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02a_pandas_tutorial.qmd")
```
:::

Le _package_ `pandas` est l'une des briques centrales de l'écosystème de
la data-science. Son créateur, Wes McKinney, l'a pensé comme
Expand Down Expand Up @@ -72,14 +74,15 @@ Le [chapitre suivant](#pandasTP) permettra de mettre en application des élémen
les données ci-dessus associées à des données de contexte au niveau communal[^1].



::: {.cell .markdown}
[^1]: Idéalement, on utiliserait les données
[disponibles sur le site de l'Insee](https://www.insee.fr/fr/statistiques/3560121) mais celles-ci nécessitent un peu de travail
de nettoyage qui n'entre pas dans le cadre de ce TP.
Pour faciliter l'import de données Insee, il est recommandé d'utiliser le package
[`pynsee`](https://github.com/InseeFrLab/Py-Insee-Data) qui simplifie l'accès aux données
de l'Insee disponibles sur le site web [insee.fr](https://www.insee.fr/fr/accueil)
ou via des API.
:::

{{% box status="note" title="Note" icon="fa fa-comment" %}}
Le package `pynsee` est relativement jeune et n'est disponible que sur
Expand Down Expand Up @@ -146,6 +149,7 @@ np.random.seed(123)
Au cours de cette démonstration des principales fonctionalités de `pandas`, et
lors du TP

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -159,6 +163,7 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::


Je recommande de se référer régulièrement aux ressources suivantes:
Expand Down Expand Up @@ -212,19 +217,21 @@ se trouve sur une unique cellule.

![Concept de tidy data (emprunté à H. Wickham)](https://d33wubrfki0l68.cloudfront.net/6f1ddb544fc5c69a2478e444ab8112fb0eea23f8/91adc/images/tidy-1.png)

:warning: Les DataFrames sont assez rapides en Python[^1] et permettent de traiter en local de manière efficace des tables de
:warning: Les DataFrames sont assez rapides en Python[^2] et permettent de traiter en local de manière efficace des tables de
données comportant plusieurs millions d'observations (en fonction de la configuration de l'ordinateur)
et dont la volumétrie peut être conséquente (plusieurs centaines
de Mo). Néanmoins, passé un certain seuil, qui dépend de la puissance de la machine mais aussi de la complexité
de l'opération effectuée, le DataFrame `pandas` peut montrer certaines limites. Dans ce cas, il existe différentes
solutions: `dask` (dataframe aux opérations parallélisés), `SQL` (notamment postgres), `spark` (solution big data)

[^1]: En `R`, les deux formes de dataframes qui se sont imposées récemment sont les `tibbles` (package `dplyr`)
::: {.cell .markdown}
[^2]: En `R`, les deux formes de dataframes qui se sont imposées récemment sont les `tibbles` (package `dplyr`)
et les `data.tables` (package `data.table`). `dplyr` reprend la syntaxe SQL de manière relativement
transparente ce qui rend la syntaxe très proche de celle de `pandas`. Cependant,
alors que `dplyr` supporte très mal les données dont la volumétrie dépasse 1Go, `pandas` s'en
accomode bien. Les performances de `pandas` sont plus proches de celles de `data.table`, qui est
connu pour être une approche efficace avec des données de taille importante.
:::

Concernant la syntaxe, une partie des commandes python est inspirée par la logique SQL. On retrouvera ainsi
des instructions relativement transparentes.
Expand Down Expand Up @@ -291,6 +298,7 @@ taille['koala']
L'existence d'indice rend le *subsetting* particulièrement aisé, ce que vous
pouvez expérimenter dans les TP

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -304,6 +312,7 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::



Expand Down Expand Up @@ -374,12 +383,8 @@ Les types des variables peuvent différer.

Un DataFrame non-indexé a la structure suivante:

<!-----
Exo 1
Aller dans la doc pandas et trouver comment créer le dataFrame pandas suivant
------>

```{python, echo = FALSE}
```{python}
#| echo: false
df = pd.DataFrame(
{'taille': [1.,1.5,1],
'poids' : [3, 5, 2.5]
Expand All @@ -391,7 +396,8 @@ df.reset_index()

Alors que le même dataframe indexé aura la structure suivante:

```{python, echo = FALSE}
```{python}
#| echo: false
df = pd.DataFrame(
{'taille': [1.,1.5,1],
'poids' : [3, 5, 2.5]
Expand All @@ -409,6 +415,7 @@ on peut partir de l'exemple des consommations de CO2 communales issues
des données de l'Ademe. Cette base de données est exploitée plus intensément
dans le TP

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -422,6 +429,7 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::


```{python}
Expand All @@ -438,7 +446,7 @@ Sinon, on peut importer le csv, et modifier les types avec `astype()`.
Avec `astype`, on peut gérer les erreurs de conversion avec le paramètre `errors`.

L'affichage des DataFrames est très ergonomique. On obtiendrait le même *output*
avec `display(df)`[^2]. Les premières et dernières lignes s'affichent
avec `display(df)`[^3]. Les premières et dernières lignes s'affichent
automatiquement. Autrement, on peut aussi faire:

* `head` qui permet, comme son
Expand All @@ -448,6 +456,7 @@ nom l'indique, de n'afficher que les dernières lignes
* `sample` qui permet d'afficher un échantillon aléatoire de *n* lignes.
Cette méthode propose de nombreuses options

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -461,14 +470,17 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::

[^2]: Il est préférable d'utiliser la fonction `display` (ou tout simplement
::: {.cell .markdown}
[^3]: Il est préférable d'utiliser la fonction `display` (ou tout simplement
taper le nom du DataFrame qu'utiliser la fonction `print`). Le
`display` des objets `pandas` est assez esthétique, contrairement à `print`
qui renvoie du texte brut.

:::

{{% box status="danger" title="warning" icon="fa fa-exclamation-triangle" %}}

Il faut faire attention au `display` et aux
commandes qui révèlent des données (`head`, `tail`, etc.)
dans un notebook ou un markdown qui exploite
Expand All @@ -482,8 +494,11 @@ Techniquement, il est possible d'appliquer des filtres avec `git`
(voir
[ici](http://timstaley.co.uk/posts/making-git-and-jupyter-notebooks-play-nice/))
mais c'est une démarche très complexe

{{% /box %}}



On pourra alors préférer convertir systématiquement les `.ipynb` en `.py` grâce
à `jupytext` (`jupytext --to py nom_du_notebook.ipynb`) et mettre l'extension `*.ipynb`
dans le `.gitignore` de son projet git.
Expand Down Expand Up @@ -522,13 +537,14 @@ Voici un premier résumé des méthodes `pandas` utiles, et un comparatif avec `
| Opération | pandas | dplyr (`R`) | data.table (`R`) |
|-------------------------------|--------------|----------------|----------------------------|
| Récupérer le nom des colonnes | `df.columns` | `colnames(df)` | `colnames(df)` |
| Récupérer les indices[^3] | `df.index` | |`unique(df[,get(key(df))])` |
| Récupérer les indices[^4] | `df.index` | |`unique(df[,get(key(df))])` |
| Récupérer les dimensions | `df.shape` | `c(nrow(df), ncol(df))` | `c(nrow(df), ncol(df))` |
| Récupérer le nombre de valeurs uniques d'une variable | `df['myvar'].nunique()` | `df %>% summarise(distinct(myvar))` | `df[,uniqueN(myvar)]` |

[^3]: Le principe d'indice n'existe pas dans `dplyr`. Ce qui s'approche le plus des indices, au sens de
::: {.cell .markdown}
[^4]: Le principe d'indice n'existe pas dans `dplyr`. Ce qui s'approche le plus des indices, au sens de
`pandas`, sont les *clés* en `data.table`.

:::

### Statistiques agrégées

Expand All @@ -551,6 +567,7 @@ ces options sont déterminantes dans le résultat obtenu.

Les exercices de TD visent à démontrer l'intérêt de ces méthodes dans quelques cas précis.

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -564,18 +581,8 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::

<!---
Comme indiqué précédemment, il faut faire attention aux valeurs manquantes qui,
par défaut, sont traitées comme des 0.
Il est ainsi recommandé de systématiquement
ajouter l'argument skipna, par exemple,
```{python}
df.mean(skipna=True)
```
----->


Le tableau suivant récapitule le code équivalent pour avoir des
Expand Down Expand Up @@ -1054,6 +1061,7 @@ En règle générale, avec `python` comme avec `R`, les formats *long* sont souv

Le TP pandas proposera des applications de ces principes

::: {.cell .markdown}
```{python}
#| echo: false
#| output: 'asis'
Expand All @@ -1067,6 +1075,7 @@ from utils import print_badges
#print_badges(__file__)
print_badges("content/course/manipulation/02b_pandas_TP.qmd")
```
:::

## Les pipe

Expand Down

0 comments on commit 8042a16

Please sign in to comment.