SPB Git
57.9 KB · 713 lines latex
1% ==============================================================================2% SPID — SEC Project Intelligence Database : rapport technique UQO3% Compilation : latexmk -lualatex rapport_spid.tex4% Figures/tableaux : python3 make_figures.py (lit data/db/spid.duckdb)5% ==============================================================================6\documentclass[11pt,a4paper]{article}7\usepackage{fontspec}8\setmainfont{Libertinus Serif}[Numbers=OldStyle]9\setsansfont{Fira Sans}[Scale=MatchLowercase]10\setmonofont{Fira Mono}[Scale=MatchLowercase]11\usepackage[french]{babel}12\frenchsetup{StandardLists=true}13\usepackage[margin=2.3cm,top=2.6cm,bottom=2.6cm]{geometry}14\usepackage{parskip}15\usepackage{lastpage}16\usepackage{fancyhdr}17\usepackage{titlesec}18\usepackage{graphicx}19\graphicspath{{./}{figures/}}20\usepackage{tikz}21\usetikzlibrary{positioning,arrows.meta,shapes.geometric,calc,fit,backgrounds,shadows}22\usepackage[table]{xcolor}23\usepackage{booktabs}24\usepackage{array}25\usepackage{tabularx}26\usepackage{longtable}27\usepackage{multirow}28\usepackage{multicol}29\usepackage{enumitem}30\usepackage{amsmath,amssymb}31\usepackage{fontawesome5}32\usepackage{fvextra}33\usepackage{tcolorbox}34\tcbuselibrary{skins,breakable}35\usepackage{csquotes}36\usepackage{needspace}37\usepackage{caption}38\usepackage{float}39\usepackage{hyperref}4041% --- Couleurs UQO ---42\definecolor{uqoBleu}{RGB}{0, 62, 126}43\definecolor{uqoBleuClair}{RGB}{0, 102, 179}44\definecolor{uqoOr}{RGB}{198, 163, 0}45\definecolor{uqoGris}{RGB}{88, 89, 91}46\definecolor{uqoGrisClair}{RGB}{200, 200, 200}47\definecolor{uqoVert}{RGB}{0, 128, 70}48\definecolor{uqoRouge}{RGB}{180, 35, 24}49\definecolor{uqoBgClair}{RGB}{240, 244, 248}50\definecolor{uqoOrange}{RGB}{214, 122, 0}51\definecolor{uqoTeal}{RGB}{0, 121, 121}52\definecolor{fileBg}{RGB}{248, 249, 251}5354\hypersetup{colorlinks=true,linkcolor=uqoBleu,urlcolor=uqoBleuClair,citecolor=uqoVert,55  pdftitle={SPID — SEC Project Intelligence Database : provenance des données, pipeline et statistiques},56  pdfauthor={Manel Kammoun, Charli Tandja Mbianda, Simon-Pierre Boucher},57  pdfsubject={Base de données de projets stratégiques extraits des filings SEC},58  pdfkeywords={SEC, EDGAR, 10-K, 8-K, LLM, extraction d'information, DuckDB, graphe de connaissances, UQO}}5960% --- En-têtes ---61\setlength{\headheight}{22pt}62\addtolength{\topmargin}{-10pt}63\pagestyle{fancy}64\fancyhf{}65\renewcommand{\headrulewidth}{1.2pt}66\renewcommand{\headrule}{\hbox to\headwidth{\color{uqoBleu}\leaders\hrule height \headrulewidth\hfill}}67\renewcommand{\footrulewidth}{0.5pt}68\renewcommand{\footrule}{\hbox to\headwidth{\color{uqoGrisClair}\leaders\hrule height \footrulewidth\hfill}}69\fancyhead[L]{\small\sffamily\color{uqoBleu}\textbf{SPID} --- SEC Project Intelligence Database}70\fancyhead[R]{\small\sffamily\color{uqoGris}UQO --- Sciences administratives}71\fancyfoot[L]{\small\sffamily\color{uqoGris}Kammoun · Tandja Mbianda · Boucher}72\fancyfoot[R]{\small\sffamily\color{uqoGris}Page \thepage\ / \pageref{LastPage}}7374% --- Titres ---75\newcommand{\numbox}[1]{\tikz[baseline=(s.base)]\node[fill=uqoBleu,text=white,rounded corners=3pt,inner xsep=5pt,inner ysep=3pt,font=\Large\bfseries\sffamily](s){#1};}76\titleformat{\section}{\Large\bfseries\sffamily\color{uqoBleu}}{\numbox{\thesection}}{0.7em}{}77  [\vspace{-0.3em}{\color{uqoOr}\rule{\textwidth}{1.2pt}}]78\titleformat{\subsection}{\large\bfseries\sffamily\color{uqoBleuClair}}{\thesubsection}{0.5em}{}79\titleformat{\subsubsection}{\normalsize\bfseries\sffamily\color{uqoGris}}{\thesubsubsection}{0.5em}{}80\let\origsection\section81\renewcommand{\section}{\Needspace*{10\baselineskip}\origsection}82\titlespacing{\section}{0pt}{22pt}{8pt}83\titlespacing{\subsection}{0pt}{12pt}{4pt}84\titlespacing{\subsubsection}{0pt}{8pt}{3pt}85\captionsetup{font=small,labelfont={bf,color=uqoBleu},labelsep=period,width=0.92\textwidth}86\setlist{itemsep=2pt,topsep=3pt}8788% --- Boîtes ---89\tcbset{boxeCommune/.style={enhanced,breakable,boxrule=0.8pt,arc=3pt,90  left=6pt,right=6pt,top=4pt,bottom=4pt,before skip=8pt,after skip=8pt,fonttitle=\sffamily\bfseries}}91\newtcolorbox{infobox}[1][]{boxeCommune,colback=uqoBgClair,colframe=uqoBleu,title={#1},coltitle=white,colbacktitle=uqoBleu}92\newtcolorbox{alertbox}[1][]{boxeCommune,colback=uqoRouge!4,colframe=uqoRouge,title={#1},coltitle=white,colbacktitle=uqoRouge}93\newtcolorbox{notebox}[1][]{boxeCommune,colback=uqoOr!6,colframe=uqoOr,title={#1},coltitle=uqoBleu,colbacktitle=uqoOr}94\newtcolorbox{fichier}[1][]{enhanced,breakable,colback=fileBg,colframe=uqoGrisClair,boxrule=0.6pt,arc=4pt,95  left=6pt,right=6pt,top=4pt,bottom=4pt,before skip=8pt,after skip=8pt,96  title={\faIcon{file-code}~\texttt{#1}},coltitle=uqoGris,fonttitle=\small\sffamily,colbacktitle=fileBg,toptitle=3pt,bottomtitle=0pt}97\fvset{fontsize=\footnotesize,breaklines=true,breakanywhere=true,breaksymbolleft={}}9899\newcommand{\code}[1]{\texttt{\small #1}}100\newcommand{\G}{G\$}101\newcolumntype{L}[1]{>{\raggedright\arraybackslash}p{#1}}102\newcolumntype{R}[1]{>{\raggedleft\arraybackslash}p{#1}}103\newcolumntype{Y}{>{\raggedright\arraybackslash}X}104\rowcolors{2}{uqoBgClair}{white}105\newcommand{\hc}[1]{\textcolor{white}{\sffamily\bfseries #1}}106107\input{tables/macros}108109\begin{document}110111% ==============================================================================112% PAGE TITRE113% ==============================================================================114\thispagestyle{empty}115\begin{tikzpicture}[remember picture, overlay]116  \fill[uqoBleu] (current page.north west) rectangle ([yshift=-6.2cm]current page.north east);117  \fill[uqoOr] ([yshift=-6.2cm]current page.north west) rectangle ([yshift=-6.35cm]current page.north east);118  \fill[uqoBleu] (current page.south west) rectangle ([yshift=2.2cm]current page.south east);119\end{tikzpicture}120\vspace*{-1.6cm}121\begin{center}122  \includegraphics[height=2cm]{uqo-logo.png}\\[0.4cm]123  {\color{white}\LARGE\textbf{Université du Québec en Outaouais}}\\[0.2cm]124  {\color{white}\large Département des sciences administratives}125\end{center}126127\vspace{2.6cm}128\begin{center}129  {\Huge\bfseries\color{uqoBleu} SPID}\\[0.4cm]130  {\LARGE\bfseries\color{uqoBleu} SEC Project Intelligence Database}\\[0.5cm]131  {\color{uqoOr}\rule{10cm}{1.5pt}}\\[0.6cm]132  {\large\color{uqoGris} Provenance des données, fonctionnement du pipeline d'extraction\\ et portrait statistique de \nProjets{} projets stratégiques\\ extraits des filings de \nCiks{} sociétés cotées américaines (2010--2026)}\\[0.9cm]133  {\sffamily\small\color{uqoGris}134  \faIcon{database}~DuckDB \quad \faIcon{file-alt}~10-K · 10-Q · 8-K \quad \faIcon{robot}~Extraction par LLM \quad \faIcon{project-diagram}~Graphe de connaissances \quad \faIcon{vector-square}~Embeddings}135\end{center}136137\vspace{1.8cm}138\begin{center}139\begin{tabular}{rl}140  \textcolor{uqoBleu}{\faIcon{user}} & {\large\textbf{Manel Kammoun}} \\[2pt]141  & \href{mailto:manel.kammoun@uqo.ca}{manel.kammoun@uqo.ca} \\[9pt]142  \textcolor{uqoBleu}{\faIcon{user}} & {\large\textbf{Charli Tandja Mbianda}} \\[2pt]143  & \href{mailto:djerrycharli.tandjambianda@uqo.ca}{djerrycharli.tandjambianda@uqo.ca} \\[9pt]144  \textcolor{uqoBleu}{\faIcon{user}} & {\large\textbf{Simon-Pierre Boucher}} \\[2pt]145  & \href{mailto:simon-pierre.boucher@uqo.ca}{simon-pierre.boucher@uqo.ca} \\[12pt]146  \textcolor{uqoBleu}{\faIcon{map-marker-alt}} & Gatineau --- Pavillon Alexandre-Taché, 283, boulevard Alexandre-Taché \\[6pt]147  \textcolor{uqoBleu}{\faIcon{calendar-alt}} & Rapport technique --- \today \\148\end{tabular}149\end{center}150\vfill151\begin{tikzpicture}[remember picture, overlay]152  \node[anchor=south, yshift=0.8cm] at (current page.south) {\color{white}\small\textbf{Université du Québec en Outaouais --- Département des sciences administratives}};153\end{tikzpicture}154\newpage155156% ==============================================================================157\section*{Résumé}158% ==============================================================================159Ce rapport documente \textbf{SPID} (\emph{SEC Project Intelligence Database}), une base de données qui reconstruit le portefeuille de \emph{projets stratégiques} des grandes sociétés cotées américaines à partir du texte brut de leurs documents réglementaires déposés auprès de la Securities and Exchange Commission (SEC). Plutôt que de lire les formulaires 10-K, 10-Q et 8-K comme des documents financiers, SPID les traite comme une source d'\emph{intelligence sur les projets} : usines, centres de données, acquisitions, programmes de R\&D, initiatives d'IA, transition énergétique, etc.160161Le document répond à trois questions. \textbf{D'où viennent les données ?} Elles proviennent du corpus EDGAR de l'UQO : les filings de \nCiks{} sociétés de l'univers \textbf{S\&P~500 $\cup$ Russell~3000} (2\,564 sociétés, extension du 27--28~octobre~2026) téléchargés depuis l'API publique de la SEC, soit 527\,548 documents et quelque 255~Go de HTML brut répartis sur dix nœuds du cluster MacLustr, découpés en sections. \textbf{Comment fonctionne le pipeline ?} Cinq étapes reprenables (ingestion des 10-K, extraction par grand modèle de langage, résolution des mentions en projets, graphe de connaissances, embeddings) persistent leurs résultats dans un unique fichier DuckDB de 3,2~Go. \textbf{Que contient la base ?} \nSections{} sections analysées, \nMentions{} mentions de projets, \nProjets{} projets résolus répartis en 21~types et 11~secteurs, un graphe de 183\,472 nœuds et \nProjets{} vecteurs sémantiques de 384~dimensions. Une trentaine de figures et de tableaux dressent le portrait statistique du jeu de données, et une section finale en expose les limites.162163\vspace{0.5cm}164\begin{infobox}[Chiffres clés de la base \code{spid.duckdb} (exécution complète, 28~octobre~2026)]165\begin{multicols}{2}\small166\begin{itemize}[leftmargin=*]167  \item Entreprises couvertes : \textbf{\nCiks} (S\&P~500 $\cup$ Russell~3000)168  \item Période des dépôts : \textbf{janv. 2010 -- oct. 2026}169  \item Sections de filings analysées : \textbf{\nSections}170  \item Filings contenant au moins un projet : \textbf{\nFilings}171  \item Mentions de projets extraites : \textbf{\nMentions}172  \item Projets résolus : \textbf{\nProjets}173  \item Types de projets (taxonomie) : \textbf{21}174  \item Secteurs GICS : \textbf{11}175  \item Projets avec montant divulgué : \textbf{\nAvecMontant} (\pctAvecMontant\,\%)176  \item Montant médian divulgué : \textbf{\medianeMontant{} M\$~US}177  \item Localisations distinctes : \textbf{\nLoc}178  \item Technologies distinctes : \textbf{\nTech}179  \item Partenaires distincts : \textbf{\nPartenaires}180  \item Nœuds / arêtes du graphe : \textbf{183\,472 / 204\,456}181  \item Embeddings (all-MiniLM-L6-v2, 384-d) : \textbf{\nProjets}182  \item Taille du fichier DuckDB : \textbf{3,2 Go}183\end{itemize}184\end{multicols}185\end{infobox}186187\newpage188\tableofcontents189\newpage190191% ==============================================================================192\section{Vue d'ensemble}193% ==============================================================================194La stratégie d'une entreprise se matérialise par des \emph{projets} : la construction d'une usine, l'ouverture d'un centre de données, l'intégration d'une société acquise, le lancement d'un programme de R\&D, la migration d'un système ERP vers l'infonuagique. Ces initiatives sont pourtant dispersées, non structurées et enfouies dans les sections narratives des documents réglementaires. Aucune base commerciale (Capital~IQ, PitchBook, Gartner) ne les recense de manière systématique et \emph{centrée sur le projet}.195196SPID comble cette lacune. L'unité d'analyse n'est ni le document ni l'entreprise, mais le \textbf{projet}, décrit par un type (taxonomie contrôlée de 21~catégories), un statut, un montant, des localisations, des technologies, des partenaires, des bénéfices attendus, des risques et une chronologie de mentions dans les filings successifs.197198\begin{figure}[H]199\centering200\includegraphics[width=0.86\textwidth]{fig_entonnoir}201\caption{L'entonnoir SPID : des \nSections{} sections de filings analysées aux \nProjets{} projets résolus. Chaque projet agrège en moyenne 2,1~mentions.}202\label{fig:entonnoir}203\end{figure}204205Le dépôt \code{project-db/} est volontairement léger (environ 1\,900~lignes de Python dans le paquet \code{spid/}) : il s'appuie sur le corpus EDGAR déjà constitué par l'UQO (section~\ref{sec:donnees}) et y ajoute la « couche projet » (section~\ref{sec:pipeline}). Le résultat tient dans un unique fichier \code{data/db/spid.duckdb} (section~\ref{sec:schema}), dont la section~\ref{sec:stats} dresse le portrait statistique.206207% ==============================================================================208\section{Provenance des données}\label{sec:donnees}209% ==============================================================================210211\subsection{La source primaire : EDGAR}212Toutes les données textuelles proviennent d'\textbf{EDGAR} (\emph{Electronic Data Gathering, Analysis, and Retrieval}), le système de dépôt électronique de la SEC. Toute société cotée aux États-Unis y publie obligatoirement :213214\begin{itemize}215  \item le \textbf{10-K}, rapport annuel exhaustif (activités, facteurs de risque, propriétés, rapport de gestion) ;216  \item le \textbf{10-Q}, rapport trimestriel abrégé ;217  \item le \textbf{8-K}, rapport d'événement courant déposé dans les quatre jours ouvrables suivant un fait important (acquisition, contrat, nomination, communiqué de résultats).218\end{itemize}219220EDGAR est public, gratuit et accessible par API (\url{https://www.sec.gov/edgar}), sous réserve d'un \emph{User-Agent} déclaratif et d'une limite de 10~requêtes par seconde. Le corpus a été téléchargé avec l'identifiant \code{UQO-Research simon-pierre.boucher@uqo.ca}.221222\subsection{Le corpus EDGAR de l'UQO}223SPID est construit \emph{par-dessus} le corpus \code{UQO\_RESEARCH\_DB}, qui réside dans le répertoire parent \code{../data} et que SPID consomme en lecture seule. Ce corpus a été constitué par la chaîne \code{src/acquisition} $\rightarrow$ \code{src/parsing} $\rightarrow$ \code{src/storage} du dépôt amont.224225\begin{table}[H]226\centering\small227\caption{Actifs du corpus source utilisés par SPID.}228\begin{tabularx}{\textwidth}{L{4.2cm} L{3.4cm} Y}229\rowcolor{uqoBleu}\hc{Actif} & \hc{Volume} & \hc{Contenu et usage par SPID}\\230\code{data/raw/sec/} & $\approx$~255 Go, 2\,564 entreprises & HTML brut de chaque dépôt, rangé par \code{<cik>/<form>/<accession>/}, conservé sur le nœud qui l'a traité (corpus S\&P~500 sur M3U96b).\\231\code{parquet/filings/} & 527\,548 filings & Une ligne par dépôt : \code{accession\_number}, \code{cik}, \code{ticker}, \code{company\_name}, \code{form\_type}, \code{filing\_date}, \code{fiscal\_year}.\\232\code{parquet/filing\_sections/} & 1\,342\,283 sections & Texte pré-segmenté des 10-K, 10-Q et 8-K (7,3~Go) : \code{section\_id}, \code{accession\_number}, \code{section\_name}, \code{item\_number}, \code{text}, \code{word\_count}.\\233\code{parquet/companies/} & 2\,564 lignes & Métadonnées : secteur GICS, code SIC, État d'incorporation, bourse, indicateurs \code{in\_sp500} / \code{in\_russell3000}.\\234\end{tabularx}235\end{table}236237\paragraph{Sélection des entreprises (\code{src/acquisition/sp500.py}, \code{universe.py}).} L'échantillon initial (juin 2026) était l'indice \textbf{S\&P~500} ; il a été étendu le 27~octobre~2026 au \textbf{Russell~3000}. Faute de liste officielle gratuite, le Russell~3000 est approché par les positions de l'ETF iShares~IWV (fichier \code{latest-holdings.csv} du 23~octobre~2026) : 2\,587 lignes « actions » dont 2\,555 appariées à un CIK (les CVR, titres en escrow et banques déposant auprès de la FDIC sont écartés). L'univers fusionné (\code{data/metadata/universe.json}) compte \textbf{2\,564 sociétés} : 491 présentes dans les deux indices, 9 S\&P~500 seulement, 2\,064 Russell seulement ; 65 d'entre elles (émetteurs étrangers déposant des 20-F/40-F) n'ont aucun 10-K/10-Q/8-K. Pour le S\&P~500, La liste des constituants (ticker, nom, CIK, secteur et sous-industrie GICS, date d'ajout) est lue dans la table de la page Wikipédia \emph{List of S\&P 500 companies} et mise en cache dans \code{data/metadata/sp500\_constituents.json}. Chaque ticker est ensuite associé à son identifiant SEC (\emph{Central Index Key}, CIK, complété à 10~chiffres) via le fichier public \code{company\_tickers.json} de la SEC (\code{cik\_mapper.py}). Il s'agit d'un \textbf{instantané courant} de l'indice, non d'une composition historique : les sociétés sorties de l'indice avant 2026 sont absentes (biais de survie, section~\ref{sec:limites}).238239\paragraph{Téléchargement.} Modules \code{sec\_client.py} et \code{downloader.py}. Pour chaque CIK, l'index des dépôts est lu à \code{data.sec.gov/submissions/CIK\{cik\}.json} (bloc \code{recent} puis fichiers d'archives paginés). Sont retenus les formulaires \textbf{10-K}, \textbf{10-Q} et \textbf{8-K} au sens strict (les amendements \code{/A} sont exclus) déposés à partir du \textbf{1\textsuperscript{er}~janvier~2010}. Le document primaire de chaque dépôt est téléchargé dans \code{data/raw/sec/\{cik\}/\{form\}/\{accession\}/}. Le client respecte la limite de la SEC (intervalle minimal de 0,1~s, soit 10~requêtes/s), effectue jusqu'à 5~tentatives avec attente exponentielle (1, 2, 4, 8, 16~s) et tient un journal JSONL des fichiers reçus qui rend le téléchargement reprenable.240241\paragraph{Nettoyage et segmentation amont (\code{src/parsing/}).} Le HTML est nettoyé avec \code{lxml} (balises \code{script}, \code{style}, \code{meta}, \code{link} supprimées ; tableaux convertis en texte tabulé ; fichiers de plus de 50~Mo ignorés). Le découpage repère les en-têtes « ITEM~\emph{n} » et « PART~I/II » par expressions régulières : les \textbf{10-Q} sont découpés en 7~sections (états financiers, MD\&A, risques de marché, contrôles, litiges, facteurs de risque, ventes non enregistrées) ; les \textbf{8-K}, trop courts et hétérogènes, sont conservés en une seule section \code{full\_body}. Toute section de moins de 20~mots est rejetée. Les \textbf{10-K}, en revanche, n'avaient été laissés qu'en HTML brut : c'est la première tâche de SPID (section~\ref{sec:ingest}).242243\begin{table}[H]244\centering\small245\caption{Composition du fichier \code{filings.parquet} (527\,548 dépôts, 2\,499 CIK).}246\begin{tabular}{lrll}247\rowcolor{uqoBleu}\hc{Formulaire} & \hc{Dépôts} & \hc{Premier dépôt} & \hc{Dernier dépôt}\\2488-K & 400\,606 & 2010-01-04 & 2026-10-27\\24910-Q & 95\,167 & 2010-01-05 & 2026-10-27\\25010-K & 31\,775 & 2010-01-08 & 2026-10-27\\251\end{tabular}252\end{table}253254\begin{table}[H]255\centering\small256\caption{Sections éligibles à l'extraction (au moins 30~mots), par formulaire, après ingestion des 10-K par SPID.}257\begin{tabular}{lrr}258\rowcolor{uqoBleu}\hc{Formulaire} & \hc{Sections} & \hc{Entreprises (CIK)}\\2598-K  & 400\,601 & 2\,499 \\26010-K & 143\,704 & 2\,464 \\26110-Q & 578\,793 & 2\,494 \\262\midrule263\textbf{Total} & \textbf{1\,123\,098} & \textbf{2\,499} \\264\end{tabular}265\end{table}266267\begin{notebox}[Pourquoi seulement 84 entreprises pour les 10-Q ?]268Le corpus amont n'a segmenté les 10-Q que pour un sous-ensemble de sociétés ; pour les autres, les 10-Q existent en HTML brut mais n'ont pas été découpés. Les 8-K et les 10-K couvrent en revanche la quasi-totalité de l'échantillon (497~CIK chacun) et fournissent 85\,\% des mentions de projets (figure~\ref{fig:mentions}).269\end{notebox}270271% ==============================================================================272\section{Fonctionnement du pipeline}\label{sec:pipeline}273% ==============================================================================274Le traitement s'organise en cinq étapes séquentielles. Chacune lit la sortie de la précédente dans DuckDB, y écrit la sienne de façon \textbf{idempotente} (clés stables, \code{INSERT OR REPLACE}) et peut être relancée sans double comptage.275276\begin{figure}[H]277\centering278\begin{tikzpicture}[279  font=\sffamily\small, node distance=5mm and 9mm, >=Latex,280  src/.style={draw=uqoGris, fill=uqoBgClair, rounded corners=2pt, minimum width=3.2cm, minimum height=9mm, align=center},281  etape/.style={draw=uqoBleu, fill=uqoBleu, text=white, rounded corners=3pt, minimum width=3.4cm, minimum height=10mm, align=center, font=\sffamily\small\bfseries, drop shadow={opacity=0.25}},282  tbl/.style={draw=uqoOr, fill=uqoOr!10, rounded corners=2pt, minimum width=3.4cm, minimum height=8mm, align=center, font=\ttfamily\footnotesize},283  arr/.style={->, thick, color=uqoGris}284]285  \node[src] (raw) {HTML brut 10-K\\ \footnotesize data/raw/sec (88 Go)};286  \node[src, right=of raw] (secq) {filing\_sections.parquet\\ \footnotesize 10-Q + 8-K (127\,800)};287  \node[src, right=of secq] (meta) {filings + companies\\ \footnotesize métadonnées, GICS};288  \node[etape, below=of raw] (ing) {1. INGEST\\ \footnotesize\mdseries nettoyage + Items 1/1A/2/7/7A};289  \node[tbl, below=of ing] (ss) {spid\_sections (27\,164)};290  \node[tbl, below=of secq, yshift=-2.2cm] (vs) {v\_sections (vue unifiée)\\ 153\,894 sections};291  \node[etape, below=of vs] (ext) {2. EXTRACT\\ \footnotesize\mdseries gate regex → LLM JSON (gpt-4o-mini)};292  \node[tbl, below=of ext] (pm) {project\_mentions (308\,065)};293  \node[etape, below=of pm] (res) {3. RESOLVE\\ \footnotesize\mdseries fusion entreprise × type × ancre};294  \node[tbl, below=of res] (pr) {projects (121\,099)\\ project\_timeline (308\,065)};295  \node[etape, below left=8mm and -12mm of pr] (gr) {4. GRAPH};296  \node[etape, below right=8mm and -12mm of pr] (em) {5. EMBED};297  \node[tbl, below=of gr] (kg) {kg\_nodes (183\,472)\\ kg\_edges (204\,456)};298  \node[tbl, below=of em] (pe) {project\_embeddings\\ 121\,099 × 384-d};299  \draw[arr] (raw) -- (ing); \draw[arr] (ing) -- (ss);300  \draw[arr] (ss.east) -| ([xshift=-6mm]vs.west) -- (vs.west);301  \draw[arr] (secq) -- (vs); \draw[arr] (meta.south) |- ([yshift=2mm]vs.north east) -- (vs.north east);302  \draw[arr] (vs) -- (ext); \draw[arr] (ext) -- (pm); \draw[arr] (pm) -- (res); \draw[arr] (res) -- (pr);303  \draw[arr] (pr) -- (gr); \draw[arr] (pr) -- (em); \draw[arr] (gr) -- (kg); \draw[arr] (em) -- (pe);304  \begin{scope}[on background layer]305    \node[fit=(ing)(ss)(ext)(pm)(res)(pr)(gr)(em)(kg)(pe), draw=uqoOr, dashed, rounded corners=4pt, inner sep=5mm, label={[uqoOr, font=\sffamily\footnotesize\bfseries]below:data/db/spid.duckdb (2,9 Go) — paquet spid/}] {};306  \end{scope}307\end{tikzpicture}308\caption{Architecture du pipeline SPID. Les rectangles gris sont les entrées (corpus EDGAR de l'UQO), les rectangles bleus les cinq étapes de traitement et les rectangles ocre les tables DuckDB produites.}309\label{fig:archi}310\end{figure}311312\subsection{Étape 1 --- Ingestion des 10-K}\label{sec:ingest}313\textbf{Module} : \code{spid/ingest.py}. Pour chaque dépôt 10-K du répertoire \code{data/raw/sec/<cik>/10-K/<accession>/} :314\begin{enumerate}315  \item \textbf{Sélection du document primaire} : le plus gros fichier \code{.htm}, \code{.html} ou \code{.txt} du répertoire (les pièces jointes et les exhibits sont écartés).316  \item \textbf{Nettoyage HTML} : suppression des balises \code{script}, \code{style} et \code{table} avec BeautifulSoup (parseur \code{lxml}), conversion en texte, dé-échappement des entités, normalisation des espaces. Contrairement au nettoyeur amont, les tableaux sont \emph{supprimés} : les chiffres présentés en tableau dans les 10-K n'atteignent donc pas l'extracteur.317  \item \textbf{Découpage en Items} : l'expression régulière \code{ITEM\textbackslash s+(\textbackslash d+[AB]?)\textbackslash s*[.\textbackslash -:—–]} repère les en-têtes et ne conserve que les Items les plus denses en projets : \textbf{1} (\emph{Business}), \textbf{1A} (\emph{Risk Factors}), \textbf{2} (\emph{Properties}), \textbf{7} (\emph{MD\&A}) et \textbf{7A} (\emph{Quantitative Disclosures}). Les occurrences de moins de 400~caractères (renvois de la table des matières) sont écartées ; pour chaque Item, la plus longue occurrence est retenue et tronquée à 600\,000~caractères. Si aucun Item n'est reconnu, le corps complet est conservé (\code{full\_body}, 1\,230 cas).318  \item \textbf{Persistance} dans \code{spid\_sections} (identifiant UUID, compte de mots), par lots de 400~lignes. Une accession déjà ingérée est sautée.319\end{enumerate}320321\begin{table}[H]322\centering\small323\caption{Sections 10-K produites par l'ingestion (\nDixK{} dépôts 10-K, \nSectionsDixK{} sections, \motsDixK{}~millions de mots).}324\begin{tabular}{llrrr}325\rowcolor{uqoBleu}\hc{section\_name} & \hc{Item du 10-K} & \hc{Sections} & \hc{Mots (moy.)} & \hc{Mots (méd.)}\\326\input{tables/tab_sections}327\end{tabular}328\end{table}329330\begin{figure}[H]331\centering332\includegraphics[width=0.95\textwidth]{fig_sections_10k}333\caption{Sections 10-K ingérées par SPID : nombre par Item et longueur médiane en mots. Le rapport de gestion (Item~7) et les facteurs de risque (Item~1A) sont les sections les plus longues ; les propriétés (Item~2) sont courtes mais riches en localisations.}334\end{figure}335336\subsection{Étape 2 --- Extraction par grand modèle de langage}\label{sec:extract}337\textbf{Modules} : \code{spid/pipeline.py} (moteur), \code{spid/extract/base.py} (interface), \code{spid/extract/llm.py} (extracteur LLM), \code{spid/extract/rules.py} (extracteur déterministe). Le backend est \emph{enfichable} : le même moteur alimente indifféremment le LLM ou les règles.338339\subsubsection{Flux unifié}340La vue \code{v\_sections} réunit les sections 10-Q/8-K du corpus amont et les sections 10-K ingérées, jointes aux métadonnées du dépôt (CIK, ticker, formulaire, date) et de l'entreprise (secteur, sous-industrie, SIC, état). Seules les sections d'au moins 30~mots sont éligibles.341342\subsubsection{Maîtrise du coût : le « gate » et le « focus »}343\begin{itemize}344  \item \textbf{Project gate.} Avant tout appel, une expression régulière de vocabulaire-projet (\code{\_PROJECT\_GATE}, racines \emph{project, initiative, program, invest, expan, construct, build, launch, develop, deploy, implement, acqui, partner, facilit, capacity, capital, migrat, transform, pipeline, plant, data center, automat, sustainab, renewable, restructur}) filtre les sections. Une section sans signal de projet ne déclenche \emph{aucun} appel API.345  \item \textbf{Focus.} Si la section dépasse 9\,000~caractères, seules les \emph{fenêtres} de texte entourant chaque signal (220~caractères avant, 380 après) sont conservées, triées, fusionnées lorsqu'elles se chevauchent et concaténées jusqu'à un budget de 9\,000~caractères. Le message final (« SECTION : \emph{nom} » + texte focalisé) est plafonné à 14\,000~caractères. Ce mécanisme est déterminant pour les 8-K, transmis en une seule section \code{full\_body}.346\end{itemize}347348\subsubsection{Consigne et schéma de sortie}349Le modèle (\code{gpt-4o-mini}, température~0, mode JSON \code{response\_format=json\_object}, 2\,000~jetons de sortie au maximum, délai de 120~s) reçoit une consigne système d'analyste financier et renvoie un objet \code{\{"projects": [\ldots]\}} dont chaque élément respecte le schéma suivant :350351\begin{fichier}[schéma d'une mention de projet (sortie JSON du LLM)]352\begin{Verbatim}353{354  "project_name": "",   // nom court (officiel si mentionné)355  "project_type": "",   // EXACTEMENT un des 21 types de la taxonomie356  "description":  "",   // 1 phrase, ancrée dans le texte (pas de spéculation)357  "objective":    "",   // le but / le pourquoi358  "status": "planned | in_progress | completed | mentioned",359  "amount_usd": 0,      // montant en USD si indiqué, sinon null360  "locations": [], "technologies": [], "partners": [], "suppliers": [],361  "benefits":  [], "risks": [], "years": [],362  "confidence": 0.0     // 0..1 : à quel point c'est un vrai projet concret363}364\end{Verbatim}365\end{fichier}366367\textbf{Règles imposées au modèle} (extrait textuel de la consigne) : \enquote{\emph{Extract ONLY real initiatives, not generic risk-factor boilerplate or hypotheticals. If the text describes no concrete project, return \{"projects": []\}. Do not invent facts. Numbers/locations must appear in the text. Prefer fewer high-quality projects over many vague ones.}} Les appels sont parallélisés dans un \code{ThreadPoolExecutor} (16~\emph{workers} lors de l'exécution complète) ; trois tentatives sont faites sur les codes~429 et~5xx (attentes de 1,5, 3 et 4,5~s), après quoi la section est considérée sans projet.368369\subsubsection{Post-traitement et identifiant stable}370Chaque projet renvoyé est normalisé : le \code{project\_type} est ramené à la taxonomie (correspondance exacte, puis floue ; défaut \code{technology\_deployment}) ; le statut est validé (défaut \code{mentioned}) ; une mention sans description est rejetée ; les montants sont convertis en nombre ; les listes sont tronquées à 8~éléments de 120~caractères ; les années ne sont retenues qu'entre 1980 et 2040 ; la confiance vaut 0,6 par défaut. Si le modèle ne renvoie ni technologies ni années, les expressions régulières de la taxonomie les cherchent dans la description. Les mentions de confiance inférieure à \textbf{0,45} sont écartées par le moteur. Un identifiant \textbf{stable} est calculé :371\[372\code{mention\_id} = \mathrm{SHA\text{-}1}\big(\code{accession} \mid \code{section\_id} \mid \code{project\_type} \mid \code{ancre}\big)[0{:}20],373\quad \code{ancre} = \code{type:nom[0{:}40]}.374\]375Ré-exécuter l'extraction réinsère les mêmes lignes (\code{INSERT OR REPLACE}) sans doublon : l'extraction est \textbf{incrémentale et reprenable}.376377\subsubsection{Le backend déterministe \code{rules}}378Sans coût d'API, \code{rules.py} découpe la section en phrases, ne garde que celles de 20 à 700~caractères qui passent le \emph{gate}, les classe par les signaux de la taxonomie (au plus deux types), repère un nom de projet explicite (« Project~X », « X~Program »), puis calcule une confiance : base 0,40, +0,20 pour un nom explicite, +0,18 pour un montant, +0,10 pour une localisation, +0,06 pour une année, +0,08 pour un statut déterminé, +0,06 pour un verbe d'engagement (\emph{announced, committed}), $-$0,08 pour un modal d'incertitude (\emph{may, could, potential}). Les phrases sous 0,30 sont abandonnées. Ce backend sert de base de comparaison et d'amorçage ; la base actuelle est intégralement issue du backend \code{llm}.379380\subsubsection{Exécution sur le corpus complet}381Le pilote \code{run\_full\_extract.py} traite les CIK par lots (15 puis 20~CIK) pour borner la mémoire (la matérialisation de toutes les sections d'un seul coup dépassait la limite de 2~Go des tampons de chaînes Arrow). Le run S\&P~500 de juin~2026 a couvert 153\,894 sections (500~CIK, 34~lots, 16~appels parallèles) ; l'extension Russell~3000 des 27--28~octobre~2026 a ajouté 968\,134 sections (81~lots de 20~CIK, 48~appels parallèles, une douzaine d'heures d'extraction effective) en s'appuyant sur le registre \code{extracted\_sections}, qui remplace l'ancien journal \code{logs/extract\_done\_ciks.txt} et garantit qu'aucune section n'est facturée deux fois. Résultat : \textbf{\nMentions} mentions, toutes issues du backend \code{llm}.382383\begin{table}[H]384\centering\small385\caption{Six mentions tirées au hasard parmi celles de confiance $\geq$~0,90 et de montant $>$~100~M\$ (types énergie, construction). Montants en M\$~US.}386\begin{tabularx}{\textwidth}{l L{1.9cm} L{2.4cm} Y r r}387\rowcolor{uqoBleu}\hc{Ticker} & \hc{Dépôt} & \hc{Type} & \hc{Nom et description extraits} & \hc{M\$} & \hc{Conf.}\\388\input{tables/tab_exemples}389\end{tabularx}390\end{table}391392\subsection{Étape 3 --- Résolution des mentions en projets}\label{sec:resolve}393\textbf{Module} : \code{spid/resolve.py}, entièrement en SQL DuckDB. Un même projet est en général mentionné dans plusieurs filings et sur plusieurs années (le 8-K d'annonce, puis les 10-K et 10-Q de suivi). La résolution regroupe les mentions par une clé exacte à trois composantes :394\[395\code{gkey} = \code{cik} \mid \code{project\_type} \mid \text{ancre},\qquad396\text{ancre} = \begin{cases}397\text{première localisation (minuscules)} & \text{si présente,}\\398\text{premier mot de 4 lettres ou plus du nom} & \text{sinon,}\\399\code{general} & \text{à défaut,}400\end{cases}401\]402et \code{project\_id} $=$ MD5(\code{gkey}). Il n'y a pas de similarité floue : deux mentions fusionnent si et seulement si elles partagent entreprise, type et ancre. Pour chaque groupe, une ligne de \code{projects} est produite :403\begin{itemize}404  \item \code{project\_name} et \code{description} : ceux de la mention la plus confiante (\code{arg\_max} sur \code{confidence}) ;405  \item \code{canonical\_location} : l'ancre géographique ; \code{technologies} : union dédupliquée ;406  \item \code{status} : celui du dépôt le plus récent (\code{arg\_max} sur \code{filing\_date}) ;407  \item \code{total\_amount\_usd} : le \textbf{maximum} des montants divulgués (et non la somme, pour ne pas compter plusieurs fois un même montant répété de filing en filing) ;408  \item \code{n\_mentions}, \code{n\_filings} (accessions distinctes), \code{avg\_confidence} ;409  \item \code{first\_seen} / \code{last\_seen} : dates de dépôt extrêmes ; \code{first\_year} / \code{last\_year} : années extrêmes citées dans le texte.410\end{itemize}411Chaque mention datée est conservée dans \code{project\_timeline} (dépôt, formulaire, statut, montant, confiance, extrait de 300~caractères), à raison d'une ligne par mention, ce qui permet de suivre l'évolution d'un projet de son annonce à son achèvement. Contrairement à l'extraction, la résolution (comme le graphe et les embeddings) reconstruit ses tables intégralement à chaque exécution.412413\textbf{Résultat} : \nMentions{} mentions $\rightarrow$ \nProjets{} projets ; \pctMonoMention\,\% des projets ne reposent que sur une mention, tandis que les projets les plus suivis cumulent jusqu'à 185~mentions (tableau~\ref{tab:suivis}).414415\subsection{Étape 4 --- Graphe de connaissances}\label{sec:graph}416\textbf{Module} : \code{spid/graph.py}. Les projets résolus sont projetés en un graphe orienté de cinq types de nœuds et trois relations :417\begin{center}\small418\begin{tabular}{llcl}419\rowcolor{uqoBleu}\hc{Nœud} & \hc{Préfixe} & & \hc{Relation}\\420Company (2\,492) & \code{C:cik} & \code{owns} $\rightarrow$ & Project\\421Project (121\,099) & \code{P:project\_id} & \code{located\_in} $\rightarrow$ & Location\\422Location (14\,508) & \code{L:lieu} & \code{uses} $\rightarrow$ & Technology\\423Technology (8\,551) & \code{T:techno} & & \\424Partner (36\,822) & \code{PR:nom} & & \\425\end{tabular}426\end{center}427Les propriétés sont stockées en JSON (entreprise : cik, ticker, secteur ; projet : type, statut, montant, nombre de filings, première et dernière observation ; arête \code{owns} : montant). Le graphe est exporté en parquet et en Cypher (\code{data/exports/kg\_import.cypher}, 6,6~Mo, instructions \code{MERGE}) pour Neo4j. Les nœuds de casse variable (partenaires, noms d'entreprise) sont agrégés par \code{GROUP BY} avec \code{any\_value()} afin de respecter la clé primaire. Les 7\,640 nœuds \code{Partner} sont créés à partir des mentions mais la relation \code{partners\_with} n'est pas encore matérialisée : ils n'ont pas d'arête entrante dans la version actuelle.428429\subsection{Étape 5 --- Embeddings et recherche sémantique}\label{sec:embed}430\textbf{Module} : \code{spid/embed.py}. Le texte de chaque projet (« \emph{nom}. \emph{type}. \emph{description}. technologies : … ») est encodé en un vecteur de \textbf{384~dimensions} normalisé (norme~L2 unitaire) par le modèle local \code{all-MiniLM-L6-v2} (\code{sentence-transformers}, lots de 256), sans appel API. Les vecteurs sont stockés dans \code{project\_embeddings}. La recherche sémantique (\code{spid semantic "AI projects launched by banks"}) encode la requête, calcule la similarité cosinus par un simple produit matriciel sur les 19\,227 vecteurs (recherche exhaustive, sans index approché), sur-échantillonne cinq fois le nombre de résultats demandés puis applique les filtres SQL éventuels.431432\subsection{Interfaces : ligne de commande et API}433\begin{fichier}[commandes du paquet spid (exécutées depuis project-db/)]434\begin{Verbatim}435PY=../.venv/bin/python436PYTHONPATH=. $PY -m spid ingest --tickers NVDA,AAPL,MSFT     # 1. sectionner les 10-K bruts437PYTHONPATH=. $PY -m spid extract --backend llm --workers 16  # 2. extraire (ou --backend rules)438PYTHONPATH=. $PY -m spid resolve                             # 3. mentions -> projets + timeline439PYTHONPATH=. $PY -m spid graph                               # 4. graphe + export Cypher/parquet440PYTHONPATH=. $PY -m spid embed                               # 5. embeddings MiniLM441PYTHONPATH=. $PY -m spid analytics | stats                   # tableaux de bord agrégés442PYTHONPATH=. $PY -m spid search "data center" --type data_center --min-amount 5e8443PYTHONPATH=. $PY -m spid semantic "AI projects launched by banks"444PYTHONPATH=. $PY -m spid all --backend llm                   # tout le pipeline445uvicorn spid.api:app --port 8088                             # API HTTP : /projects /semantic /analytics446\end{Verbatim}447\end{fichier}448449La configuration passe par \code{project-db/.env} : \code{OPENAI\_API\_KEY}, \code{SPID\_LLM\_BASE\_URL}, \code{SPID\_LLM\_MODEL} (défaut \code{gpt-4o-mini}), \code{SPID\_EMBED\_MODEL}, \code{SPID\_BACKEND}. L'interface étant compatible OpenAI, deux variables suffisent pour viser la passerelle du cluster de calcul de l'UQO (\code{llm.maclustr.io}) ou tout modèle local.450451\subsection{Coût, débit et reproductibilité}452\begin{itemize}453  \item \textbf{Coût} : de l'ordre du dixième de cent US par section grâce au \emph{gate} et au \emph{focus} ; l'exécution complète est estimée entre 100 et 130~\$~US de \code{gpt-4o-mini}.454  \item \textbf{Débit} : appels LLM parallèles (16~\emph{workers}) ; résolution, graphe et analytique sont du SQL DuckDB pur et passent à l'échelle de millions de mentions.455  \item \textbf{Reprenabilité} : identifiants stables, \code{INSERT OR REPLACE}, journal des CIK terminés ; une interruption ne re-facture jamais le travail déjà fait.456\end{itemize}457458% ==============================================================================459\section{Schéma de la base de données}\label{sec:schema}460% ==============================================================================461La base est un unique fichier DuckDB (\code{data/db/spid.duckdb}, 3,2~Go, dernière écriture le 28~octobre~2026). Elle contient huit tables physiques (dont le registre \code{extracted\_sections} ajouté en octobre~2026), trois vues sur le corpus amont et une vue unifiée.462463\begin{table}[H]464\centering\small465\caption{Tables persistées dans \code{spid.duckdb}.}466\begin{tabularx}{\textwidth}{L{3.3cm} R{1.5cm} Y}467\rowcolor{uqoBleu}\hc{Table} & \hc{Lignes} & \hc{Colonnes}\\468\code{spid\_sections} & 27\,164 & section\_id, accession\_number, section\_name, item\_number, text, word\_count\\469\code{project\_mentions} & 308\,065 & mention\_id, accession\_number, cik, section\_id, section\_name, project\_name, project\_type, description, objective, amount\_usd, amount\_raw, locations[], technologies[], partners[], suppliers[], benefits[], risks[], years[], status, confidence, backend, ticker, company\_name, form\_type, filing\_date, fiscal\_year, sector\\470\code{projects} & 121\,099 & project\_id, cik, ticker, company\_name, sector, project\_type, project\_name, canonical\_location, technologies[], status, total\_amount\_usd, n\_mentions, n\_filings, first\_seen, last\_seen, first\_year, last\_year, avg\_confidence, description\\471\code{project\_timeline} & 308\,065 & project\_id, accession\_number, filing\_date, form\_type, status, amount\_usd, confidence, snippet\\472\code{kg\_nodes} & 183\,472 & node\_id, node\_type, label, props (JSON)\\473\code{kg\_edges} & 204\,456 & src, rel, dst, props (JSON)\\474\code{project\_embeddings} & 121\,099 & project\_id, model, dim, vector (FLOAT[384])\\475\end{tabularx}476\end{table}477478\begin{table}[H]479\centering\small480\caption{Vues définies dans \code{spid.duckdb}.}481\begin{tabularx}{\textwidth}{L{3.3cm} Y}482\rowcolor{uqoBleu}\hc{Vue} & \hc{Définition}\\483\code{src\_filings} & \code{read\_parquet(…/parquet/filings/filings.parquet)}\\484\code{src\_sections} & \code{read\_parquet(…/parquet/filing\_sections/filing\_sections.parquet)}\\485\code{src\_companies} & \code{read\_parquet(…/parquet/companies/companies.parquet)}\\486\code{v\_sections} & \code{src\_sections} $\cup$ \code{spid\_sections}, jointes à \code{src\_filings} (cik, ticker, formulaire, date, exercice) et \code{src\_companies} (secteur, sous-industrie, SIC, état)\\487\end{tabularx}488\end{table}489490\begin{alertbox}[Point d'attention : chemins des vues]491Les trois vues \code{src\_*} pointent en dur vers le corpus parquet du nœud maître du cluster (\code{\textasciitilde/UQO\_RESEARCH\_DB/data/parquet/…} sur M3U96b, où le pipeline s'exécute désormais). Sur toute autre machine (copie du laptop, serveur \code{pdb-api}), les huit tables physiques restent parfaitement lisibles, mais toute requête sur \code{v\_sections} ou \code{src\_filings} échoue tant que les vues ne sont pas recréées avec le chemin local du corpus (\code{Store()} les recrée automatiquement à l'ouverture en écriture). Par ailleurs, la colonne \code{fiscal\_year} de \code{project\_mentions} est vide pour les mentions du run de juin~2026 (elle est renseignée depuis octobre~2026) : les analyses temporelles s'appuient sur \code{filing\_date}.492\end{alertbox}493494% ==============================================================================495\section{Portrait statistique des projets}\label{sec:stats}496% ==============================================================================497498\subsection{Couverture temporelle et formulaires}499\begin{figure}[H]500\centering501\includegraphics[width=0.92\textwidth]{fig_mentions_annee}502\caption{Mentions de projets par année de dépôt et par formulaire (\nMentionsHuitK{} en 8-K, \nMentionsDixK{} en 10-K, \nMentionsDixQ{} en 10-Q). Le flux est stable, entre 2\,000 et 2\,800 mentions par an ; 2026 est une année partielle (dépôts jusqu'au 26~mai).}503\label{fig:mentions}504\end{figure}505506\begin{figure}[H]507\centering508\includegraphics[width=\textwidth]{fig_dynamique}509\caption{\emph{Gauche} : nouveaux projets par année de première mention. \emph{Droite} : part des mentions annuelles consacrée à six thèmes émergents. La transformation numérique décolle à partir de 2018, la durabilité culmine en 2023 et les initiatives d'IA passent de moins de 0,3\,\% des mentions avant 2022 à 1,7\,\% en 2025--2026.}510\end{figure}511512\subsection{Types de projets}513\begin{figure}[H]514\centering515\includegraphics[width=\textwidth]{fig_types}516\caption{Répartition des \nProjets{} projets selon les 21~types de la taxonomie et capital annoncé par type. L'intégration post-M\&A domine en nombre (38\,\%) comme en capital, suivie des programmes de capex.}517\end{figure}518519\begin{table}[H]520\centering\small521\caption{Les 21 types de projets : nombre de projets, capital annoncé cumulé (G\$~US) et montant médian par projet (M\$~US, projets avec montant).}522\begin{tabular}{llrrr}523\rowcolor{uqoBleu}\hc{project\_type} & \hc{Libellé} & \hc{Projets} & \hc{Capital (G\$)} & \hc{Médiane (M\$)}\\524\input{tables/tab_types}525\end{tabular}526\end{table}527528\subsection{Secteurs}529\begin{figure}[H]530\centering531\includegraphics[width=\textwidth]{fig_secteurs}532\caption{Projets et capital annoncé par secteur GICS. L'industrie, la santé et les technologies de l'information comptent le plus de projets ; la finance concentre le plus de capital annoncé, du fait des grandes acquisitions bancaires.}533\end{figure}534535\begin{table}[H]536\centering\small537\caption{Répartition par secteur GICS : nombre d'entreprises, de projets, projets par entreprise et capital annoncé.}538\begin{tabular}{lrrrr}539\rowcolor{uqoBleu}\hc{Secteur} & \hc{Entreprises} & \hc{Projets} & \hc{Projets / entr.} & \hc{Capital (G\$)}\\540\input{tables/tab_secteurs}541\end{tabular}542\end{table}543544\begin{figure}[H]545\centering546\includegraphics[width=\textwidth]{fig_heatmap_secteur_type}547\caption{Composition du portefeuille de projets par secteur (parts en pourcentage de chaque ligne). Les secteurs se spécialisent : services publics dans l'infrastructure et la construction d'usines (centrales), santé dans les pipelines de médicaments et lancements de produits, consommation discrétionnaire dans l'expansion géographique, finance et immobilier dans les acquisitions.}548\end{figure}549550\subsection{Statut et cycle de vie}551\begin{figure}[H]552\centering553\includegraphics[width=\textwidth]{fig_statut}554\caption{\emph{Gauche} : statut courant des projets résolus. \emph{Droite} : composition par statut des douze types principaux. Les programmes de capex et les intégrations M\&A sont les plus souvent déclarés terminés ; les programmes de R\&D et la transformation numérique restent majoritairement « en cours ».}555\end{figure}556557\begin{figure}[H]558\centering559\includegraphics[width=\textwidth]{fig_cycle}560\caption{\emph{Gauche} : durée de suivi (écart entre première et dernière année citée) ; \pctMonoAnnee\,\% des projets ne sont cités que sur une année, \pctCinqAns\,\% sur cinq ans ou plus. \emph{Centre} : nombre de mentions fusionnées par projet (échelle log). \emph{Droite} : confiance attribuée par le modèle à chaque mention (moyenne \confMoy{} ; \pctConfHuit\,\% des mentions à 0,80 ou plus).}561\end{figure}562563\begin{table}[H]564\centering\small565\caption{Les dix projets les plus suivis (nombre de mentions et de filings distincts). Les années sont celles citées dans le texte des filings et peuvent inclure des horizons projetés.}566\label{tab:suivis}567\begin{tabularx}{\textwidth}{l Y L{2.4cm} l l r r}568\rowcolor{uqoBleu}\hc{Ticker} & \hc{Projet} & \hc{Type} & \hc{Statut} & \hc{Années} & \hc{Ment.} & \hc{Filings}\\569\input{tables/tab_plus_suivis}570\end{tabularx}571\end{table}572573\subsection{Montants divulgués}574\begin{figure}[H]575\centering576\includegraphics[width=\textwidth]{fig_montants}577\caption{\emph{Gauche} : distribution des montants divulgués (\nAvecMontant{} projets, échelle logarithmique) ; médiane \medianeMontant{}~M\$, moyenne \moyenneMontant{}~M\$. \emph{Droite} : médiane et intervalle interquartile par type. Les intégrations M\&A et les programmes de capex sont d'un ordre de grandeur supérieur aux lancements de produits ou aux implantations ERP.}578\end{figure}579580\begin{table}[H]581\centering\small582\caption{Les quinze projets au montant divulgué le plus élevé (au moins trois mentions, hors programmes de capex). Le montant retenu est le maximum observé dans les mentions du projet ; plusieurs valeurs de cette liste sont manifestement des erreurs d'extraction (valeur d'entreprise ou chiffre d'affaires attribué à une transaction), voir la note ci-dessous.}583\begin{tabularx}{\textwidth}{l Y L{2.6cm} r l r}584\rowcolor{uqoBleu}\hc{Ticker} & \hc{Projet} & \hc{Type} & \hc{Capital (G\$)} & \hc{Années} & \hc{Ment.}\\585\input{tables/tab_top_projets}586\end{tabularx}587\end{table}588589\begin{notebox}[Comment lire le « capital annoncé »]590Le montant d'un projet (\code{total\_amount\_usd}) est le \emph{maximum} des montants divulgués dans ses mentions ; le « capital annoncé » d'un type ou d'un secteur est la somme de ces maxima sur les projets concernés. Ces montants sont auto-déclarés, de portée hétérogène (coût total d'un programme, dépense annuelle, valeur d'une transaction, parfois un chiffre d'entreprise capté par erreur) et un même programme pluriannuel peut apparaître sous plusieurs projets si son nom ou sa localisation varie. Le total de \totalMontant{}~G\$ sur l'ensemble de la base, comme les valeurs par type ou par secteur, se lit donc comme un \textbf{ordre de grandeur supérieur}, non comme un investissement net. Pour une analyse économétrique, les auteurs recommandent de travailler sur le montant \emph{médian} des mentions d'un projet (table \code{project\_timeline}) et d'écarter les valeurs extrêmes.591\end{notebox}592593\subsection{Entreprises}594\begin{figure}[H]595\centering596\includegraphics[width=0.92\textwidth]{fig_entreprises}597\caption{Les vingt entreprises aux portefeuilles de projets les plus fournis, colorées par secteur. Chaque entreprise compte en médiane \projParFirmeMed{} projets (moyenne \projParFirmeMoy, maximum \projParFirmeMax). Les services publics (WEC, PPL, Duke, Xcel, PG\&E) sont surreprésentés : leurs plans d'investissement réglementés sont décrits en détail dans chaque filing.}598\end{figure}599600\begin{table}[H]601\centering\small602\caption{Les quinze entreprises comptant le plus de projets résolus.}603\begin{tabular}{llL{4.2cm}rr}604\rowcolor{uqoBleu}\hc{Ticker} & \hc{Entreprise} & \hc{Secteur} & \hc{Projets} & \hc{Capital (G\$)}\\605\input{tables/tab_entreprises}606\end{tabular}607\end{table}608609\subsection{Localisations, technologies et partenaires}610\begin{figure}[H]611\centering612\includegraphics[width=\textwidth]{fig_tech_localisations}613\caption{\emph{Gauche} : les vingt technologies les plus citées (\pctAvecTech\,\% des projets en portent au moins une ; \nTech{} libellés distincts). \emph{Droite} : les vingt localisations canoniques les plus fréquentes (\pctAvecLoc\,\% des projets sont localisés ; \nLoc{} localisations distinctes).}614\end{figure}615616% ==============================================================================617\section{Graphe de connaissances et espace sémantique}618% ==============================================================================619\begin{figure}[H]620\centering621\includegraphics[width=\textwidth]{fig_graphe}622\caption{\emph{Gauche} : composition du graphe (183\,472 nœuds ; arêtes : 121\,099 \code{owns}, 54\,583 \code{located\_in}, 28\,774 \code{uses}). \emph{Droite} : distribution des degrés entrants des localisations et technologies (log-log) ; la queue lourde traduit quelques hubs (États-Unis, Texas, Chine ; IA, énergie renouvelable, logiciel) reliés à des centaines de projets.}623\end{figure}624625Le graphe permet des requêtes impossibles sur des tables plates : « quelles entreprises construisent au Texas des installations utilisant des batteries ? », « quels partenaires reviennent dans les projets d'IA du secteur financier ? ». L'export Cypher (\code{data/exports/kg\_import.cypher}) charge le graphe dans Neo4j en une commande. Les embeddings complètent le graphe par une recherche \emph{par le sens} : deux projets décrits avec des mots différents mais un même objet (une « gigafactory » et une « usine de cellules de batteries ») se retrouvent voisins dans l'espace à 384~dimensions. Le projet de recherche \code{research/} exploite ces deux couches (détection de communautés technologiques, regroupement $K$-means et projection t-SNE des projets).626627% ==============================================================================628\section{Qualité des données et limites}\label{sec:limites}629% ==============================================================================630\begin{itemize}631  \item \textbf{Divulgation, non réalité.} SPID mesure ce que les entreprises \emph{disent} de leurs projets dans leurs filings. Une initiative jamais évoquée est invisible, et les incitations à divulguer varient selon les secteurs (les services publics réglementés décrivent tout, les sociétés technologiques peu).632  \item \textbf{Montants.} Auto-déclarés, hétérogènes en portée et absents pour la moitié des projets (voir la note de la section~\ref{sec:stats}). Quelques valeurs aberrantes subsistent (montant d'un rachat d'actions ou d'une valeur d'entreprise attribué à un « projet »).633  \item \textbf{Échantillon non historique.} Les listes S\&P~500 (mai~2026) et Russell~3000 (positions IWV d'octobre~2026) sont des instantanés : les sociétés sorties des indices entre 2010 et 2026 (faillites, acquisitions, déclassements) sont absentes, ce qui introduit un biais de survie.634  \item \textbf{Tableaux des 10-K supprimés.} L'ingestion SPID retire les tableaux HTML ; les montants présentés en tableau (plans de capex chiffrés, par exemple) ne sont captés que s'ils sont repris dans la prose.635  \item \textbf{Extraction par LLM.} Faux positifs (formules génériques prises pour des projets) et faux négatifs (projets décrits sans vocabulaire de projet) existent. Le seuil de confiance, l'ancrage textuel obligatoire et la température nulle les réduisent, mais aucun échantillon étiqueté à la main d'une taille suffisante ne permet encore d'estimer précision et rappel.636  \item \textbf{Résolution heuristique.} Le regroupement par entreprise, type et nom normalisé peut scinder un même projet nommé différemment d'un filing à l'autre (surestimation du nombre de projets) ou fusionner deux projets homonymes (sous-estimation). Le nom d'un projet peut aussi être une reformulation du modèle plutôt qu'un nom officiel.637  \item \textbf{Années citées.} \code{first\_year} et \code{last\_year} proviennent des années mentionnées dans le texte : elles peuvent précéder la date du dépôt (rappel historique) ou lui succéder (horizon projeté, jusqu'en 2033 ou 2040). Pour dater l'observation, préférer \code{first\_seen} et \code{last\_seen}.638  \item \textbf{Couverture des 10-Q.} Depuis l'extension d'octobre~2026, les 10-Q de 2\,494 entreprises sont segmentés et extraits (578\,793 sections, 52\,\% des sections éligibles) ; le run initial de juin~2026 n'en couvrait que 84.639  \item \textbf{Échantillon.} 2\,564 sociétés cotées aux États-Unis, des grandes aux petites capitalisations ; les émetteurs étrangers déposant des 20-F/40-F (65 sociétés de l'ETF), les sociétés privées et les micro-capitalisations hors ETF restent hors champ.640  \item \textbf{Vues cassées.} Les vues \code{src\_*} doivent être recréées avec le nouveau chemin du corpus avant toute ré-exécution du pipeline (section~\ref{sec:schema}).641\end{itemize}642643% ==============================================================================644\section{Reproduire ce rapport}645% ==============================================================================646\begin{fichier}[docs/rapport\_uqo/]647\begin{Verbatim}648python3 make_figures.py          # lit data/db/spid.duckdb, écrit figures/*.pdf et tables/*.tex649latexmk -lualatex rapport_spid.tex650\end{Verbatim}651\end{fichier}652Toutes les valeurs numériques du texte (macros \code{\textbackslash nProjets}, \code{\textbackslash medianeMontant}, etc.) et tous les tableaux sont régénérés depuis la base par le script ; aucun chiffre n'est saisi à la main.653654% ==============================================================================655\appendix656\section{Taxonomie des 21 types de projets}657% ==============================================================================658La taxonomie (\code{spid/taxonomy.py}) est un vocabulaire contrôlé de 21~catégories mutuellement exclusives. Chaque catégorie est dotée d'une description transmise au modèle et de mots-clés servant au \emph{gate}, au backend déterministe et à la correspondance floue du post-traitement.659660\begin{table}[H]661\centering\small662\begin{tabularx}{\textwidth}{L{4.1cm} Y}663\rowcolor{uqoBleu}\hc{Type} & \hc{Définition retenue}\\664\code{manufacturing\_expansion} & Extension de la capacité de production d'un site existant (lignes, équipements, quarts).\\665\code{plant\_construction} & Construction d'une nouvelle usine, centrale, raffinerie ou installation industrielle.\\666\code{data\_center} & Construction, extension ou location de centres de données et d'infrastructures de calcul.\\667\code{cloud\_migration} & Migration de systèmes ou de charges de travail vers l'infonuagique.\\668\code{ai\_initiative} & Programme d'intelligence artificielle ou d'apprentissage automatique (produits, plateformes, modèles).\\669\code{digital\_transformation} & Modernisation numérique transversale (plateformes, canaux, processus).\\670\code{erp\_implementation} & Implantation ou remplacement d'un système ERP ou de gestion intégrée.\\671\code{rd\_program} & Programme de recherche et développement identifié (hors médicaments).\\672\code{product\_launch} & Lancement commercial d'un produit ou service nouveau.\\673\code{drug\_pipeline} & Candidat-médicament, essai clinique ou dépôt réglementaire.\\674\code{ma\_integration} & Acquisition, cession, fusion ou intégration post-transaction.\\675\code{geographic\_expansion} & Entrée sur un nouveau marché géographique, ouverture de magasins ou de bureaux.\\676\code{capex\_program} & Programme d'investissement pluriannuel chiffré (plan de capex).\\677\code{supply\_chain} & Réorganisation de la chaîne d'approvisionnement, logistique, entrepôts.\\678\code{automation} & Automatisation industrielle ou robotique de processus.\\679\code{sustainability} & Programme environnemental ou de durabilité (émissions, déchets, eau).\\680\code{energy\_transition} & Production renouvelable, stockage, décarbonation, électrification.\\681\code{infrastructure} & Réseaux, pipelines, lignes de transport, infrastructures lourdes.\\682\code{cost\_reduction} & Programme de réduction des coûts, restructuration, fermetures.\\683\code{partnership} & Partenariat stratégique, coentreprise, alliance, contrat majeur.\\684\code{technology\_deployment} & Déploiement d'une technologie identifiée ne relevant d'aucune autre catégorie (type par défaut).\\685\end{tabularx}686\end{table}687688\section{Fichiers du dépôt \code{project-db/}}689\begin{table}[H]690\centering\small691\begin{tabularx}{\textwidth}{L{5.2cm} Y}692\rowcolor{uqoBleu}\hc{Chemin} & \hc{Rôle}\\693\code{spid/config.py} & Chargement de \code{.env}, chemins, journalisation.\\694\code{spid/store.py} & Connexion DuckDB, création du schéma et des vues, primitives d'écriture.\\695\code{spid/taxonomy.py} & Les 21 types, descriptions, mots-clés, correspondance floue.\\696\code{spid/ingest.py} & Nettoyage et sectionnement des 10-K bruts.\\697\code{spid/extract/base.py, llm.py, rules.py} & Interface d'extraction, backend LLM (prompt, gate, focus), backend déterministe.\\698\code{spid/pipeline.py} & Moteur d'extraction : sélection des sections, parallélisme, écriture des mentions.\\699\code{spid/resolve.py} & Fusion des mentions en projets et chronologies.\\700\code{spid/graph.py} & Graphe de connaissances et exports parquet/Cypher.\\701\code{spid/embed.py}, \code{spid/search.py} & Embeddings MiniLM, recherche sémantique et filtrée.\\702\code{spid/analytics.py}, \code{spid/api.py}, \code{spid/\_\_main\_\_.py} & Agrégats, API FastAPI, interface en ligne de commande.\\703\code{run\_full\_extract.py} & Pilote d'extraction par lots de 15~CIK avec points de reprise.\\704\code{data/db/spid.duckdb} & La base (3,2~Go).\\705\code{data/exports/} & \code{kg\_nodes.parquet}, \code{kg\_edges.parquet}, \code{kg\_import.cypher}.\\706\code{logs/} & \code{ingest.log}, \code{extract.log}, \code{post.log}, \code{extract\_done\_ciks.txt}.\\707\code{research/} & Projet de recherche aval : scripts 01--10, figures, tableaux et article (\code{paper/main.pdf}).\\708\code{docs/} & Documentation, dont ce rapport (\code{docs/rapport\_uqo/}).\\709\end{tabularx}710\end{table}711712\end{document}713
Files · main
Menu

Theme