2025.46 changes
This commit is contained in:
@@ -438,10 +438,11 @@ print(selection1, selection2, sep="\n")
|
||||
### Bon à savoir : vues et copies
|
||||
|
||||
Lorsque vous extrayez une partie d'un `DataFrame`{.python}, vous obtenez généralement un objet de type `DataFrame`{.python}.
|
||||
Cependant, il faut savoir que par défaut, le nouveau `DataFrame`{.python} est une **vue** sur le `DataFrame`{.python} initial.
|
||||
Cela veut dire que si vous modifiez le contenu du `DataFrame`{.python} initial, le contenu du `DataFrame`{.python} extrait sera aussi modifié, et vice versa.
|
||||
Cependant, il faut savoir que dans Pandas 2.0+, le nouveau `DataFrame`{.python} est une **copie** des données du `DataFrame`{.python} initial.
|
||||
Cela veut dire que modifier le contenu d'un des deux `DataFrame`{.python} n'a pas d'effet sur l'autre.
|
||||
|
||||
Pour obtenir une copie des données du `DataFrame`{.python} extrait, il faut utiliser la méthode `.copy()`{.python}.
|
||||
Pour obtenir une vue des données du `DataFrame`{.python} extrait et appliquer des modifications partagées, il faut
|
||||
extraire en utilisant par exemple `.loc[(lignes, colonnes)]` (avec un `tuple`{.python}).
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
@@ -552,8 +553,13 @@ is_high = data > 3 # F, F, F, T, T, T
|
||||
high_data = data.loc[is_high & is_even] # 4, 6
|
||||
```
|
||||
|
||||
On peut utiliser les opérateurs binaires `&`{.python} (`and`) et `|`{.python} (`or`) pour combiner les séries de booléens.
|
||||
Le résultat est une série de booléens de la même longueur.
|
||||
Pour des questions d'ordre d'évaluation des opérateurs, vous devrez quasi systématiquement utiliser des parenthèses pour discriminer vos conditions.
|
||||
Les opérateurs à utiliser pour assembler vos propositions sont les opérateurs logiques binaires :
|
||||
|
||||
- `&`{.python} : ET binaire
|
||||
- `|`{.python} : OU binaire
|
||||
- `~`{.python} : NON binaire
|
||||
- `^`{.python} : OU exclusif binaire
|
||||
|
||||
----
|
||||
|
||||
@@ -712,6 +718,24 @@ L'attribut est documenté ici :
|
||||
[37]: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dt.day_name.html
|
||||
[38]: https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.Series.dt.isocalendar.html
|
||||
|
||||
----
|
||||
|
||||
#### Exemple d'extraction de la semaine ISO
|
||||
|
||||
Dans le standard ISO, le numéro de semaine est déterminé comme suit :
|
||||
|
||||
La première semaine de l'année est celle dont la majorité de jours (au moins 4) est contenue
|
||||
dans l'année en cours.
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
|
||||
data = pd.DataFrame(data={
|
||||
"order": ["A15", "B84", "D25", "B43"],
|
||||
"date": pd.to_datetime(["2024-06-10", "2021-02-14", "2023-06-25", "2024-11-30"])
|
||||
})
|
||||
data["week"] = data["date"].dt.isocalendar()["week"]
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
@@ -870,6 +894,14 @@ Dans tous les cas sauf pour `df.at`{.python}, la clé peut être un des objets s
|
||||
- liste de clés de lignes/colonne ou numéro de ligne (`[a, b, c]`{.python});
|
||||
- tuple à deux éléments (`(ligne(s), colonne(s))`{.python}).
|
||||
|
||||
**Attention** : Passer un tuple contenant un slice ne fonctionne pas syntaxiquement parlant
|
||||
s'il est exprimé explicitement, ie. avec des parenthèses.
|
||||
|
||||
```python {.numberLines}
|
||||
df.loc[(0, 0:2)] # Ceci est une erreur de syntaxe
|
||||
df.loc[0, 0:2] # Ceci est du Python valide
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
## Valeurs vides
|
||||
@@ -1020,6 +1052,9 @@ df3 = df.fillna({"siret": "N/A", "siege": "Inconnu"})
|
||||
df4 = df.ffill() # forward fill
|
||||
# Remplir les colonnes avec la prochaine valeur non vide trouvée
|
||||
df5 = df.bfill() # backward fill
|
||||
# Remplir les valeurs NaN en interpolant
|
||||
# https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.interpolate.html
|
||||
df6 = df.interpolate(method="cubic")
|
||||
```
|
||||
|
||||
----
|
||||
@@ -1157,6 +1192,8 @@ df = pd.DataFrame(data={
|
||||
df.drop(labels=["prenom"], axis="columns", inplace=True)
|
||||
# Retirer les lignes aux index 0 et 2, mais retourner un nouveau DataFrame
|
||||
df2 = df.drop(labels=[0, 2], axis="index")
|
||||
# Variante : Retirer les lignes aux index 0 et 2
|
||||
df3 = df.drop(index=[0, 2])
|
||||
```
|
||||
|
||||
----
|
||||
@@ -1200,7 +1237,7 @@ df = pd.DataFrame(data={
|
||||
"numero": [8, 31, 23, 14]
|
||||
})
|
||||
|
||||
# Appliquer une fonction sur chaque colonne
|
||||
# Appliquer une fonction sur chaque ligne
|
||||
df2 = df.apply(lambda s: s * 2, axis="columns")
|
||||
```
|
||||
|
||||
@@ -1434,7 +1471,7 @@ et organiser les éléments dans chaque groupe.
|
||||
|
||||
----
|
||||
|
||||
## Astuces inoubliables
|
||||
## Extra :En vrac
|
||||
|
||||
À 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.
|
||||
@@ -1446,7 +1483,14 @@ comportements sont difficiles à comprendre, ou certains usages nécessitent que
|
||||
|
||||
### 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.
|
||||
Lorsqu'un utilisateur utilise Pandas dans l'objectif de modifier un `DataFrame`{.python}
|
||||
extrait d'un `DataFrame`{.python} plus large (après filtrage de lignes par exemple), il
|
||||
sera généralement exposé à un message d'avertissement tel que le suivant :
|
||||
|
||||
```text {.numberLines}
|
||||
SettingWithCopyWarning: A value is trying to be set on a copy of a slice from a DataFrame.
|
||||
Try using .loc[row_index,col_indexer] = value instead
|
||||
```
|
||||
|
||||
Le message peut être désactivé via les paramètres de Pandas, ou encore en récupérant explicitement
|
||||
un `DataFrame`{.python} via la méthode `copy()`{.python}.
|
||||
|
||||
@@ -18,7 +18,7 @@ propre à la publication.
|
||||
|
||||
## Comment fonctionne Plotly ?
|
||||
|
||||
Plotly est une bibliothèque Python compatible avec les `DataFrame`{.python} Pandas, qui permet de créer des graphiques
|
||||
Plotly est une bibliothèque Python qui permet de créer des graphiques
|
||||
interactifs, et cela grâce aux technologies web (HTML, CSS et JS). Un navigateur suffit à
|
||||
afficher le contenu d'un graphique généré avec Plotly.
|
||||
|
||||
@@ -55,10 +55,10 @@ Nous allons passer en revue quelques graphiques réalisables avec Express.
|
||||
|
||||
----
|
||||
|
||||
#### `plotly.express.bar`
|
||||
#### `plotly.express.bar` (`DataFrame`)
|
||||
|
||||
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)
|
||||
Générer un graphique en barres est assez simple avec Plotly Express, et fonctionne
|
||||
de manière relativement satisfaisante par défaut (ex. gestion du contraste et angle des étiquettes)
|
||||
|
||||
```python {.numberLines}
|
||||
import pandas as pd
|
||||
@@ -799,6 +799,10 @@ figure.update_layout(
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
La méthode `add_hrect()`{.python} dessine un rectangle prenant l'intégralité de la largeur du
|
||||
graphique. Il ne reste qu'à définir les coordonnées `y0` et `y1` du rectangle,
|
||||
coordonnées qui dépendent d'une référence (taille du graphique, pixels ou axe Y)
|
||||
|
||||
----
|
||||
|
||||

|
||||
@@ -835,18 +839,29 @@ 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)})
|
||||
# Créer une courbe aléatoire lissée de valeurs entre 1 et 80
|
||||
SIZE: int = 500
|
||||
np.random.seed(4) # Pour reproduire les résultats
|
||||
df = pd.DataFrame(data={"col1": gaussian_filter(np.random.random(size=SIZE) * 79.0 + 1.0, sigma=SIZE / 133)})
|
||||
# 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
|
||||
|
||||
df["reg1"] = c2 * df.index**2 + c1 * df.index + 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 = Figure(
|
||||
data=[
|
||||
Scatter(name="values", x=df.index, y=df["col1"], line={"color": "gray", "width": 1}, mode="lines"),
|
||||
Scatter(
|
||||
name="regression", x=df.index, y=df["reg1"], line={"color": "red", "width": 4, "dash": "dot"}, mode="lines"
|
||||
),
|
||||
],
|
||||
layout={
|
||||
"template": "seaborn",
|
||||
"xaxis1": {"title": "time"},
|
||||
"title": "Test de régression",
|
||||
"font": {"family": "Cabin", "size": 13},
|
||||
"yaxis1": {"title": "value"},
|
||||
},
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
```
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 250 KiB After Width: | Height: | Size: 189 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 88 KiB |
@@ -15,6 +15,11 @@ jupyter = "^1.0.0"
|
||||
xlsxwriter = "^3.1.1"
|
||||
plotly = "^5.15.0"
|
||||
|
||||
[tool.black]
|
||||
line-length = 120
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 120
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
|
||||
30
source/plotting/charts/plotly_regression_curve.py
Normal file
30
source/plotting/charts/plotly_regression_curve.py
Normal file
@@ -0,0 +1,30 @@
|
||||
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 de valeurs entre 1 et 80
|
||||
SIZE: int = 500
|
||||
np.random.seed(4) # Pour reproduire les résultats
|
||||
df = pd.DataFrame(data={"col1": gaussian_filter(np.random.random(size=SIZE) * 79.0 + 1.0, sigma=SIZE / 133)})
|
||||
# Calculer les coefficients d'une régression de degré 2 pour col1
|
||||
c2, c1, c0 = np.polyfit(df.index, df["col1"], 2)
|
||||
df["reg1"] = c2 * df.index**2 + c1 * df.index + c0
|
||||
|
||||
# Créer une image avec deux lignes
|
||||
figure = Figure(
|
||||
data=[
|
||||
Scatter(name="values", x=df.index, y=df["col1"], line={"color": "gray", "width": 1}, mode="lines"),
|
||||
Scatter(
|
||||
name="regression", x=df.index, y=df["reg1"], line={"color": "red", "width": 4, "dash": "dot"}, mode="lines"
|
||||
),
|
||||
],
|
||||
layout={
|
||||
"template": "seaborn",
|
||||
"xaxis1": {"title": "time"},
|
||||
"title": "Test de régression",
|
||||
"font": {"family": "Cabin", "size": 13},
|
||||
"yaxis1": {"title": "value"},
|
||||
},
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
@@ -6,14 +6,12 @@ from plotly.graph_objs import Figure, Bar
|
||||
data = pd.DataFrame(data={
|
||||
"product": ["tarte", "gâteau", "biscuit", "mille-feuille", "éclair", "brownie"],
|
||||
"price": [2.99, 3.49, 1.99, 4.99, 5.99, 6.99],
|
||||
"weight": [250, 300, 200, 400, 500, 600]
|
||||
"weight": [400, 500, 100, 250, 150, 350]
|
||||
})
|
||||
figure: Figure = make_subplots(rows=1, cols=3, subplot_titles=("Prix", "Poids unitaires"))
|
||||
subplot = figure.get_subplot(row=1, col=2)
|
||||
subplot.xaxis["domain"] = [0.3555555, 1.0]
|
||||
print(subplot, dir(subplot))
|
||||
figure: Figure = make_subplots(rows=1, cols=2, subplot_titles=("Prix", "Poids unitaires"))
|
||||
# subplot = figure.get_subplot(row=1, col=2)
|
||||
# subplot.xaxis["domain"] = [0.3555555, 1.0]
|
||||
figure.add_trace(Bar(name="Prix", x=data["product"], y=data["price"]), row=1, col=1)
|
||||
figure.add_trace(Bar(name="Poids", x=data["product"], y=data["weight"]), row=1, col=2)
|
||||
figure.update_layout(template="seaborn", title="Prix et poids unitaires", font={"family": "Cabin", "size": 13})
|
||||
figure.update_traces(row=1, col=2, specs=2)
|
||||
figure.show(renderer="browser")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import pandas as pd
|
||||
from plotly.graph_objs import Figure, Bar, Scatter
|
||||
from plotly.graph_objs import Figure, Bar
|
||||
|
||||
data = pd.DataFrame(
|
||||
data={
|
||||
@@ -8,13 +8,21 @@ data = pd.DataFrame(
|
||||
"weight": [250, 300, 200, 400, 500, 600],
|
||||
}
|
||||
)
|
||||
figure: Figure = Figure(data=[Bar(name="Prix", x=data["product"], y=data["price"])])
|
||||
figure.add_hrect(y0=2.75, y1=4.5, fillcolor="gray", opacity=0.25, layer="below")
|
||||
figure: Figure = Figure(data=[])
|
||||
figure.add_hrect(
|
||||
y0=2.75,
|
||||
y1=4.5,
|
||||
fillcolor="gray",
|
||||
opacity=0.25,
|
||||
layer="below",
|
||||
)
|
||||
figure.add_trace(Bar(name="Prix", x=data["product"], y=data["price"]))
|
||||
figure.add_annotation(text="Zone de prix spéciale", xref="paper", yref="paper", x=0.5, y=0.5, xanchor="center", yanchor="middle", showarrow=False, font={"family": "Cabin", "size": 20})
|
||||
figure.update_layout(
|
||||
template="seaborn",
|
||||
title="Prix et poids unitaires",
|
||||
font={"family": "Cabin", "size": 13},
|
||||
xaxis={"title": "Produit", "showgrid": False},
|
||||
yaxis={"title": "Prix (€)", "showgrid": False}
|
||||
yaxis={"title": "Prix (€)", "showgrid": False},
|
||||
)
|
||||
figure.show(renderer="browser")
|
||||
|
||||
Reference in New Issue
Block a user