Auditoria Automàtica de Licitacions de TMB i FGC amb Python: Transparència i Control Públic

Objectiu: Aquest script en Python ha estat dissenyat per ajudar a la Sindicatura de Comptes, l'OLAF o qualsevol entitat de control a auditar automàticament les licitacions i adjudicacions de contractes públics per part de Transports Metropolitans de Barcelona (TMB) i Ferrocarrils de la Generalitat de Catalunya (FGC).

L'script analitza conjunts de dades de contractació pública per detectar patrons sospitosos, com adjudicacions recurrents al mateix proveïdor, imports fraccionats, terminis atípics o processos amb baixa concurrència.

El model pot integrar-se fàcilment amb fonts com Plataforma de Contractació Pública de Catalunya, Gencat Open Data, o portals europeus mitjançant connectors GTFS o APIs obertes. A més, ofereix un informe visual interactiu per identificar riscos, generar alertes i facilitar la presa de decisions per part dels auditors.

Funcionalitats clau:

  • Importació i neteja de dades obertes de contractes.
  • Anàlisi de concentració d’adjudicacions per empresa.
  • Detecció de fraccionament de contractes.
  • Control d’imports, terminis i concurrència.
  • Visualització gràfica amb mapes i taules interactives.
  • Generació automàtica d'informes d'auditoria (PDF/HTML).

Aquest projecte és part d'una iniciativa per fomentar la transparència, la rendició de comptes i la justícia econòmica en la gestió dels recursos públics de mobilitat a Catalunya.

# Script base per a l'auditoria automatitzada de licitacions públiques de TMB i FGC import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns # 1. Importació de dades (des de CSV o API pública) df = pd.read_csv("contractes_tmb_fgc.csv") # Simulació de fitxer real # 2. Neteja i transformació df['Data_adjudicació'] = pd.to_datetime(df['Data_adjudicació']) df['Any'] = df['Data_adjudicació'].dt.year # 3. Anàlisi de concentració top_proveïdors = df['Empresa_adjudicatària'].value_counts().head(10) # 4. Fraccionament: mateix objecte contractat a intervals breus df['clau_contracte'] = df['Objecte_contracte'] + df['Import'].astype(str) fraccionats = df[df.duplicated(['clau_contracte'], keep=False)] # 5. Gràfiques de visualització plt.figure(figsize=(10,5)) sns.countplot(y='Empresa_adjudicatària', data=df, order=top_proveïdors.index) plt.title("Top 10 empreses adjudicatàries") plt.tight_layout() plt.savefig("empreses_top.png") # 6. Exportació d'informe df.to_html("informe_contractes.html") # Opcional: Enviament d’alertes si es detecten anomalies sospitosos = df[df['Import'] > 5000000] # Exemple: imports elevats sense concurrència if not sospitosos.empty: print("Alerta: hi ha contractes potencialment sospitosos.") # auditoria_contractes_tmb_fgc.py import pandas as pd import numpy as np import plotly.express as px from datetime import datetime import os # 1. Carrega de dades des d’un CSV amb dades públiques de contractes df = pd.read_csv("contractes_tmb_fgc.csv") # 2. Neteja bàsica df['Data_adjudicació'] = pd.to_datetime(df['Data_adjudicació'], errors='coerce') df['Import'] = pd.to_numeric(df['Import'], errors='coerce') df.dropna(subset=['Data_adjudicació', 'Import', 'Empresa_adjudicatària'], inplace=True) # 3. Columnes derivades df['Any'] = df['Data_adjudicació'].dt.year df['clau_contracte'] = df['Objecte_contracte'].astype(str) + "_" + df['Import'].astype(str) # 4. Anàlisi de concentració d’adjudicacions ranking_empreses = df['Empresa_adjudicatària'].value_counts().reset_index() ranking_empreses.columns = ['Empresa', 'Nombre_contractes'] # 5. Detecció de fraccionaments sospitosos df['Duplicat'] = df.duplicated(subset=['clau_contracte'], keep=False) fraccionaments = df[df['Duplicat']] # 6. Contractes sense concurrència o d’import elevat anomalies = df[(df['Nombre_ofertes'] <= 1) | (df['Import'] > 1000000)] # 7. Gràfics interactius fig1 = px.bar(ranking_empreses.head(10), x='Nombre_contractes', y='Empresa', title='Top 10 Empreses Adjudicatàries', orientation='h') fig2 = px.histogram(df, x='Any', nbins=10, title='Distribució de Contractes per Any') fig3 = px.scatter(anomalies, x='Data_adjudicació', y='Import', color='Empresa_adjudicatària', hover_data=['Objecte_contracte'], title='Contractes amb anomalies') # 8. Exportació HTML complet html_output = f""" Informe d'Auditoria - Contractes TMB i FGC

Informe d'Auditoria Automàtica

Data generació: {datetime.now().strftime("%d/%m/%Y %H:%M:%S")}

Top 10 Empreses Adjudicatàries

{fig1.to_html(include_plotlyjs='cdn')}

Distribució de Contractes per Any

{fig2.to_html(include_plotlyjs=False)}

Contractes amb Anomalies

{fig3.to_html(include_plotlyjs=False)}

Fraccionament Detectat

{fraccionaments[['Data_adjudicació','Objecte_contracte','Import','Empresa_adjudicatària']].to_html(index=False)} """ with open("informe_auditoria_tmb_fgc.html", "w", encoding="utf-8") as f: f.write(html_output) print("Informe HTML generat: informe_auditoria_tmb_fgc.html")

Comments

Popular posts from this blog

BIOMEDICAL ENGINEERING AND MAINTENANCE

European Intelligence: Theoretical Foundations and Strategic Challenges

EDA, CIRCULAR ECONOMY, STANDARDIZATION & DEFENSE CHALLENGES EN