2025.42 changes
This commit is contained in:
@@ -12,9 +12,9 @@ author: Steve Kossouho
|
||||
Il existe d'assez nombreuses bibliothèques Python destinées à faciliter le traitement de données.
|
||||
Bien que la bascule prenne du temps, de plus en plus de développeurs et d'entreprises optent pour
|
||||
inclure ces bibliothèques dans leur flux de travail, bien souvent en remplacement de solutions
|
||||
payantes telles que **SAS**, **Stata** ou **MatLab**.
|
||||
payantes telles que **SAS**, **Stata** ou **Excel**.
|
||||
|
||||
Parmi ces bibliothèques, on compte notamment `pyspark` (`Apache Spark`), `pandas`, `polars`
|
||||
Parmi ces bibliothèques, on compte notamment `pyspark` (un client `Apache Spark`), `pandas`, `polars`
|
||||
ou encore `dask`.
|
||||
|
||||
`pandas`, la plus connue d'entre elles, est une bibliothèque assez intuitive, destinée à des
|
||||
|
||||
@@ -581,13 +581,13 @@ import pandas as pd
|
||||
|
||||
data = pd.Series(data=["matt", "jenn", "igor", "alex", "mila"])
|
||||
# Ici on garde True si la valeur contient un "i" minuscule
|
||||
filter_data1 = data.loc[data.str.contains("i")]
|
||||
filter_data1 = data.loc[data.str.contains("i", regex=True)]
|
||||
# Ici on garde True si la valeur contient un "i" (ignore la casse)
|
||||
filter_data2_a = data.loc[data.str.contains("(?i)i")]
|
||||
filter_data2_b = data.loc[data.str.contains("i", case=False)]
|
||||
filter_data2_a = data.loc[data.str.contains("(?i)i", regex=True)]
|
||||
filter_data2_b = data.loc[data.str.contains("i", case=False, regex=True)]
|
||||
# Si vous connaissez les regex, le reste marche aussi :
|
||||
# Ici reconnaître les chaînes où un caractère apparaît 2 fois de suite
|
||||
filter_data3 = data.loc[data.str.contains(r"(\w)\1")]
|
||||
filter_data3 = data.loc[data.str.contains(r"(\w)\1", regex=True)]
|
||||
```
|
||||
|
||||
[Apprendre les Regex avec RegexLearn](https://regexlearn.com/fr)
|
||||
@@ -739,6 +739,8 @@ data["hour"] = data.dt.round("H")
|
||||
print(data)
|
||||
```
|
||||
|
||||
[Fréquences disponibles pour l'arrondi](https://pandas.pydata.org/docs/user_guide/timeseries.html#timeseries-offset-aliases)
|
||||
|
||||
----
|
||||
|
||||
### Dédupliquer des lignes
|
||||
@@ -1182,7 +1184,7 @@ df = pd.DataFrame(data={
|
||||
})
|
||||
|
||||
# Appliquer une fonction sur chaque colonne
|
||||
df2 = df.apply(double, axis="columns")
|
||||
df2 = df.apply(double, axis="index")
|
||||
```
|
||||
|
||||
----
|
||||
@@ -1365,6 +1367,25 @@ ses colonnes, mais uniquement à partir des deux lignes précédentes, ex. :
|
||||
|
||||
----
|
||||
|
||||
### Fonctions de partition : Comptage de lignes par groupe
|
||||
|
||||
Vous pouvez dans un DataFrame utiliser la méthode `.groupby()`{.python} pour scinder
|
||||
son contenu en groupes possédant une valeur en commun.
|
||||
En SQL, le résultat d'un `GROUP BY` doit généralement être suivi d'un calcul d'agrégation,
|
||||
qui va calculer une valeur d'agrégation (somme, moyenne) pour chaque groupe.
|
||||
Dans Pandas, la contrainte est généralement la même; on appliquera des méthodes
|
||||
d'agrégation une fois les groupes créés.
|
||||
|
||||
Pandas offre également des fonctions de [fenêtrage]{.naming} sur le résultat :
|
||||
Plutôt que d'obtenir un résultat seul pour chaque groupe, le partitionnement permet de conserver
|
||||
les lignes de chaque groupe. Une des fonctions de partitionnement proposées est
|
||||
`.cumcount()`{.python} : la méthode applique à chaque ligne une numérotation, qui
|
||||
démarre à zéro pour chaque groupe distinct.
|
||||
|
||||
TODO: Groupby + cumcount (potentiellement un sort_values avant)
|
||||
|
||||
----
|
||||
|
||||
### Fonctions d'agrégation mobiles/glissantes
|
||||
|
||||
Si nous appliquons cette idée sur la colonne `minutes`, nous obtiendrons une colonne avec les valeurs suivantes :
|
||||
@@ -1379,6 +1400,10 @@ runs = pd.DataFrame(data={
|
||||
"minutes": [31, 47, 26, 52, 34, 22, 36, 15, 30],
|
||||
})
|
||||
# Calculer la nouvelle colonne
|
||||
# Somme glissante utilisant 2 observations (premier argument)
|
||||
# Pour faire une somme, il faut au minimum 0 observation, sinon le résultat est NaN (min_periods=0)
|
||||
# L'argument `center=False`{.python} indique que la fenêtre est décalée vers le passé
|
||||
# L'argument `closed="both"`{.python} indique que les deux bornes sont incluses dans le calcul
|
||||
runs["3-day sum"] = runs["minutes"].rolling(2, min_periods=0, center=False, closed="both").sum()
|
||||
```
|
||||
|
||||
@@ -1398,11 +1423,30 @@ runs = pd.DataFrame(data={
|
||||
"minutes": [31, 47, 26, 52, 34, 22, 36, 15, 30],
|
||||
})
|
||||
# Calculer la nouvelle colonne
|
||||
runs["total sum"] = runs["minutes"].expanding(min_periods=0).sum()
|
||||
# La même chose peut être faite avec une somme roulante avec un grand nombre d'observations
|
||||
runs["total sum+"] = runs["minutes"].rolling(len(runs), min_periods=0).sum()
|
||||
runs["expanding mean"] = runs["minutes"].expanding(min_periods=0).mean()
|
||||
# La même chose peut être faite avec une moyenne roulante (lissée) avec un grand nombre d'observations
|
||||
runs["expanding mean+"] = runs["minutes"].rolling(len(runs), min_periods=0).mean()
|
||||
```
|
||||
|
||||
Les méthodes `runs.rolling`{.python} et `runs.expanding`{.python} peuvent être précédées d'un
|
||||
`.groupby()`{.python} et d'un `.sort_values()`{.python} pour créer des groupes d'agrégation
|
||||
et organiser les éléments dans chaque groupe.
|
||||
|
||||
----
|
||||
|
||||
## Astuces inoubliables
|
||||
|
||||
À l'usage, de nombreux cas empiriques déborderont des bases vues dans ce chapitre. Par exemple, certains
|
||||
comportements sont difficiles à comprendre, ou certains usages nécessitent quelques ajustements pour la performance.
|
||||
|
||||
- **Warnings** concernant la modification sur une copie
|
||||
- `pandas.DataFrame.apply()` très lent
|
||||
|
||||
----
|
||||
|
||||
### Warning : modifications sur une copie de slice
|
||||
|
||||
Lorsqu'un utilisateur utilise Pandas dans le cadre d'une recherche ou d'un traitement, il est fréquent de
|
||||
vouloir filtrer les lignes d'un `DataFrame`, puis d'appliquer des modifications au contenu de ce dernier.
|
||||
|
||||
|
||||
|
||||
@@ -108,29 +108,28 @@ pd.options.display.max_colwidth = 20 # max par colonne
|
||||
|
||||
### Options disponibles
|
||||
|
||||
| Attribut de l'option | Explication succincte |
|
||||
|-----------------------------|----------------------------------------------------------------|
|
||||
| `display.max_rows` | Nombre maximum de lignes à afficher |
|
||||
| `display.max_columns` | Nombre maximum de colonnes à afficher |
|
||||
| `display.width` | Largeur maximale de l'affichage en caractères |
|
||||
| `display.max_colwidth` | Largeur maximale en caractères pour une colonne |
|
||||
| `display.precision` | Nombre de décimales à afficher pour les nombres |
|
||||
| `display.float_format` | Format des nombres à virgule flottante |
|
||||
| `display.max_seq_items` | Nombre maximum d'éléments d'une séquence à afficher |
|
||||
| `display.expand_frame_repr` | Expansion automatique des DataFrames pour remplir la largeur |
|
||||
| `display.colheader_justify` | Justification des en-têtes de colonnes (left, right, center) |
|
||||
| Attribut de l'option | Explication succincte |
|
||||
|-----------------------------|--------------------------------------------------------------|
|
||||
| `display.max_rows` | Nombre maximum de lignes à afficher |
|
||||
| `display.max_columns` | Nombre maximum de colonnes à afficher |
|
||||
| `display.width` | Largeur maximale de l'affichage en caractères |
|
||||
| `display.max_colwidth` | Largeur maximale en caractères pour une colonne |
|
||||
| `display.precision` | Nombre de décimales à afficher pour les nombres |
|
||||
| `display.float_format` | Format des nombres à virgule flottante |
|
||||
| `display.max_seq_items` | Nombre maximum d'éléments d'une séquence à afficher |
|
||||
| `display.expand_frame_repr` | Expansion automatique des DataFrames pour remplir la largeur |
|
||||
| `display.colheader_justify` | Justification des en-têtes de colonnes (left, right, center) |
|
||||
|
||||
----
|
||||
|
||||
| Attribut de l'option | Explication succincte |
|
||||
|-----------------------------|----------------------------------------------------------------|
|
||||
| `display.show_dimensions` | Afficher les dimensions du DataFrame (True, False, 'truncate') |
|
||||
| `display.memory_usage` | Afficher l'utilisation de la mémoire pour les DataFrames |
|
||||
| `display.large_repr` | Représentation des grandes DataFrames ('truncate', 'info') |
|
||||
| `display.notebook_repr_html` | Utiliser l'HTML pour la représentation dans les notebooks |
|
||||
| `display.html.border` | Largeur de la bordure en pixels pour les représentations HTML |
|
||||
| `display.min_rows` | Nombre minimum de lignes à afficher |
|
||||
| `display.max_info_columns` | Nombre maximum de colonnes à inclure dans la sortie d'info() |
|
||||
| `display.max_info_rows` | Nombre maximum de lignes à inclure dans la sortie d'info() |
|
||||
| `display.memory_usage` | Afficher l'utilisation de la mémoire (True, False, 'deep') |
|
||||
| Attribut de l'option | Explication succincte |
|
||||
|------------------------------|----------------------------------------------------------------|
|
||||
| `display.show_dimensions` | Afficher les dimensions du DataFrame (True, False, 'truncate') |
|
||||
| `display.large_repr` | Représentation des grandes DataFrames ('truncate', 'info') |
|
||||
| `display.notebook_repr_html` | Utiliser l'HTML pour la représentation dans les notebooks |
|
||||
| `display.html.border` | Largeur de la bordure en pixels pour les représentations HTML |
|
||||
| `display.min_rows` | Nombre minimum de lignes à afficher |
|
||||
| `display.max_info_columns` | Nombre maximum de colonnes à inclure dans la sortie d'info() |
|
||||
| `display.max_info_rows` | Nombre maximum de lignes à inclure dans la sortie d'info() |
|
||||
| `display.memory_usage` | Afficher l'utilisation de la mémoire (True, False, 'deep') |
|
||||
|
||||
|
||||
@@ -41,13 +41,21 @@ toute la variété de graphiques générables avec Plotly, via des fonctions pr
|
||||
|
||||
### Installer Plotly Express
|
||||
|
||||
```bash= {.numberLines}
|
||||
```bash {.numberLines}
|
||||
pip install plotly
|
||||
```
|
||||
|
||||
Plotly contient un package `express` proposant des fonctions simples de rendu.
|
||||
|
||||
----
|
||||
|
||||
### Barres
|
||||
### Graphiques Plotly Express
|
||||
|
||||
Nous allons passer en revue quelques graphiques réalisables avec Express.
|
||||
|
||||
----
|
||||
|
||||
#### `plotly.express.bar`
|
||||
|
||||
Générer un graphique en barres est assez simple avec Plotly, et fonctionne
|
||||
de manière relativement satisfaisante par défaut (ex. texte en blanc sur fond sombre)
|
||||
@@ -56,15 +64,14 @@ de manière relativement satisfaisante par défaut (ex. texte en blanc sur fond
|
||||
import pandas as pd
|
||||
from plotly import express
|
||||
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["pomme", "poire", "banane", "pêche"],
|
||||
"price": [1.99, 2.49, 2.99, 3.49],
|
||||
"wpu": [200, 180, 140, 200]
|
||||
})
|
||||
# Générer un graphique
|
||||
# Générer un graphique avec deux colonnes par valeur de "product"
|
||||
figure = express.bar(data, x="product", y=["price", "wpu"], barmode="group", title="Prix et poids unitaires")
|
||||
figure.show()
|
||||
figure.show(renderer="browser") # Le renderer peut être obligatoire, ex. avec Spyder
|
||||
```
|
||||
|
||||
[Documentation de `bar`](https://plotly.com/python-api-reference/generated/plotly.express.bar.html)
|
||||
@@ -75,17 +82,16 @@ figure.show()
|
||||
|
||||
----
|
||||
|
||||
### Barres (sur un objet `Series`)
|
||||
#### `plotly.express.bar` (`Series`)
|
||||
|
||||
Vous pouvez également générer un graphique en partant d'un objet de type `Series`, même si l'objet ne contient
|
||||
Vous pouvez également générer un graphique en partant d'un objet de type `Series`{.python}, même si l'objet ne contient
|
||||
en lui-même qu'une seule colonne. Les valeurs d'index peuvent également servir sur un axe; il suffit d'utiliser
|
||||
la valeur `None`{.python} :
|
||||
la valeur `None`{.python} pour indiquer que les valeurs d'index doivent être utilisées sur l'axe des X.
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
from plotly import express
|
||||
|
||||
|
||||
values = pd.Series(
|
||||
data=[1.99, 2.49, 2.99, 3.49],
|
||||
index=["pomme", "poire", "banane", "peche"],
|
||||
@@ -93,15 +99,17 @@ values = pd.Series(
|
||||
)
|
||||
# Générer un graphique
|
||||
figure = express.bar(values, x=None, y="price")
|
||||
figure.show()
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
L'axe des Y pourra utiliser le nom associé à l'objet `Series` (`values.name`{.python})
|
||||
|
||||
----
|
||||
|
||||
#### Personnalisation
|
||||
|
||||
Quelques personnalisations sont possibles, notamment via la notion de `template` (thème),
|
||||
et de `layout` (organisation du contenu).
|
||||
que nous reverrons avec Plotly.
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
@@ -115,25 +123,8 @@ data = pd.DataFrame(data={
|
||||
# Générer un graphique. Plotly express ne prend en charge qu'un seul graphique par figure
|
||||
figure = express.bar(data, x="product", y="price", title="Prix", template="seaborn",
|
||||
labels={"price": "Prix", "product": "Produit"})
|
||||
figure.layout.update({"font": {"family": "Cabin", "size": 13}})
|
||||
figure.show()
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
Voici une liste des valeurs possibles fournies par Plotly pour l'argument `template`{.python}:
|
||||
|
||||
- `ggplot2` : Thème par défaut de GGPlot2 pour [R]{.naming}
|
||||
- `seaborn` : Thème par défaut de Seaborn pour Python
|
||||
- `plotly` : Thème par défaut de Plotly
|
||||
- `plotly_white`
|
||||
- `plotly_dark`
|
||||
- `presentation`
|
||||
- `xgridoff`
|
||||
- `ygridoff`
|
||||
- `gridon`
|
||||
- `none`
|
||||
|
||||
----
|
||||
|
||||

|
||||
@@ -144,7 +135,7 @@ Voici une liste des valeurs possibles fournies par Plotly pour l'argument `templ
|
||||
|
||||
----
|
||||
|
||||
### Secteurs concentriques
|
||||
#### `plotly.express.sunburst` (anneaux concentriques)
|
||||
|
||||
Le graphique [sunburst]{.naming} permet d'afficher des secteurs, et de les découper en sous-catégories
|
||||
dans des anneaux concentriques. Ici, nous avons un `DataFrame`{.python} avec des ventes par ville,
|
||||
@@ -175,7 +166,7 @@ if __name__ == '__main__':
|
||||
|
||||
----
|
||||
|
||||
### Nuages de points
|
||||
#### `plotly.express.scatter` (nuages de points)
|
||||
|
||||
Les nuages de points ([scatter plot]{.naming}) sont un moyen pratique de mettre en regard deux valeurs
|
||||
d'une même observation afin d'essayer de déduire une tendance ou une corrélation. Ils se présentent en
|
||||
@@ -186,14 +177,14 @@ graphique.
|
||||
import pandas as pd
|
||||
from plotly import express as px
|
||||
|
||||
# Charger le dataset Iris
|
||||
data = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data", header=None,
|
||||
names=["sepal-length", "sepal-width", "petal-length", "petal-width", "class"])
|
||||
|
||||
plot = px.scatter(data, x="sepal-length", y="sepal-width", size="petal-width", color="class", template="seaborn",
|
||||
title="Iris flowers dataset",
|
||||
labels={"sepal-length": "Sepal length", "sepal-width": "Sepal width", "petal-width": "Petal width", "class": "Class"})
|
||||
plot.layout.update({"font": {"family": "Cabin", "size": 13}})
|
||||
plot.show()
|
||||
plot.show(renderer="browser")
|
||||
```
|
||||
|
||||
[Documentation de `scatter`](https://plotly.com/python-api-reference/generated/plotly.express.scatter.html)
|
||||
@@ -204,76 +195,341 @@ plot.show()
|
||||
|
||||
----
|
||||
|
||||
## Construction
|
||||
## Plotly
|
||||
|
||||
Cette section regroupe plusieurs solutions pour parvenir à certains résultats.
|
||||
Cette section permet de creuser plus loin en utilisant les
|
||||
outils fondamentaux proposés par Plotly, eux aussi relativement simples
|
||||
mais riches.
|
||||
|
||||
----
|
||||
|
||||
### Deux axes Y dans un graphique en barres
|
||||
### Notions
|
||||
|
||||
Par défaut, Plotly Express ne génère pas deux axes distincts lorsque vous affichez un graphique
|
||||
avec deux colonnes pour l'axe Y. Si leurs ordres de grandeur sont différents, les barres partageront toutefois
|
||||
la même échelle.
|
||||
Plotly propose nombre d'outils classés dans certains thèmes pour vous permettre de
|
||||
personnaliser vos graphiques. Les thèmes que nous allons aborder sont les suivants :
|
||||
|
||||
Pour obtenir deux axes distincts en Y, nous devons utiliser Plotly manuellement. Rien d'anormalement
|
||||
complexe toutefois :
|
||||
| Thème | Description en français |
|
||||
|:----------------------------------|-----------------------------------------------------|
|
||||
| `templates` | Thèmes pour personnaliser les graphiques |
|
||||
| `layout` et `figure` | Mises en page pour les graphiques |
|
||||
| `axes` | Axes pour les graphiques |
|
||||
| `texttemplates` | Textes pour les éléments de graphiques |
|
||||
| `palettes de couleurs` | Sélections de couleurs pour les graphiques |
|
||||
| `séquences et cartes de couleurs` | Séquences et cartes de couleurs pour les graphiques |
|
||||
| `traces` | Tracés pour les graphiques |
|
||||
| `sous-graphiques` | Sous-graphiques pour les rendus |
|
||||
|
||||
|
||||
----
|
||||
|
||||
### Templates
|
||||
|
||||
Les [templates]{.naming} dans Plotly sont des objets contenant un ensemble de configurations
|
||||
pour le rendu d'éléments de graphiques. Les options individuelles personnalisables
|
||||
sont extrêmement nombreuses (des milliers), ainsi Plotly fournit des thèmes prêts
|
||||
à l'emploi pour vous permettre de personnaliser l'apparence de vos graphiques.
|
||||
Voici une liste des noms possibles fournis par Plotly pour appliquer un `template`{.python} à un rendu :
|
||||
|
||||
| Template | Description | Template | Description |
|
||||
|----------------|--------------------------------------|----------------|---------------------------------------------------|
|
||||
| `plotly` | Thème par défaut de **Plotly** | `ggplot2` | Thème par défaut de **GGPlot2** pour [R]{.naming} |
|
||||
| `seaborn` | Thème par défaut de **Seaborn** | `plotly_white` | Thème blanc avec des grilles |
|
||||
| `plotly_dark` | Thème sombre | `presentation` | Style optimisé pour les présentations |
|
||||
| `xgridoff` | Désactive la grille en X | `ygridoff` | Désactive la grille en Y |
|
||||
| `gridon` | Active les grilles sur les deux axes | `none` | Désactive tous les styles par défaut |
|
||||
|
||||
----
|
||||
|
||||
#### Associer un template
|
||||
|
||||
```python {.numberLines}
|
||||
from plotly.express import bar
|
||||
import pandas as pd
|
||||
|
||||
data = pd.DataFrame({
|
||||
"product": ["stylo", "clavier", "souris", "écran"],
|
||||
"price": [1.99, 15.99, 8.99, 129.99],
|
||||
})
|
||||
figure = bar(data, x="product", y="price", title="Prix", template="seaborn")
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
Ce code génère un graphique en barres, en utilisant le template `seaborn`{.python}.
|
||||
|
||||
[Documentation sur les templates](https://plotly.com/python/templates/)
|
||||
|
||||
----
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
#### Définir un template
|
||||
|
||||
Vous pouvez définir vos propres templates dans Plotly en définissant des objets héritant
|
||||
de la classe `plotly.graph_objs.layout.Template`{.python}.
|
||||
|
||||
Ces objets sont créés avec un dictionnaire contenant les configurations des éléments de graphiques
|
||||
que vous souhaitez personnaliser.
|
||||
|
||||
```python {.numberLines}
|
||||
from plotly.graph_objs.layout import Template
|
||||
|
||||
my_template = Template(layout={
|
||||
"hoverlabel": {"bgcolor": "#333333", "bordercolor": "black", "font": {
|
||||
"family": "Roboto", "size": 12, "color": "white", "weight": "bold"
|
||||
}},
|
||||
"font": {"family": "Roboto", "size": 15},
|
||||
"margin": {"pad": 20},
|
||||
"title": {"font": {"size": 36, "weight": "bold"}}
|
||||
})
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
#### Enregistrer le template
|
||||
|
||||
Pour enregistrer votre template afin de le désigner simplement par un nom, vous devez l'ajouter au
|
||||
dictionnaire des templates disponibles dans Plotly.
|
||||
|
||||
```python {.numberLines}
|
||||
from plotly.graph_objs.layout import Template
|
||||
from plotly.io import templates
|
||||
|
||||
my_template = Template(layout={
|
||||
"hoverlabel": {
|
||||
"bgcolor": "#333333",
|
||||
"bordercolor": "black",
|
||||
"font": {"family": "Roboto", "size": 12, "color": "white", "weight": "bold"}
|
||||
},
|
||||
"font": {"family": "Roboto", "size": 15},
|
||||
"margin": {"pad": 20},
|
||||
"title": {"font": {"size": 36, "weight": "bold"}}
|
||||
})
|
||||
# Enregistrer le template
|
||||
templates["my_template"] = my_template
|
||||
```
|
||||
|
||||
Vous pourrez ensuite le sélectionner en précisant son nom seul, ou via une addition `template="other_template+my_template"`{.python} afin de superposer
|
||||
les configurations des deux templates.
|
||||
|
||||
----
|
||||
|
||||
### Layout et Figure
|
||||
|
||||
Les objets de type `plotly.graph_objs.Layout`{.python} peuvent être renseignés sous forme de dictionnaires et comprennent
|
||||
plusieurs options pour personnaliser le rendu des graphiques. Les options disponibles sont nombreuses et varient en fonction
|
||||
du type de graphique que vous souhaitez afficher. Elles sont exactement les mêmes que celles des templates.
|
||||
|
||||
[Documentation sur les options de layout](https://plotly.com/python/reference/layout/)
|
||||
|
||||
----
|
||||
|
||||
#### Appliquer un layout (Express)
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
import plotly
|
||||
from plotly.graph_objs import Figure
|
||||
from plotly.express import sunburst
|
||||
|
||||
df = pd.DataFrame(data={
|
||||
"country": ["France", "France", "Spain", "Spain", "England", "England", "England"],
|
||||
"city": ["Montpellier", "Bordeaux", "Madrid", "Valencia", "London", "Manchester", "Bristol"],
|
||||
"sales": [150_000, 127_000, 97_200, 137_250, 200_000, 180_000, 150_000]
|
||||
})
|
||||
plot: Figure = sunburst(df, path=["country", "city"], values="sales", title="Sales by country and city", template="ggplot2")
|
||||
plot.layout.update({"font": {"family": "Cabin", "size": 13}, "showlegend": True})
|
||||
plot.show(renderer="browser")
|
||||
```
|
||||
|
||||
Les objets de type `plotly.graph_objs.Figure`{.python} possèdent un attribut `layout`{.python} de type `plotly.graph_objs.Layout`{.python},
|
||||
qui fonctionne comme un dictionnaire et permet de personnaliser le rendu des graphiques. Ici, on a personnalisé la police et l'affichage des légendes.
|
||||
|
||||
----
|
||||
|
||||
#### Appliquer un layout (Plotly)
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Bar
|
||||
|
||||
df = pd.DataFrame(data={"label": ["Citron", "Pomme", "Mangue"], "price": [1.99, 3.97, 6.8]})
|
||||
figure = Figure(
|
||||
data=[Bar(x=df["label"], y=df["price"])],
|
||||
layout={
|
||||
"font": {"family": "Cabin", "size": 20},
|
||||
"title": {"text": "Prix au kilo"},
|
||||
}
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
Ici, on crée un objet `Figure`{.python} manuellement, en lui associant une ou plusieurs [traces]{.naming}.
|
||||
L'initialisation accepte un argument `layout: dict`{.python} pour personnaliser le rendu des graphiques.
|
||||
|
||||
----
|
||||
|
||||
#### Exemples d'options de layout
|
||||
|
||||
| Option | Type / valeur possible | Description / notes |
|
||||
| ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `title.automargin` | booléen | Ajuste automatiquement les marges pour éviter le chevauchement du titre. |
|
||||
| `title.font` | dict | Définit la police du texte du titre. |
|
||||
| `title.font.color` | color | Couleur du texte du titre. |
|
||||
| `title.font.family` | string | Famille de police (ex. `"Arial, sans-serif"`). |
|
||||
| `title.font.lineposition` | flaglist / string | Décoration du texte : `"under"`, `"over"`, `"through"`, ou `"none"`. |
|
||||
| `title.font.shadow` | string | Définit l’ombre du texte, `"auto"` ou une valeur personnalisée. |
|
||||
| `title.font.size` | nombre | Taille de la police (>= 1). |
|
||||
| `title.font.style` | `"normal"` / `"italic"` | Style du texte (normal ou italique). |
|
||||
|
||||
1/4
|
||||
|
||||
----
|
||||
|
||||
| Option | Type / valeur possible | Description / notes |
|
||||
| ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `title.font.textcase` | `"normal"` / `"word caps"` / `"upper"` / `"lower"` | Définit la casse du texte. |
|
||||
| `title.font.variant` | `"normal"` / `"small-caps"` / `"all-small-caps"` | Variante typographique. |
|
||||
| `title.font.weight` | nombre ou `"normal"` / `"bold"` | Épaisseur de la police (1–1000). |
|
||||
| `title.pad` | dict | Définit les marges internes autour du titre. |
|
||||
| `title.pad.b` | nombre | Marge interne inférieure (px). |
|
||||
| `title.pad.l` | nombre | Marge interne gauche (px). |
|
||||
| `title.pad.r` | nombre | Marge interne droite (px). |
|
||||
| `title.pad.t` | nombre | Marge interne supérieure (px). |
|
||||
|
||||
2/4
|
||||
|
||||
----
|
||||
|
||||
| Option | Type / valeur possible | Description / notes |
|
||||
| ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `title.subtitle` | dict | Définit le sous-titre du graphique. |
|
||||
| `title.subtitle.text` | string | Texte du sous-titre. |
|
||||
| `title.subtitle.font` | dict | Police du sous-titre (mêmes propriétés que `title.font`). |
|
||||
| `title.text` | string | Texte du titre principal. |
|
||||
| `title.x` | nombre ∈ [0, 1] | Position horizontale du titre (relative à `title.xref`). |
|
||||
| `title.xanchor` | `"auto"` / `"left"` / `"center"` / `"right"` | Alignement horizontal du texte selon `x`. |
|
||||
| `title.xref` | `"container"` / `"paper"` | Référence horizontale du titre. |
|
||||
| `title.y` | nombre ∈ [0, 1] ou `"auto"` | Position verticale du titre (relative à `title.yref`). |
|
||||
|
||||
3/4
|
||||
|
||||
----
|
||||
|
||||
| Option | Type / valeur possible | Description / notes |
|
||||
| ------------------------- | -------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| `title.yanchor` | `"auto"` / `"top"` / `"middle"` / `"bottom"` | Alignement vertical du texte selon `y`. |
|
||||
| `title.yref` | `"container"` / `"paper"` | Référence verticale du titre. |
|
||||
|
||||
4/4
|
||||
|
||||
Toutes les options sont disponibles dans la [documentation officielle](https://plotly.com/python/reference/layout/) de Plotly.
|
||||
|
||||
----
|
||||
|
||||
#### Layouts à axes multiples
|
||||
|
||||
Par défaut, Plotly Express ne génère pas deux axes Y distincts lorsque vous affichez un graphique
|
||||
avec deux colonnes pour l'axe Y. Si leurs plages de valeurs sont différentes, les barres partageront toutefois
|
||||
la même échelle.
|
||||
|
||||
Pour définir deux axes distincts en Y (ou 3), nous devons utiliser Plotly manuellement.
|
||||
|
||||
```python {.numberLines}
|
||||
from plotly.graph_objs import Figure, Bar
|
||||
import pandas as pd
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["pomme", "poire", "banane", "pêche"],
|
||||
"price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200]
|
||||
})
|
||||
figure = Figure([
|
||||
Bar(name="Prix", x=data["product"], y=data["price"], yaxis="y", offsetgroup=1),
|
||||
Bar(name="Poids", x=data["product"], y=data["wpu"], yaxis="y2", offsetgroup=2),
|
||||
])
|
||||
# Afficher le dernier graphique généré
|
||||
figure.layout.update({
|
||||
"template": "seaborn",
|
||||
"title": "Prix et poids unitaires", "font": {"family": "Cabin", "size": 13},
|
||||
"yaxis": {"title": "Prix (€)"}, "yaxis2": {"title": "Poids (g)", "overlaying": "y", "side": "right"}
|
||||
})
|
||||
figure.show()
|
||||
figure = Figure(
|
||||
data=[
|
||||
Bar(name="Prix", x=data["product"], y=data["price"], yaxis="y1", offsetgroup=1),
|
||||
Bar(name="Poids", x=data["product"], y=data["wpu"], yaxis="y2", offsetgroup=2),
|
||||
],
|
||||
layout={
|
||||
"template": "seaborn",
|
||||
"title": "Prix et poids unitaires",
|
||||
"font": {"family": "Cabin", "size": 13},
|
||||
"yaxis1": {"title": "Prix (€)", "color": "red", "side": "left"},
|
||||
"yaxis2": {"title": "Poids (g)", "overlaying": "y1", "side": "right"}
|
||||
}
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
#### Nomenclature des axes
|
||||
|
||||
Plotly gère dynamiquement la définition de plusieurs axes dans un graphique. Lorsque vous définissez
|
||||
par exemple un axe Y pour un tracé orthogonal 2D, vous le définissez via un argument nommé `yaxis`{.python}.
|
||||
|
||||
La valeur de cet attribut est généralement un nom tel que `y`, `y1`, `y2`, etc.
|
||||
Notez que le nom `y`{.python} est un raccourci pour `y0`{.python}.
|
||||
|
||||
Les informations de mise en page pour cet axe sont ensuite définies dans le layout avec un nom similaire,
|
||||
par exemple `yaxis1`{.python} pour `y1`{.python}.
|
||||
|
||||
----
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
### Texte personnalisé dans un camembert
|
||||
### Texte personnalisé dans les éléments
|
||||
|
||||
Par défaut, les secteurs de graphique camembert ([pie]{.naming}) affichent la taille
|
||||
d'un secteur en pourcents du total. Vous pouvez y formater d'autres infos :
|
||||
d'un secteur en pourcents du total. De façon moins évidente, le texte des barres est
|
||||
masqué par défaut. L'affichage ou non d'une étiquette, et la personnalisation du texte
|
||||
des étiquettes est possible, via un ensemble d'arguments définis dans le tableau suivant.
|
||||
|
||||
| Option | Type / valeur possible | Description / notes |
|
||||
| ------------------------- |-------------------------------------------------| ------------------------------------------------------------------------ |
|
||||
| `textinfo` | `"label"` / `"value"` / `"percent"` ou addition | Définit le texte à afficher dans chaque secteur. |
|
||||
| `texttemplate` | string | Format du texte à afficher dans chaque secteur. |
|
||||
| `textposition` | `"inside"` / `"outside"` / `"auto"` / `"middle"` | Position du texte par rapport au secteur. |
|
||||
|
||||
----
|
||||
|
||||
#### Texte de secteurs de camembert
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
from plotly import express as px
|
||||
from plotly.graph_objs import Figure, Pie
|
||||
from plotly.colors import qualitative
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["pomme", "poire", "banane", "pêche"],
|
||||
"price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200]
|
||||
"product": ["oignon", "carotte", "pomme", "poire", "radis", "tomate"],
|
||||
"category": ["légume", "légume", "fruit", "fruit", "légume", "fruit"],
|
||||
"origin": ["Espagne", "France", "France", "France", "France", "Espagne"],
|
||||
"price": [1.69, 2.49, 2.99, 1.79, 1.29, 2.99]
|
||||
})
|
||||
figure = px.pie(data, values="price", names="product", title="Prix")
|
||||
# Afficher le dernier graphique généré
|
||||
figure.layout.update({
|
||||
"template": "seaborn",
|
||||
"title": "Prix au kilo", "font": {"family": "Cabin", "size": 13},
|
||||
})
|
||||
figure.update_traces(**{"textinfo": "label+value", "texttemplate": "%{label}<br>%{value:.2f}€"})
|
||||
figure.show()
|
||||
figure = Figure(
|
||||
data=[Pie(
|
||||
values=data["price"],
|
||||
labels=data["product"].str.title(),
|
||||
customdata=data[["category", "origin"]], # 2 colonnes
|
||||
title="Prix",
|
||||
textinfo="label+value",
|
||||
texttemplate="<b>%{label}</b><br>%{value:.2f}€<br><em>%{customdata[0]}</em><br>%{customdata[1]}",
|
||||
insidetextorientation="tangential")
|
||||
],
|
||||
layout={
|
||||
"template": "seaborn",
|
||||
"title": "Prix au kilo", "font": {"family": "Cabin", "size": 13},
|
||||
"piecolorway": qualitative.Prism
|
||||
})
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
[Personnalisation des camemberts](https://plotly.com/python/pie-charts/)
|
||||
|
||||
----
|
||||
|
||||

|
||||

|
||||
|
||||
----
|
||||
|
||||
@@ -332,3 +588,42 @@ colorier les barres.
|
||||
----
|
||||
|
||||

|
||||
|
||||
----
|
||||
|
||||
### Tracer une ligne ou une courbe de régression
|
||||
|
||||
Pour analyser la tendance générale de la disposition des points d'un jeu de données, il est
|
||||
souvent intéressant de tracer des courbes (polynômes) ou des lignes.
|
||||
|
||||
Numpy propose une fonction de régression pour des points 2D, capable de générer les coefficients
|
||||
d'une fonction polynômiale du `n`ième degré : `np.polyfit()`{.python}
|
||||
|
||||
----
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from plotly.graph_objs import Figure, Scatter
|
||||
from scipy.ndimage import gaussian_filter
|
||||
|
||||
# Créer une courbe aléatoire lissée
|
||||
df = pd.DataFrame(data={"col1": gaussian_filter(np.random.random(size=200) * 79.0 + 1.0, sigma=1.5)})
|
||||
# Calculer les coefficients d'une régression de degré 2 pour col1
|
||||
c2, c1, c0 = np.polyfit(df.index, df["col1"], 2)
|
||||
df["reg1"] = df.index ** 2 * c2 + df.index * c1 + c0
|
||||
|
||||
# Créer une image avec deux lignes
|
||||
figure = Figure([
|
||||
Scatter(name="values", x=df.index, y=df["col1"], line={"color": "black", "width": 2}, marker={"symbol": "circle"}, mode="lines+markers"),
|
||||
Scatter(name="regression", x=df.index, y=df["reg1"], line={"color": "red", "width": 4, "dash": "dot"}, mode="lines")
|
||||
])
|
||||
figure.layout.update({"template": "seaborn", "xaxis1": {"title": "time"}, "title": "Test de régression", "font": {"family": "Cabin", "size": 13}, "yaxis1": {"title": "value"}})
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
Calcul et tracé d'une courbe sur un graphique avec `scipy` et `Plotly`
|
||||
|
||||
----
|
||||
|
||||

|
||||
|
||||
@@ -88,7 +88,8 @@ Modin utilise une technique de **partitionnement** pour diviser le fichier en mo
|
||||
|
||||
## Opérations de transformation
|
||||
|
||||
Modin prend en charge la plupart des opérations Pandas standard comme `groupby`{.py}, `merge`{.py}, et `join`{.python}. Ces opérations sont distribuées, ce qui permet de les réaliser rapidement.
|
||||
Modin prend en charge la plupart des opérations Pandas standard comme `groupby`{.py}, `merge`{.py}, et `join`{.python}.
|
||||
Ces opérations sont distribuées, ce qui permet de les réaliser rapidement.
|
||||
|
||||
```python {.numberLines}
|
||||
# GroupBy avec Modin
|
||||
@@ -116,7 +117,8 @@ mdf = mpd.read_csv("large_dataset.csv")
|
||||
%time mdf.groupby("column_name").mean()
|
||||
```
|
||||
|
||||
Modin affiche un temps de calcul inférieur en utilisant plusieurs cœurs. Cela ne se verra que lorsque vous travaillez avec des jeux de données volumineux.
|
||||
Modin affiche un temps de calcul inférieur en utilisant plusieurs cœurs.
|
||||
Cela ne se verra que lorsque vous travaillez avec des jeux de données suffisamment volumineux.
|
||||
|
||||
----
|
||||
|
||||
@@ -161,7 +163,8 @@ Modin détecte automatiquement le backend configuré et exécute les opérations
|
||||
|
||||
## Limitations et cas particuliers
|
||||
|
||||
Bien que Modin accélère de nombreuses opérations, certaines fonctionnalités de pandas ne sont pas encore entièrement prises en charge. Les opérations très complexes ou nécessitant un traitement unique peuvent ne pas bénéficier de la même accélération.
|
||||
Bien que Modin accélère de nombreuses opérations, certaines fonctionnalités de pandas ne sont pas encore entièrement prises en charge.
|
||||
Les opérations très complexes ou nécessitant un traitement unique peuvent ne pas bénéficier de la même accélération.
|
||||
|
||||
Quelques limitations à garder en tête :
|
||||
|
||||
|
||||
@@ -5,82 +5,119 @@ author: Steve Kossouho
|
||||
|
||||
# Gestion de tâches avec Celery
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Qu'est-ce que Celery ?
|
||||
|
||||
Celery est une bibliothèque Python open source qui est utilisée pour la gestion asynchrone de tâches. Il permet de distribuer l'exécution des tâches sur plusieurs travailleurs (workers), que l'on peut répartir sur plusieurs machines ou sur un même serveur.
|
||||
**Celery** est une bibliothèque Python open source qui est utilisée pour l'exécution asynchrone de tâches.
|
||||
Elle permet de distribuer l'exécution des tâches sur plusieurs travailleurs (workers), que l'on peut répartir sur plusieurs machines ou sur un même serveur.
|
||||
|
||||
Grâce à sa capacité de parallélisation, Celery est un excellent choix pour réaliser des tâches longues et coûteuses telles que le traitement de gros volumes de données avec Pandas.
|
||||
Grâce à sa capacité de parallélisation, Celery est un bon choix pour exécuter sans supervision directe des tâches longues et coûteuses
|
||||
telles que des calculs longs, typiquement sur de gros volumes de données.
|
||||
|
||||
---
|
||||
{width=160px}
|
||||
|
||||
----
|
||||
|
||||
## Configuration de Celery
|
||||
|
||||
Pour commencer à utiliser Celery, vous devez tout d'abord installer le paquet via pip :
|
||||
|
||||
```{.bash .numberLines}
|
||||
```bash {.numberLines}
|
||||
pip install celery
|
||||
```
|
||||
|
||||
Ensuite, vous aurez besoin d'un broker de messages, qui est utilisé par Celery pour passer les messages entre votre application principale et les travailleurs. Celery supporte plusieurs brokers de messages, mais nous utiliserons ici Redis pour sa simplicité d'utilisation.
|
||||
Ensuite, vous aurez besoin d'un [broker]{.naming} de messages, qui est utilisé par Celery pour transmettre des messages
|
||||
de façon bidirectionnelle entre votre application principale et les processus exécutant des tâches.
|
||||
Celery prend en charge plusieurs brokers de messages, mais nous utiliserons ici Redis pour sa simplicité d'utilisation.
|
||||
|
||||
```{.bash .numberLines}
|
||||
```bash {.numberLines}
|
||||
pip install redis
|
||||
```
|
||||
|
||||
Une fois Redis installé, vous pouvez configurer Celery pour l'utiliser comme broker. Pour cela, vous devez créer une instance de Celery dans votre application :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
from celery import Celery
|
||||
|
||||
app = Celery('myapp', broker='redis://localhost:6379/0')
|
||||
CELERY_APP_NAME = 'myapp'
|
||||
CELERY_BROKER_URL = 'redis://localhost:6379/0'
|
||||
|
||||
app = Celery(CELERY_APP_NAME, broker=CELERY_BROKER_URL)
|
||||
```
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Utilisation de Celery pour paralléliser des calculs avec Pandas
|
||||
## Démarrer des tâches
|
||||
|
||||
Pour utiliser Celery pour paralléliser des calculs avec Pandas, vous devez d'abord définir des tâches. Une tâche est une fonction qui est exécutée de manière asynchrone. Par exemple, disons que vous ayez une fonction qui effectue un calcul sur un DataFrame Pandas :
|
||||
Pour démarrer avec Celery, vous devez d'abord définir des [tâches]{.naming}.
|
||||
Une tâche se déclare sous la forme d'une fonction qui sera exécutée de manière asynchrone.
|
||||
Par exemple, imaginons que vous avez une fonction qui effectue un calcul sur un DataFrame Pandas :
|
||||
|
||||
```{.python .numberLines}
|
||||
def calculate(df):
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
|
||||
def calculate(df: pd.DataFrame):
|
||||
return df.sum()
|
||||
```
|
||||
|
||||
Vous pouvez transformer cette fonction en une tâche Celery en utilisant le décorateur `app.task` :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
from celery import Celery
|
||||
|
||||
app = Celery(..., broker=...)
|
||||
|
||||
@app.task
|
||||
def calculate(df):
|
||||
def calculate(df: pd.DataFrame):
|
||||
return df.sum()
|
||||
```
|
||||
|
||||
Maintenant, vous pouvez exécuter cette fonction de manière asynchrone en utilisant la méthode `.delay()` :
|
||||
----
|
||||
|
||||
```{.python .numberLines}
|
||||
Vous pouvez désormais exécuter cette fonction de manière asynchrone en utilisant la méthode `task.delay()`{.python} :
|
||||
|
||||
```python {.numberLines}
|
||||
result = calculate.delay(df)
|
||||
```
|
||||
|
||||
La méthode `.delay()` renvoie un objet `AsyncResult` que vous pouvez utiliser pour obtenir le résultat de la tâche une fois qu'elle est terminée :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
print(result.get())
|
||||
```
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Utilisation de Celery pour planifier des tâches avec Pandas
|
||||
### Serveur de Celery
|
||||
|
||||
Celery fournit également un moyen de planifier l'exécution des tâches. Pour cela, vous aurez besoin de l'extension Celery Beat.
|
||||
Pour demarrer le serveur de Celery, qui exécutera les tâches, vous devez utiliser la commande `celery worker` dans votre terminal.
|
||||
|
||||
Avec Celery Beat, vous pouvez définir des intervalles de temps réguliers pour l'exécution des tâches. Par exemple, vous pouvez configurer une tâche pour qu'elle soit exécutée toutes les 10 minutes.
|
||||
```bash {.numberLines}
|
||||
celery worker
|
||||
```
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Planifier des tâches
|
||||
|
||||
Celery fournit également un moyen de planifier l'exécution des tâches.
|
||||
Pour cela, vous aurez besoin de l'extension _Celery Beat_.
|
||||
|
||||
Avec Celery Beat, vous pouvez définir des intervalles de temps réguliers pour l'exécution des tâches.
|
||||
Par exemple, vous pouvez configurer une tâche pour qu'elle soit exécutée toutes les 10 minutes.
|
||||
|
||||
Vous avez le choix entre deux types d'intervalle :
|
||||
|
||||
- **crontab** : Utiliser une expression de crontab pour définir l'intervalle de temps.
|
||||
- **schedule** : Utiliser un objet `datetime.timedelta` pour définir l'intervalle de temps.
|
||||
|
||||
----
|
||||
|
||||
Voici comment vous pouvez configurer Celery Beat pour exécuter une tâche toutes les 10 minutes :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
from celery.schedules import crontab
|
||||
|
||||
app.conf.beat_schedule = {
|
||||
@@ -91,65 +128,72 @@ app.conf.beat_schedule = {
|
||||
}
|
||||
```
|
||||
|
||||
Dans cet exemple, `myapp.calculate` est le nom de la tâche que vous souhaitez exécuter. L'objet `crontab` est utilisé pour définir l'intervalle de temps pour l'exécution de la tâche.
|
||||
Dans cet exemple, `myapp.calculate` est le chemin d'import pleinement qualifié de la tâche que vous souhaitez exécuter.
|
||||
L'objet `crontab` est utilisé pour définir l'intervalle de temps pour l'exécution de la tâche.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
Celery est une bibliothèque puissante qui, associée à Pandas, peut grandement faciliter la gestion de tâches lourdes et coûteuses en termes de calcul.
|
||||
### Serveur de Celery Beat
|
||||
|
||||
---
|
||||
Pour demarrer le serveur de Celery Beat, vous devez utiliser la commande `celery beat` dans votre terminal.
|
||||
|
||||
```bash {.numberLines}
|
||||
celery beat
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
# Alternatives à Celery
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## RQ (Redis Queue)
|
||||
|
||||
[RQ](https://python-rq.org/) est une bibliothèque Python simple pour la mise en file d'attente des tâches. Elle utilise Redis comme système de file d'attente. RQ est particulièrement apprécié pour sa simplicité et sa clarté, il est donc plus facile à apprendre et à mettre en œuvre que Celery.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Dramatiq
|
||||
|
||||
[Dramatiq](https://dramatiq.io/) est une bibliothèque Python de mise en file d'attente de tâches distribuées avec un accent sur la simplicité, la fiabilité et la performance. Comme Celery, Dramatiq peut utiliser plusieurs brokers de messages, dont RabbitMQ et Redis.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## TaskTiger
|
||||
|
||||
[TaskTiger](https://tasktiger.readthedocs.io/en/latest/) est une autre bibliothèque Python pour la gestion des tâches. Elle utilise également Redis comme système de file d'attente. TaskTiger offre des fonctionnalités uniques telles que la possibilité de gérer les tâches en batch et une interface d'administration intégrée.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Apache Airflow
|
||||
|
||||
[Airflow](https://airflow.apache.org/) est une plateforme utilisée pour programmer et surveiller des flux de travail. Créée par Airbnb, elle est utilisée pour gérer les processus ETL complexes. Bien qu'elle ne soit pas une bibliothèque Python à proprement parler, elle est écrite en Python et est couramment utilisée dans les projets de science des données.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
Ces bibliothèques offrent chacune une approche unique de la mise en file d'attente des tâches en Python et sont toutes de bonnes alternatives à Celery selon les besoins spécifiques de votre projet.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
# Utilisation de RQ (Redis Queue)
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Installation
|
||||
|
||||
Pour commencer à utiliser RQ, vous devez l'installer en exécutant la commande suivante :
|
||||
|
||||
```{.bash .numberLines}
|
||||
```bash {.numberLines}
|
||||
pip install rq
|
||||
```
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Configuration
|
||||
|
||||
RQ nécessite un broker de messages pour fonctionner, et il utilise Redis par défaut. Assurez-vous d'avoir installé et démarré un serveur Redis sur votre machine. Une fois le serveur Redis en place, vous pouvez créer une connexion à Redis dans votre script Python :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
from redis import Redis
|
||||
from rq import Queue
|
||||
|
||||
@@ -160,37 +204,37 @@ redis_conn = Redis()
|
||||
q = Queue(connection=redis_conn)
|
||||
```
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Envoi de tâches
|
||||
|
||||
Une fois que vous avez configuré votre file d'attente, vous pouvez commencer à y ajouter des tâches. Voici un exemple de fonction que nous pourrions vouloir exécuter en arrière-plan :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
def say_hello(name):
|
||||
print(f'Hello, {name}!')
|
||||
```
|
||||
|
||||
Pour ajouter cette tâche à notre file d'attente, nous utilisons la méthode `enqueue()` de notre objet `Queue` :
|
||||
|
||||
```{.python .numberLines}
|
||||
```python {.numberLines}
|
||||
q.enqueue(say_hello, 'Alice')
|
||||
```
|
||||
|
||||
Cette tâche sera alors ajoutée à la file d'attente et exécutée par un "travailleur" RQ dès qu'il sera disponible.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
## Démarrage d'un Worker
|
||||
|
||||
Pour démarrer un travailleur RQ qui va consommer des tâches depuis la file d'attente, vous pouvez utiliser la commande `rq worker` dans votre terminal. Assurez-vous d'être dans le même environnement que celui où votre serveur Redis est en cours d'exécution :
|
||||
|
||||
```{.bash .numberLines}
|
||||
```bash {.numberLines}
|
||||
rq worker
|
||||
```
|
||||
|
||||
Le travailleur va démarrer et commencer à traiter les tâches de la file d'attente.
|
||||
|
||||
---
|
||||
----
|
||||
|
||||
L'utilisation de RQ est un moyen simple et efficace de gérer les tâches en arrière-plan en Python. Avec sa simplicité et sa facilité d'utilisation, RQ est un excellent choix pour les applications Python qui nécessitent la mise en file d'attente de tâches.
|
||||
BIN
documentation/assets/images/eda-plotly-regression-curve.png
Normal file
BIN
documentation/assets/images/eda-plotly-regression-curve.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 250 KiB |
BIN
documentation/assets/images/eda-plotly-template-select-base.png
Normal file
BIN
documentation/assets/images/eda-plotly-template-select-base.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 61 KiB |
BIN
documentation/assets/images/eda-plotly-texttemplate-pie.png
Normal file
BIN
documentation/assets/images/eda-plotly-texttemplate-pie.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
BIN
documentation/assets/images/performance-celery-logo.png
Normal file
BIN
documentation/assets/images/performance-celery-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.5 KiB |
11
source/pandas/01-pandas-files/.pandasrc.ini
Normal file
11
source/pandas/01-pandas-files/.pandasrc.ini
Normal file
@@ -0,0 +1,11 @@
|
||||
[display]
|
||||
width = 200
|
||||
max_colwidth = 25
|
||||
max_columns = 20
|
||||
min_rows = 20
|
||||
precision = 3
|
||||
expand_frame_repr = True
|
||||
memory_usage = True
|
||||
|
||||
[display.html]
|
||||
border = 4
|
||||
7
source/pandas/01-pandas-files/03-csv-catalog.py
Normal file
7
source/pandas/01-pandas-files/03-csv-catalog.py
Normal file
@@ -0,0 +1,7 @@
|
||||
import pandas as pd
|
||||
from pandas import configfile
|
||||
|
||||
|
||||
configfile.load()
|
||||
df = pd.read_csv("../data/csv/demo-file.csv", encoding="1252", header=None)
|
||||
print(df)
|
||||
BIN
source/pandas/data/datasets-csv-excel.zip
Normal file
BIN
source/pandas/data/datasets-csv-excel.zip
Normal file
Binary file not shown.
@@ -2,7 +2,7 @@ import pandas as pd
|
||||
from matplotlib import use, pyplot
|
||||
|
||||
# Utiliser tkinter
|
||||
use("TkAgg")
|
||||
# use("TkAgg")
|
||||
pyplot.style.use('ggplot')
|
||||
pyplot.rcParams["font.family"] = "Cabin"
|
||||
|
||||
|
||||
14
source/plotting/charts/plotly_figure_bar.py
Normal file
14
source/plotting/charts/plotly_figure_bar.py
Normal file
@@ -0,0 +1,14 @@
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Bar
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
df = pd.DataFrame(data={"label": ["Citron", "Pomme", "Mangue"], "price": [1.99, 3.97, 6.8]})
|
||||
figure = Figure(
|
||||
data=[Bar(x=df["label"], y=df["price"])],
|
||||
layout={
|
||||
"font": {"family": "Cabin", "size": 20},
|
||||
"title": "Prix au kilo",
|
||||
}
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
20
source/plotting/charts/plotly_figure_multiaxis.py
Normal file
20
source/plotting/charts/plotly_figure_multiaxis.py
Normal file
@@ -0,0 +1,20 @@
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Bar
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["pomme", "poire", "banane", "pêche"],
|
||||
"price": [1.99, 2.49, 2.99, 3.49], "wpu": [200, 180, 140, 200]
|
||||
})
|
||||
figure = Figure([
|
||||
Bar(name="Prix", x=data["product"], y=data["price"], yaxis="y1", offsetgroup=1, texttemplate="%{y:.2f}€"),
|
||||
Bar(name="Poids", x=data["product"], y=data["wpu"], yaxis="y2", offsetgroup=2, texttemplate="%{y:.2f}g"),
|
||||
])
|
||||
# Afficher le dernier graphique généré
|
||||
figure.layout.update({
|
||||
"template": "seaborn",
|
||||
"title": "Prix et poids unitaires",
|
||||
"font": {"family": "Cabin", "size": 13},
|
||||
"yaxis1": {"title": "Prix (€)", "color": "red"},
|
||||
"yaxis2": {"title": "Poids (g)", "overlaying": "y1", "side": "right"}
|
||||
})
|
||||
figure.show(renderer="browser")
|
||||
27
source/plotting/charts/plotly_figure_pie.py
Normal file
27
source/plotting/charts/plotly_figure_pie.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Pie
|
||||
from plotly.colors import qualitative
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["oignon", "carotte", "pomme", "poire", "radis", "tomate"],
|
||||
"category": ["légume", "légume", "fruit", "fruit", "légume", "fruit"],
|
||||
"origin": ["Espagne", "France", "France", "France", "France", "Espagne"],
|
||||
"price": [1.69, 2.49, 2.99, 1.79, 1.29, 2.99]
|
||||
})
|
||||
figure = Figure(
|
||||
data=[Pie(
|
||||
values=data["price"],
|
||||
labels=data["product"].str.title(),
|
||||
customdata=data[["category", "origin"]],
|
||||
title="Prix",
|
||||
textinfo="label+value",
|
||||
texttemplate="<b>%{label}</b><br>%{value:.2f}€<br><em>%{customdata[0]}</em><br>%{customdata[1]}",
|
||||
insidetextorientation="tangential")
|
||||
],
|
||||
layout={
|
||||
"template": "seaborn",
|
||||
"font": {"family": "Cabin", "size": 20},
|
||||
"title": "Prix au kilo",
|
||||
"piecolorway": qualitative.Prism
|
||||
})
|
||||
figure.show(renderer="browser")
|
||||
29
source/plotting/charts/plotly_figure_sunburst.py
Normal file
29
source/plotting/charts/plotly_figure_sunburst.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Sunburst
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
df = pd.DataFrame(data={
|
||||
"continent": ["Europe", "Europe", "Europe", "Europe", "Europe", "Europe", "Europe", "Asia", "Asia"],
|
||||
"country": ["France", "France", "Spain", "Spain", "England", "England", "England", "China", "China"],
|
||||
"city": ["Montpellier", "Bordeaux", "Madrid", "Valencia", "London", "Manchester", "Bristol", "Beijing", "Shanghai"],
|
||||
"sales": [150_000, 127_000, 97_200, 137_250, 200_000, 180_000, 150_000, 120_000, 140_000]
|
||||
})
|
||||
# Create a path column
|
||||
PATH: list[str] = ["continent", "country", "city"]
|
||||
COLUMNS: list[str] = [None] * (len(PATH) - 2) + ["parent", "child"]
|
||||
|
||||
rollups = []
|
||||
base = df.groupby(PATH).sum(numeric_only=True)
|
||||
for level in range(len(PATH)):
|
||||
rollup = base.groupby(None, level=list(range(level + 1))).sum()
|
||||
rollup = rollup.reset_index(list(range(level + 1)), names=COLUMNS[-level - 1:])
|
||||
rollups.append(rollup)
|
||||
rollups = pd.concat(rollups, axis=0)
|
||||
|
||||
sb = Sunburst(labels=rollups["child"], parents=rollups["parent"], values=rollups["sales"], textinfo="label+value+percent parent", texttemplate="%{label}<br>%{value:,.2f}€", branchvalues="total")
|
||||
fig: Figure = Figure(sb, layout={
|
||||
"font": {"family": "Cabin", "size": 13},
|
||||
"margin": {"l": 0, "r": 0, "b": 0, "t": 0}
|
||||
})
|
||||
fig.show(renderer="browser")
|
||||
@@ -17,5 +17,9 @@ if __name__ == '__main__':
|
||||
})
|
||||
plot = sunburst(df, path=["country", "city"], values="sales", title="Sales by country and city", template="ggplot2",
|
||||
color_discrete_sequence=plotly.colors.qualitative.Dark2)
|
||||
plot.layout.update({"font": {"family": "Cabin", "size": 13}})
|
||||
plot.show()
|
||||
sb = next(plot.select_traces(row=0, col=0))
|
||||
sb.textinfo="label+percent parent"
|
||||
# sb.texttemplate="%{label}<br>%{value:.2f}€"
|
||||
plot.layout.update({"font": {"family": "Cabin", "size": 13}, "showlegend": True})
|
||||
# plot.update_traces(textinfo="label+percent parent", texttemplate="%{label}<br>%{value:.2f}€")
|
||||
plot.show(renderer="browser")
|
||||
|
||||
9
source/plotting/charts/plotly_template_select.py
Normal file
9
source/plotting/charts/plotly_template_select.py
Normal file
@@ -0,0 +1,9 @@
|
||||
from plotly.express import bar
|
||||
import pandas as pd
|
||||
|
||||
data = pd.DataFrame({
|
||||
"product": ["stylo", "clavier", "souris", "écran"],
|
||||
"price": [1.99, 15.99, 8.99, 129.99],
|
||||
})
|
||||
figure = bar(data, x="product", y="price", title="Prix", template="seaborn")
|
||||
figure.show(renderer="browser")
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
@@ -1,163 +0,0 @@
|
||||
amqp==5.2.0
|
||||
anyio==4.3.0
|
||||
argon2-cffi==23.1.0
|
||||
argon2-cffi-bindings==21.2.0
|
||||
arrow==1.3.0
|
||||
asttokens==2.4.1
|
||||
async-lru==2.0.4
|
||||
attrs==23.2.0
|
||||
Babel==2.14.0
|
||||
beautifulsoup4==4.12.3
|
||||
billiard==4.2.0
|
||||
bleach==6.1.0
|
||||
blinker==1.8.1
|
||||
cairocffi==1.7.0
|
||||
celery==5.4.0
|
||||
certifi==2024.2.2
|
||||
cffi==1.16.0
|
||||
charset-normalizer==3.3.2
|
||||
click==8.1.7
|
||||
click-didyoumean==0.3.1
|
||||
click-plugins==1.1.1
|
||||
click-repl==0.3.0
|
||||
cloudpickle==3.0.0
|
||||
comm==0.2.2
|
||||
contexttimer==0.3.3
|
||||
contourpy==1.2.1
|
||||
cycler==0.12.1
|
||||
dash==2.16.1
|
||||
dash-core-components==2.0.0
|
||||
dash-html-components==2.0.0
|
||||
dash-table==5.0.0
|
||||
dask==2024.6.2
|
||||
dask-expr==1.1.6
|
||||
debugpy==1.8.1
|
||||
decorator==5.1.1
|
||||
defusedxml==0.7.1
|
||||
distributed==2024.6.2
|
||||
duckdb==1.0.0
|
||||
et-xmlfile==1.1.0
|
||||
executing==2.0.1
|
||||
fastjsonschema==2.19.1
|
||||
Flask==3.0.3
|
||||
fonttools==4.51.0
|
||||
fqdn==1.5.1
|
||||
fsspec==2024.6.1
|
||||
greenlet==3.0.3
|
||||
h11==0.14.0
|
||||
httpcore==1.0.5
|
||||
httpx==0.27.0
|
||||
idna==3.7
|
||||
importlib_metadata==7.1.0
|
||||
ipykernel==6.29.4
|
||||
ipython==8.24.0
|
||||
ipywidgets==8.1.2
|
||||
isoduration==20.11.0
|
||||
itsdangerous==2.2.0
|
||||
jedi==0.19.1
|
||||
Jinja2==3.1.3
|
||||
json5==0.9.25
|
||||
jsonpointer==2.4
|
||||
jsonschema==4.22.0
|
||||
jsonschema-specifications==2023.12.1
|
||||
jupyter==1.0.0
|
||||
jupyter-console==6.6.3
|
||||
jupyter-events==0.10.0
|
||||
jupyter-lsp==2.2.5
|
||||
jupyter_client==8.6.1
|
||||
jupyter_core==5.7.2
|
||||
jupyter_server==2.14.0
|
||||
jupyter_server_terminals==0.5.3
|
||||
jupyterlab==4.1.8
|
||||
jupyterlab_pygments==0.3.0
|
||||
jupyterlab_server==2.27.1
|
||||
jupyterlab_widgets==3.0.10
|
||||
kiwisolver==1.4.5
|
||||
kombu==5.3.7
|
||||
locket==1.0.0
|
||||
MarkupSafe==2.1.5
|
||||
matplotlib==3.8.4
|
||||
matplotlib-inline==0.1.7
|
||||
mistune==3.0.2
|
||||
msgpack==1.0.8
|
||||
nbclient==0.10.0
|
||||
nbconvert==7.16.4
|
||||
nbformat==5.10.4
|
||||
nest-asyncio==1.6.0
|
||||
notebook==7.1.3
|
||||
notebook_shim==0.2.4
|
||||
numpy==1.26.4
|
||||
openpyxl==3.1.2
|
||||
overrides==7.7.0
|
||||
packaging==24.0
|
||||
pandas==2.2.2
|
||||
pandas-stubs==2.2.2.240603
|
||||
pandocfilters==1.5.1
|
||||
parso==0.8.4
|
||||
partd==1.4.2
|
||||
pexpect==4.9.0
|
||||
pillow==10.3.0
|
||||
platformdirs==4.2.1
|
||||
plotly==5.21.0
|
||||
polars==0.20.31
|
||||
prometheus_client==0.20.0
|
||||
prompt-toolkit==3.0.43
|
||||
psutil==5.9.8
|
||||
psycopg==3.2.1
|
||||
ptyprocess==0.7.0
|
||||
pure-eval==0.2.2
|
||||
pyarrow==16.1.0
|
||||
pycparser==2.22
|
||||
Pygments==2.17.2
|
||||
pylibmc==1.6.3
|
||||
pyparsing==3.1.2
|
||||
PySide6==6.7.0
|
||||
PySide6_Addons==6.7.0
|
||||
PySide6_Essentials==6.7.0
|
||||
python-dateutil==2.9.0.post0
|
||||
python-json-logger==2.0.7
|
||||
pytz==2024.1
|
||||
PyYAML==6.0.1
|
||||
pyzmq==26.0.2
|
||||
qtconsole==5.5.1
|
||||
QtPy==2.4.1
|
||||
redis==5.0.4
|
||||
referencing==0.35.0
|
||||
requests==2.31.0
|
||||
retrying==1.3.4
|
||||
rfc3339-validator==0.1.4
|
||||
rfc3986-validator==0.1.1
|
||||
rpds-py==0.18.0
|
||||
Send2Trash==1.8.3
|
||||
setuptools==69.5.1
|
||||
shiboken6==6.7.0
|
||||
six==1.16.0
|
||||
sniffio==1.3.1
|
||||
sortedcontainers==2.4.0
|
||||
soupsieve==2.5
|
||||
SQLAlchemy==2.0.31
|
||||
stack-data==0.6.3
|
||||
tblib==3.0.0
|
||||
tenacity==8.2.3
|
||||
terminado==0.18.1
|
||||
tinycss2==1.3.0
|
||||
toolz==0.12.1
|
||||
tornado==6.4
|
||||
traitlets==5.14.3
|
||||
types-python-dateutil==2.9.0.20240316
|
||||
types-pytz==2024.1.0.20240417
|
||||
typing_extensions==4.11.0
|
||||
tzdata==2024.1
|
||||
Unidecode==1.3.8
|
||||
uri-template==1.3.0
|
||||
urllib3==2.2.1
|
||||
vine==5.1.0
|
||||
wcwidth==0.2.13
|
||||
webcolors==1.13
|
||||
webencodings==0.5.1
|
||||
websocket-client==1.8.0
|
||||
Werkzeug==3.0.2
|
||||
widgetsnbextension==4.0.10
|
||||
XlsxWriter==3.2.0
|
||||
zict==3.0.0
|
||||
zipp==3.18.1
|
||||
BIN
workshop/pandas-shoes.zip
Normal file
BIN
workshop/pandas-shoes.zip
Normal file
Binary file not shown.
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# Exercice de traitement de données avec Pandas\n",
|
||||
"# Atelier de traitement de données avec Pandas\n",
|
||||
"\n",
|
||||
"Tiré du site de Guillaume Dueymes : https://www.guillaumedueymes.com/courses/formation_python/8-pandas-exercice/\n",
|
||||
"\n",
|
||||
@@ -23,9 +23,18 @@
|
||||
"## Découverte du data set\n",
|
||||
"\n",
|
||||
"1. À l’aide de la fonction `read_csv()`, importez entièrement le data set et enregistrez-le dans une variable `shoes`.\n",
|
||||
"2. Utilisez la méthode `.head()` pour afficher les premières lignes du `DataFrame`.\n",
|
||||
"3. Il y a plus de 4 colonnes, beaucoup ne sont pas visibles. Afin de toutes les voir lors de l'affichage, utilisez la fonction `pandas.set_option()` pour que `.head()` affiche toutes les colonnes du `DataFrame`. (consultez la documentation de `set_option()`)\n",
|
||||
"4. On va garder uniquement les colonnes intéressantes. Grâce à la syntaxe de filtrage par colonnes, créez une variable `shoes_light`, comprenant uniquement les colonnes suivantes : `id`, `name`, `brand`, dateUpdated`, `colors`, `prices.amountMax`, `prices.amountMin` et `prices.merchant`. Affichez le `head()` de `shoes_light`.\n"
|
||||
"2. Utilisez la méthode `.head(n=10)` pour récupérer et afficher les premières lignes du `DataFrame`.\n",
|
||||
"3. Il y a beaucoup de colonnes, beaucoup ne sont pas visibles. Afin de toutes les voir lors de l'affichage, utilisez l'attribut' `pandas.options` pour que `.head()` affiche toutes les colonnes du `DataFrame`. (ou utilisez la fonction `display()` de Jupyter)\n",
|
||||
"4. On va garder uniquement les colonnes intéressantes. Grâce à la syntaxe de filtrage par colonnes, créez une variable `shoes_light`, comprenant uniquement les colonnes suivantes :\n",
|
||||
" - `id`\n",
|
||||
" - `name`\n",
|
||||
" - `brand`\n",
|
||||
" - `dateUpdated`\n",
|
||||
" - `colors`\n",
|
||||
" - `prices.amountMax`\n",
|
||||
" - `prices.amountMin`\n",
|
||||
" - `prices.merchant`.\n",
|
||||
"4. Suite : Affichez le `head()` de `shoes_light`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
@@ -34,36 +43,19 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Requirement already satisfied: pandas in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (2.1.1)\r\n",
|
||||
"Requirement already satisfied: numpy>=1.23.2 in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (from pandas) (1.26.0)\r\n",
|
||||
"Requirement already satisfied: python-dateutil>=2.8.2 in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (from pandas) (2.8.2)\r\n",
|
||||
"Requirement already satisfied: pytz>=2020.1 in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (from pandas) (2023.3.post1)\r\n",
|
||||
"Requirement already satisfied: tzdata>=2022.1 in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (from pandas) (2023.3)\r\n",
|
||||
"Requirement already satisfied: six>=1.5 in /home/steve/Code/python/.venv/datascience/lib/python3.11/site-packages (from python-dateutil>=2.8.2->pandas) (1.16.0)\r\n",
|
||||
"\r\n",
|
||||
"\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.3.1\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m23.3.2\u001B[0m\r\n",
|
||||
"\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"!pip install pandas\n",
|
||||
"#!pip install pandas\n",
|
||||
"import pandas as pd # noqa"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false,
|
||||
"ExecuteTime": {
|
||||
"end_time": "2023-12-19T09:59:24.292192547Z",
|
||||
"start_time": "2023-12-19T09:59:21.699160182Z"
|
||||
"jupyter": {
|
||||
"is_executing": true
|
||||
}
|
||||
},
|
||||
"id": "fb6b33145b46036b"
|
||||
"id": "fb6b33145b46036b",
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -119,10 +111,10 @@
|
||||
"source": [
|
||||
"## Data Cleaning\n",
|
||||
"\n",
|
||||
"1. À l'aide de l'attribut `.dtypes` du dataframe, regardez attentivement les types de chaque colonne. Certaines ont un type qui n'est pas celui attendu. Lesquelles ?\n",
|
||||
"2. À l'aide des méthodes `.isnull()` (ou `.isna()`), `.sum()` et `len()`, calculez pour chaque colonne le pourcentage de valeurs non renseignées. Notez quelque part celles qui ont un non remplissage supérieur à 10%. La méthode `sum()` employée sur une série de booléens fait l'addition en considérant que `False == 0` et `True == 1`.\n",
|
||||
"3. Supprimez du dataframe `shoes_light` les colonnes que vous avez notées dans la question précédente, elles ont trop de valeurs non renseignées.\n",
|
||||
"4. À l'aide de la méthode `.to_datetime()` du dataframe, convertissez le type de la colonne `dateUpdated`.\n"
|
||||
"1. À l'aide de l'attribut `.dtypes` du Dataframe, observez attentivement les types de chaque colonne. Certaines ont un type qui ne correspond pas à celui attendu. Lesquelles ? Notez-les simplement quelque part.\n",
|
||||
"2. À l'aide des méthodes `.isnull()` (ou `.isna()`), `.sum()` et `len()`, calculez pour chaque colonne le **pourcentage** de valeurs non renseignées. Récupérez dans une variable celles qui ont un non remplissage supérieur à 10%. La méthode `sum()` employée sur une série de booléens fait l'addition en considérant que `False == 0` et `True == 1`. La méthode `mean()` fonctionne aussi et renverra un ratio des valeurs `True` sur le nombre total de valeurs.\n",
|
||||
"3. Supprimez du dataframe `shoes_light` les colonnes que vous avez récupérées dans la question précédente, elles ont trop de valeurs non renseignées.\n",
|
||||
"4. À l'aide de la fonction `pd.to_datetime()`, remplacez la colonne `dateUpdated` par une colonne de type `datetime64[ns]`.\n"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
@@ -183,7 +175,8 @@
|
||||
"## Features Modeling\n",
|
||||
"\n",
|
||||
"1. Ajoutez au dataframe une nouvelle colonne `prices.amountAverage` calculant la moyenne des colonnes `prices.amountMax` et `prices.amountMin` (via une addition et une division par 2).\n",
|
||||
"2. Grâce à l'attribut `Series.dt.weekday`, ajoutez au dataframe une nouvelle colonne `dayOfweekUpdated`, extrayant depuis la colonne `dateUpdated` le jour de la semaine où les produits sont mis à jour (un nombre entre 0 et 6).\n"
|
||||
"2. Grâce à l'attribut `Series.dt.weekday`, ajoutez au dataframe une nouvelle colonne `dayOfweekUpdated`, extrayant depuis la colonne `dateUpdated` le jour de la semaine où les produits sont mis à jour (un nombre entre 0 et 6).\n",
|
||||
"3. Grâce à l'attribut `Series.dt.day_name(locale=\"\")`, ajoutez au dataframe une nouvelle colonne `dayNameUpdated`, extrayant depuis la colonne `dateUpdated` le nom du jour de la semaine où les produits sont mis à jour (Lundi à Dimanche).\n"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
@@ -192,15 +185,18 @@
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"# Question 1"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
"collapsed": false,
|
||||
"jupyter": {
|
||||
"is_executing": true
|
||||
}
|
||||
},
|
||||
"id": "c1c2d9b73cf09b13"
|
||||
"id": "c1c2d9b73cf09b13",
|
||||
"outputs": [],
|
||||
"execution_count": null
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
@@ -214,15 +210,23 @@
|
||||
},
|
||||
"id": "f79a989bd03e4f61"
|
||||
},
|
||||
{
|
||||
"metadata": {},
|
||||
"cell_type": "code",
|
||||
"outputs": [],
|
||||
"execution_count": null,
|
||||
"source": "# Question 3",
|
||||
"id": "bd08c4a6a8e5d18f"
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"## Data Analyse\n",
|
||||
"\n",
|
||||
"1. Affichez le prix moyen, écart type, etc. des chaussures avec la méthode `.describe()`.\n",
|
||||
"2. Y a-t-il de grandes différences de prix en fonction de la marque ? À l'aide des méthodes `groupby()`, `mean()` et `sort_values()`, créez une variable `luxury` contenant les 10 marques les plus chères, puis une variable `low_cost` contenant les 10 marques les moins chères.\n",
|
||||
"3. Grâce à la méthode `value_counts()`, déterminez le jour de la semaine où les produits sont le plus souvent mis à jour.\n",
|
||||
"4. **(Optionnel)** Donnez le prix moyen des produits de la marque `easy street` mis à jour un jeudi (jour 3).\n"
|
||||
"1. Affichez le prix moyen, écart type, etc. des chaussures avec la méthode `.describe()` du `DataFrame` `shoes_light`.\n",
|
||||
"2. Y a-t-il de grandes différences de prix en fonction de la marque ? À l'aide des méthodes `groupby()`, `mean()` et `sort_values()`, créez une variable `luxury` contenant les 10 marques dont les prix moyens des produits sont les plus élevés, puis une variable `low_cost` contenant les 10 marques les moins chères sur les mêmes critères.\n",
|
||||
"3. Grâce à la méthode `.value_counts()` du Dataframe, déterminez le jour de la semaine où les produits sont le plus souvent mis à jour.\n",
|
||||
"4. Donnez le prix moyen des produits de la marque `easy street` mis à jour un jeudi (jour 3).\n"
|
||||
],
|
||||
"metadata": {
|
||||
"collapsed": false
|
||||
|
||||
Reference in New Issue
Block a user