This commit is contained in:
2025-09-14 22:12:09 +02:00
parent 8eaa75ba5f
commit 8d30a0a4bc
11 changed files with 6691 additions and 6582 deletions

View File

@@ -0,0 +1,55 @@
Parfait 👍 Alors, puisque vous avez vos vecteurs nutritionnels dans une colonne nutrition vector (normalisés avec un Z-score), vous pouvez utiliser lextension pgvector pour faire une classification KNN directement dans PostgreSQL.
Voici un exemple de requête complète en k-nearest neighbors (kNN) :
-- Supposons que vous avez :
-- table produit(id serial, nom text, famille text, nutrition vector)
-- Exemple : on veut classifier un produit inconnu
```sql
WITH nouveau AS (
SELECT
ARRAY[
80, -- énergie (kcal/100g)
3.5, -- protéines
12, -- glucides
11, -- sucres
2.0, -- graisses
0.8, -- graisses_saturées
0.1, -- sel
1.2, -- fibres
5, -- nutriscore numérique
0 -- nombre d'additifs
]::vector AS nutrition
)
SELECT p.famille,
COUNT(*) AS voisins,
ROUND(AVG(p.nutrition <-> n.nutrition)::numeric, 3) AS distance_moyenne
FROM produit p
JOIN nouveau n ON true
ORDER BY p.nutrition <-> n.nutrition -- tri par distance euclidienne
LIMIT 5; -- on récupère les 5 plus proches voisins
```
```sql
Étape suivante : classification majoritaire
Pour prédire la famille (yaourt ou confiture), on peut compter la famille majoritaire parmi les k plus proches voisins :
WITH nouveau AS (
SELECT ARRAY[80, 3.5, 12, 11, 2.0, 0.8, 0.1, 1.2, 5, 0]::vector AS nutrition
),
voisins AS (
SELECT p.famille
FROM produit p
JOIN nouveau n ON true
ORDER BY p.nutrition <-> n.nutrition
LIMIT 5 -- k=5
)
SELECT famille, COUNT(*) AS occurrences
FROM voisins
GROUP BY famille
ORDER BY occurrences DESC
LIMIT 1; -- famille prédite
```

View File

@@ -1,6 +1,11 @@
-- 1. Ajouter les extensions
create extension if not exists vector;
create extension if not exists isn;
-- 2. Créer la table des produits
create table produit (
id bigint primary key,
ean13 EAN13 null
ean13 EAN13 null,
nom text not null,
marque text null,
categorie text null,
@@ -31,6 +36,7 @@ create table produit (
vitamin_c float null
);
-- 3. ajouter les commentaires
comment on column produit.potassium IS 'K⁺ en mg/L';
comment on column produit.calcium IS 'Ca²⁺ en mg/L';
comment on column produit.magnesium IS 'Mg²⁺ en mg/L';
@@ -39,15 +45,51 @@ comment on column produit.chlorure IS 'Cl⁻ en mg/L';
comment on column produit.sulfate IS 'SO₄²⁻ en mg/L';
comment on column produit.nitrate IS 'NO₃⁻ en mg/L';
comment on column produit.hydrogenocarbonate IS 'HCO₃⁻ en mg/L';
comment on column produit.silice IS s'SiO₂ en mg/L';
comment on column produit.silice IS 'SiO₂ en mg/L';
comment on column produit.fluor IS 'F en mg/L';
\COPY produit FROM '/tmp/produits/cereales_petitdejeuner.csv' (FORMAT CSV, header, ENCODING 'UTF8');
\COPY produit FROM '/tmp/produits/confiture.csv' (FORMAT CSV, header, ENCODING 'UTF8');
\COPY produit FROM '/tmp/produit.csv' (FORMAT CSV, header, ENCODING 'UTF8');
alter table produits
-- 5. ajouter une colonne vecteur
alter table produit
add column nutrition vector(10);
update produits
set nutrition = ARRAY[energie, proteines, glucides, sucres, graisses, graisses_saturees, sel, fibres, nutriscore, additifs]::vector;
-- 6. Création de lindex ivfflat
create index produit_nutrition_hnsw
on produit
using hnsw (nutrition vector_l2_ops)
with (m = 16, ef_construction = 200);
-- 7. calculer la moyenne et l'écart-type pour chaque colonne, puis construire le vecteur :
WITH stats AS (
SELECT
AVG(energie) AS mu_energie, STDDEV_SAMP(energie) AS sigma_energie,
AVG(proteines) AS mu_proteines, STDDEV_SAMP(proteines) AS sigma_proteines,
AVG(glucides) AS mu_glucides, STDDEV_SAMP(glucides) AS sigma_glucides,
AVG(sucres) AS mu_sucres, STDDEV_SAMP(sucres) AS sigma_sucres,
AVG(graisses) AS mu_graisses, STDDEV_SAMP(graisses) AS sigma_graisses,
AVG(graisses_saturees) AS mu_graisses_saturees, STDDEV_SAMP(graisses_saturees) AS sigma_graisses_saturees,
AVG(sel) AS mu_sel, STDDEV_SAMP(sel) AS sigma_sel,
AVG(fibres) AS mu_fibres, STDDEV_SAMP(fibres) AS sigma_fibres,
AVG(nutriscore) AS mu_nutriscore, STDDEV_SAMP(nutriscore) AS sigma_nutriscore,
AVG(additifs) AS mu_additifs, STDDEV_SAMP(additifs) AS sigma_additifs
FROM produit
)
UPDATE produit
SET nutrition = (
SELECT ARRAY[
((COALESCE(energie, mu_energie) - mu_energie) / NULLIF(sigma_energie,0)),
((COALESCE(proteines, mu_proteines) - mu_proteines) / NULLIF(sigma_proteines,0)),
((COALESCE(glucides, mu_glucides) - mu_glucides) / NULLIF(sigma_glucides,0)),
((COALESCE(sucres, mu_sucres) - mu_sucres) / NULLIF(sigma_sucres,0)),
((COALESCE(graisses, mu_graisses) - mu_graisses) / NULLIF(sigma_graisses,0)),
((COALESCE(graisses_saturees, mu_graisses_saturees) - mu_graisses_saturees) / NULLIF(sigma_graisses_saturees,0)),
((COALESCE(sel, mu_sel) - mu_sel) / NULLIF(sigma_sel,0)),
((COALESCE(fibres, mu_fibres) - mu_fibres) / NULLIF(sigma_fibres,0)),
((COALESCE(nutriscore, mu_nutriscore) - mu_nutriscore) / NULLIF(sigma_nutriscore,0)),
((COALESCE(additifs, mu_additifs) - mu_additifs) / NULLIF(sigma_additifs,0))
]::vector
FROM stats
);