Aller au contenu

Python

Initialiser jupyter via WSL

mkdir python_juin_2026
cd python_juin_2026
wget -qO- https://astral.sh/uv/install.sh | sh # installation de UV
uv init
uv add jupyter
uv run jupyter lab

Numpy

# np.random.seed + np.random.normal : données aléatoires reproductibles
np.random.seed(42) #  fixation du générateur de nombres aléatoires (pour reproductibilité)
bruit = np.random.normal(loc=0, scale=0.5, size=(3, 4)) # où loc est la moyenne et scale l'écart type
bruit

Masque booléen

Un masque booléen est un tableau de True/False obtenu en appliquant une condition sur un tableau. Il permet de sélectionner ou de modifier des éléments selon un critère, sans boucle.

masque_froid = carte_temp < 14.0
masque_froid

np.sum(masque_froid)   # True est traité comme 1

# Extraire uniquement les valeurs froides
carte_temp[masque_froid]

# Remplacer des valeurs : les cellules > 17degC sont marquées comme anomalie (np.nan)
carte_modif = carte_temp.copy()   # toujours travailler sur une copie
carte_modif[carte_temp > 17.0] = np.nan
carte_modif

Gestion des données manquantes

# Détecter les NaN
np.isnan(array)

# Calculs en ignorant les NaN
print("Moyenne (avec NaN ignorés) :", np.nanmean(mesures))
print("Max    (avec NaN ignorés) :", np.nanmax(mesures))
print("Somme  (avec NaN ignorés) :", np.nansum(mesures))

Reshape

# Convertir en matrice 3x4
mat = v.reshape(3, 4)

# flatten() : retourner à un vecteur (renvoie une copie)
mat.flatten()

# ravel() : idem mais renvoie une vue (plus efficace en mémoire)
mat.ravel()

# Ajouter une dimension (utile pour le broadcasting ou RasterIO)
# Une image raster à une bande a la forme (1, H, W)
mat_3d = mat[np.newaxis, :, :]    # shape (1, 3, 4)
print("Avant :", mat.shape)
print("Après :", mat_3d.shape)

Visualisation d'un tableau 2D

# La colormap 'terrain' est appropriée pour les élévations.
# D'autres options utiles : 'gray', 'viridis', 'RdYlGn'
fig, axes = plt.subplots(1, 3, figsize=(14, 4))

for ax, cmap in zip(axes, ['terrain', 'gray', 'viridis']):
    im = ax.imshow(altitude_synth, cmap=cmap)
    plt.colorbar(im, ax=ax, label='Altitude (m)')
    ax.set_title(f'cmap = {cmap!r}')

plt.tight_layout()
plt.show()

Récapitulatif des fonctions utiles

Fonction Rôle
np.array([...]) Créer un tableau à partir d’une liste
np.zeros(shape) Tableau de zéros
np.ones(shape) Tableau de uns
np.arange(start, stop, step) Suite de valeurs espacées d’un pas
np.linspace(start, stop, n) n valeurs régulièrement espacées
arr.shape Dimensions du tableau
arr.ndim Nombre de dimensions
arr.size Nombre total d’éléments
arr.dtype Type des données
arr.reshape(shape) Changer la forme (sans copier)
arr.flatten() Remettre à plat (copie)
arr.copy() Copie indépendante
np.sum / min / max / mean / std Statistiques globales
np.nanmean / nanmax / nansum Statistiques en ignorant les NaN
np.isnan(arr) Masque des NaN
arr[masque] Sélection par masque booléen
plt.imshow(arr, cmap=...) Visualiser un tableau 2D comme image

Pandas

DataFrame

df = pd.DataFrame({
    'nom'      : ['Tarbes', 'Lourdes', 'Bagnères', 'Arreau', 'Saint-Lary'],
    'altitude' : [320, 420, 550, 720, 830],
    'temp_moy' : [15.5, 14.8, 13.9, 11.2, 10.4],
    'pluvio'   : [850, 1050, 1200, 1400, 1600],
})

# Aperçu des premières lignes
df.head()

# Aperçu des dernières lignes
df.tail(3)

# Résumé : types, mémoire, valeurs non-nulles
df.info()

# Statistiques descriptives des colonnes numériques
df.describe()

# Noms des colonnes
df.columns

# Index des lignes (entiers par défaut)
df.index

# Nombre total d'éléments
df.size

# Dimensions : (nombre de lignes, nombre de colonnes)
df.shape

# Type de chaque colonne
df.dtypes

# Accéder à une colonne entière -> renvoie une Series
df.loc[:, 'altitude']

# Raccourci équivalent (notation crochets)
df['altitude']

# Accéder à plusieurs colonnes -> renvoie un DataFrame
df.loc[:, ['nom', 'altitude', 'temp_moy']]

# Raccourci équivalent
df[['nom', 'altitude', 'temp_moy']]

# Accéder à une ligne par son index entier (ici index 0 = Tarbes)
df.loc[0]

# Accéder à une cellule précise : ligne 1, colonne 'temp_moy'
df.loc[1, 'temp_moy']

Pont Numpy <=> Pandas

# .values renvoie un ndarray NumPy (c'est le pont NumPy <-> Pandas)
altitudes = df['altitude'].values
print(type(altitudes))
print(altitudes)

