Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
179 changes: 128 additions & 51 deletions src/tasks/analyse.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import os
from datetime import datetime

import polars as pl

from config import DATE_NOW
import os
from tasks.setup import create_table_artifact

from datetime import datetime
# from config import DIST_DIR
from tasks.get import get_stats
from collections import Counter
import json
DATE_NOW = datetime.now().isoformat()[0:10] # YYYY-MM-DD
DIST_DIR = f"dist/" + DATE_NOW

def list_data_issues(df: pl.LazyFrame):
df = df.collect()
Expand Down Expand Up @@ -37,50 +39,125 @@ def list_data_issues(df: pl.LazyFrame):

def generate_stats(df: pl.DataFrame):
now = datetime.now()
df_uid: pl.DataFrame = df.select(
"uid", "acheteur_id", "datePublicationDonnees", "dateNotification", "montant"
).unique(subset=["uid"])

stats = {
"datetime": now.isoformat()[:-7], # jusqu'aux secondes
"date": DATE_NOW,
"fichiers": os.environ["downloaded_files"].split(","),
"nb_lignes": df.height,
"colonnes_triées": sorted(df.columns),
"nb_colonnes": len(df.columns),
"nb_marches": df_uid.height,
"nb_acheteurs_uniques": df_uid.select("acheteur_id").unique().height
- 1, # -1 pour ne pas compter la valeur "acheteur vide"
"nb_titulaires_uniques": df.select("titulaire_id", "titulaire_typeIdentifiant")
.unique()
.height
- 1, # -1 pour ne pas compter la valeur "titulaire vide"
}

for year in range(2018, int(DATE_NOW[0:4]) + 1):
stats[f"{str(year)}_nb_publications_marchés"] = df_uid.filter(
pl.col("datePublicationDonnees").dt.year() == year
).height

df_date_notification = df_uid.filter(
pl.col("dateNotification").dt.year() == year

df_titulaires = pl.DataFrame(columns=["titulaire_id", "titulaire_typeIdentifiant"])

for i in range(1, 4):
df_temp = df[[f"titulaire_id_{i}", f"titulaire_typeIdentifiant_{i}"]]
df_temp = df_temp.rename(
columns={
f"titulaire_id_{i}": "titulaire_id",
f"titulaire_typeIdentifiant_{i}": "titulaire_typeIdentifiant",
}
)
stats[f"{str(year)}_nb_notifications_marchés"] = df_date_notification.height

if df_date_notification.height > 0:
stats[f"{str(year)}_somme_montant_marchés_notifiés"] = (
df_date_notification.group_by("montant").sum()["montant"][0]
)
stats[f"{str(year)}_médiane_montant_marchés_notifiés"] = (
df_date_notification.group_by("montant").median()["montant"][0]
)
df_titulaires = pl.concat([df_titulaires, df_temp], ignore_index=True)

df.to_pickle("data/decp_before_stats.pkl")

stats = [
{
"datetime": now.isoformat()[:-7], # jusqu'aux secondes
"année": str(now.year),
"mois": str(now.month).zfill(2),
"dataset": "decp-augmente-minef",
"nb_lignes": df.index.size,
"nb_colonnes": len(df.columns),
"nb_marches": df[["id", "acheteur_id"]].drop_duplicates().index.size,
"nb_acheteurs_uniques": df[["acheteur_id"]].drop_duplicates().index.size
- 1, # -1 pour ne pas compter la valeur "acheteur vide"
"nb_titulaires_uniques": df_titulaires.drop_duplicates().index.size
- 1, # -1 pour ne pas compter la valeur "titulaire vide"
# "2024_nb_notifications": df.loc[
# df["dateNotification"].str.startswith("2024")
# ].index.size,
"2024_nb_publications": df.loc[
df["datePublicationDonnees"].dt.year == 2024
].index.size,
"2023_nb_notifications": df.loc[
df["dateNotification"].dt.year == 2023
].index.size,
"2023_nb_publications": df.loc[
df["datePublicationDonnees"].dt.year == 2023
].index.size,
"nb_marches_format_arrete_2022": df.loc[df["ccag"] != ""].index.size,
}
]

# df_per_source = (
# df[["id", "acheteur_id", "source"]].drop_duplicates().groupby(by="source").count()
# )

# for idx in df_per_source.index:
# if idx == "":
# source = "source-manquante"
# else:
# source = idx

# stats[source] = df_per_source.loc[idx, "id"]

df_stats_dgfr: pl.DataFrame = get_stats()
df_stats_dgfr = pl.concat([df_stats_dgfr, pl.DataFrame(stats)], ignore_index=True)
df_stats_dgfr.to_csv(f"{DIST_DIR}/statistiques.csv")





def count_and_print_modifications(json_path, i_modif=None, i_marche_modifie=None):
"""
si i_modif = i_marche_modifie = None, le code print le nombre de marchés modifiés (1 marché avec 17 modif, 4 avec 18 modifs, etc)
si i_modif = 13 et i_marche_modifie = None, le code print tout les marchés avec 13 modification et leur contenu.
si i_modif = 13 et i_marche_modifie = 3, le code print le contenu du 3ème marché avec 13 modifications uniquement.
"""
print(f"📥 Lecture du fichier JSON : {json_path}")
with open(json_path, "r", encoding="utf-8") as f:
data = json.load(f)

if isinstance(data, dict) and "marches" in data:
data = data["marches"]
elif not isinstance(data, list):
print("❌ Format inattendu.")
return

compteur = Counter()
total = 0
marches_to_print = []

for idx, marche in enumerate(data):
mods = marche.get("modifications", [])
if not isinstance(mods, list):
mods = []
nb_mods = len(mods)
compteur[nb_mods] += 1
total += 1

if i_modif is not None and nb_mods == i_modif:
marches_to_print.append((idx, marche))

print(f"\n📊 Stats sur les modifications ({total} marchés) :\n")
for nb_mods in sorted(compteur):
print(f"🔹 {nb_mods} modification(s) : {compteur[nb_mods]:,} marché(s)")

if i_modif is not None:
if not marches_to_print:
print(f"\n❌ Aucun marché avec {i_modif} modification(s) trouvé.")
else:
stats[f"{str(year)}_somme_montant_marchés_notifiés"] = ""
stats[f"{str(year)}_médiane_montant_marchés_notifiés"] = ""

# Stock les statistiques dans prefect
create_table_artifact(
table=[stats],
key="stats-marches-publics",
description=f"Statistiques sur les marchés publics agrégés ({DATE_NOW})",
)
print(f"\n📋 Marchés avec {i_modif} modification(s) :")
selected_marches = [marches_to_print[i_marche_modifie]] if i_marche_modifie is not None else marches_to_print
for idx, marche in selected_marches:
mods = marche.get("modifications", [])
print(f"\n✅ Marché à l'index {idx}")
print(f"🔑 ID : {marche.get('id', 'N/A')}")
print(f"📝 Objet : {marche.get('objet', 'N/A')}")
print(f"📅 Date de notification : {marche.get('dateNotification', 'N/A')}")
print(f"🛠️ Nombre de modifications : {len(mods)}\n")
for i, mod in enumerate(mods, 1):
print(f" ✏️ Modification {i}: {json.dumps(mod, indent=2, ensure_ascii=False)}")

return compteur


count_and_print_modifications("data/decp-2022.json",i_modif=11,i_marche_modifie=2)