# On peut alors utiliser toutes les fonctions NumPy
print("Altitude moyenne :", np.mean(altitudes))
print("Altitude max     :", np.max(altitudes))
print("Écart-type       :", np.std(altitudes))

Sélection conditionnelle

Pandas permet de filtrer les lignes selon une condition, exactement comme les masques booléens NumPy.

# La condition produit une Series de booléens
df['altitude'] > 600

# Utiliser cette Series comme masque pour filtrer le DataFrame
df[df['altitude'] > 600]

# Combiner plusieurs conditions : & (ET), | (OU), ~ (NON)
# Attention : chaque condition doit être entre parenthèses
df[(df['altitude'] > 400) & (df['temp_moy'] < 14.0)]

df_filtered=df[(df['altitude']>400) & (df['altitude']<700)]

Nouvelle colonne

df['temp_fahrenheit'] = df['temp_moy'] * 9/5 + 32

# Catégorie d'altitude en 3 niveaux
df['categorie'] = np.where(
    df['altitude'] < 400, 'Plaine',
    np.where(df['altitude'] < 700, 'Colline', 'Montagne')
)
df[['nom', 'altitude', 'categorie']]

Appliquer une fonction à tous les éléments

# Appliquer une fonction personnalisée
def classer_temp(t):
    if t < 12:
        return 'froid'
    elif t < 15:
        return 'tempéré'
    else:
        return 'chaud'

df['climat'] = df['temp_moy'].apply(classer_temp)
df[['nom', 'temp_moy', 'climat']]

Supprimer une colonne

# Supprimer les colonnes de travail (inplace=True modifie directement le DataFrame)
df.drop(columns=['temp_fahrenheit', 
                 'nom_maj', 'climat'], inplace=True)
df

Gestion des valeurs manquantes

# Créer un DataFrame avec des NaN
df_incomplet = pd.DataFrame({
    'station'  : ['A', 'B', 'C', 'D', 'E'],
    'altitude' : [320, np.nan, 550, 720, np.nan],
    'temp_moy' : [15.5, 14.8, np.nan, 11.2, 10.4],
})
df_incomplet

# Détecter les NaN : True là où la valeur est manquante
df_incomplet.isnull()

# Compter les NaN par colonne
df_incomplet.isnull().sum()

# Supprimer les lignes contenant au moins un NaN
df_incomplet.dropna()

# Remplacer les NaN par une valeur fixe
df_incomplet.fillna(0)

Agréger avec groupby

# Nombre d'adresses par commune
adresses_par_commune = df_ban.groupby('commune_nom').size().reset_index(name='nb_adresses')
adresses_par_commune.sort_values('nb_adresses', ascending=False).head(10)

# Nombre de noms de voies distincts par commune
df_ban.groupby('commune_nom')['voie_nom'].nunique().sort_values(ascending=False).head(10)

# Plusieurs agrégations en une fois avec .agg()
df_ban.groupby('commune_nom').agg(
    nb_adresses=('uid_adresse', 'count'),
    nb_voies=('voie_nom', 'nunique'),
    lon_moy=('long', 'mean'),
    lat_moy=('lat', 'mean'),
).sort_values('nb_adresses', ascending=False).head(10)

Fonctions clés

Fonction / Méthode Rôle
pd.DataFrame({...}) Créer un DataFrame depuis un dictionnaire
pd.read_csv(path, sep=, dtype=) Lire un fichier CSV
df.to_csv(path, index=False) Écrire un fichier CSV
df.head(n) / df.tail(n) Aperçu des premières / dernières lignes
df.info() Types, mémoire, valeurs non-nulles
df.describe() Statistiques descriptives
df.shape / df.size Dimensions / nombre total d'éléments
df.dtypes Type de chaque colonne
df.columns / df.index Étiquettes de colonnes / lignes
df.loc[lignes, colonnes] Sélection par étiquette
df.iloc[lignes, colonnes] Sélection par position
df['col'].values Récupérer le ndarray sous-jacent
df[condition] Filtrage par masque booléen
df['col'].value_counts() Fréquences de chaque valeur
df['col'].nunique() Nombre de valeurs distinctes
df['col'].unique() Liste des valeurs distinctes
df.sort_values('col') Tri par colonne
df.groupby('col').agg(...) Agrégation par groupe
df.isnull() / .sum() Détecter / compter les NaN
df.dropna() Supprimer les lignes avec NaN
df.fillna(valeur) Remplacer les NaN
df.drop(columns=[...]) Supprimer des colonnes
df.rename(columns={...}) Renommer des colonnes
pd.melt(df, id_vars=, value_vars=) Transformer wide -> long
np.where(cond, vrai, faux) Créer une colonne catégorielle
df['col'].apply(fonction) Appliquer une fonction élément par élément

Exercice opérations spatiales

# À vous !
tarbes_buffer = tarbes_geom.buffer(10000)
mask = gdf_communes_l93.centroid.within(tarbes_buffer)
communes_buffer = gdf_communes_l93[mask].copy()
communes_buffer['distance_tarbes'] = communes_buffer.distance(tarbes_geom)
communes_buffer[['nom','distance_tarbes']].sort_values('distance_tarbes').head(25)