Une méthode d'optimisation où des dizaines de solutions, les particules, se déplacent ensemble dans l'espace des possibles. Chacune se souvient de sa meilleure position et connaît la meilleure du groupe, et ajuste sa trajectoire entre les deux. Efficace pour régler des quantités continues quand la fonction à optimiser n'a pas de formule simple.
Une nuée d'oiseaux cherche de la nourriture dans un champ. Chaque oiseau se souvient du meilleur endroit qu'il a vu et voit où le groupe a trouvé le plus. Il vole vers un mélange des deux, et la nuée finit par converger sur le meilleur coin.
30 particules sont placées au hasard. Chacune est une solution possible, ici une répartition du budget entre quatre canaux.
Nouvelle vitesse = une part de l'ancienne (inertie) + une attirance vers son propre record + une attirance vers le record du groupe, avec un dosage aléatoire à chaque pas.
Chaque particule évalue sa nouvelle position. Si elle bat son record ou celui du groupe, le record change. On s'arrête après un nombre fixé d'itérations.
TV, Search, Social et Affichage, chacun avec sa courbe de réponse en S : presque rien en dessous d'un seuil d'investissement, puis une montée, puis la saturation. Dans la réalité, ces courbes sortent d'un modèle de marketing mix ; ici, elles sont simulées.
Sur l'exemple simulé en Python, l'essaim place 81 k€ en TV, 32 k€ en Search, 37 k€ en Social et coupe l'Affichage, qui n'atteint jamais son seuil d'efficacité. Ventes attendues : 622 k€, contre 572 k€ pour une répartition égale.
On compare les ventes attendues à celles du plan en place ou d'une répartition simple. Les courbes de réponse étant elles-mêmes estimées, on teste aussi la robustesse : la répartition change-t-elle beaucoup si une courbe bouge de 10 % ?
Noms donnés pour R (pso). En Python, la bibliothèque pyswarms, ou une boucle NumPy comme ici.
20 à 50 particules. Plus il y en a, plus l'exploration est large, et plus chaque itération coûte.
Autour de 0,7. Forte, les particules gardent leur élan et explorent ; faible, elles se posent vite, parfois trop tôt.
Poids de l'attirance vers le record personnel et vers le record du groupe, souvent autour de 1,5 chacun. Un groupe trop attirant fait converger l'essaim prématurément.
Les particules sont maintenues dans des bornes. Ici, la contrainte de budget est respectée par construction : on optimise des poids, ramenés ensuite au budget total.
# Répartition d'un budget média : essaims particulaires (PSO) en R
library(pso)
# Courbes de réponse simulées (ventes en k€ selon l'investissement en k€), forme en S
canaux <- c("TV", "Search", "Social", "Affichage")
plafond <- c(420, 260, 200, 150) # ventes maximales atteignables par canal
demi <- c(60, 15, 25, 30) # investissement qui donne la moitié du plafond
budget <- 150
ventes <- function(poids) { # poids positifs -> répartition du budget
invest <- budget * poids / sum(poids)
sum(plafond * invest^2 / (invest^2 + demi^2))
}
# 30 particules, 200 itérations ; psoptim minimise, on lui donne donc l'opposé des ventes
set.seed(42)
res <- psoptim(par = rep(NA, 4), fn = function(p) -ventes(p), lower = 1e-6, upper = 1,
control = list(s = 30, maxit = 200))
repartition <- setNames(round(budget * res$par / sum(res$par), 1), canaux)
print(repartition)
cat("Ventes attendues :", round(-res$value, 1), "k€\n")
cat("Répartition égale :", round(ventes(rep(1, 4)), 1), "k€\n")
# Répartition d'un budget média : essaims particulaires (PSO) en Python
import numpy as np
# Courbes de réponse simulées (ventes en k€ selon l'investissement en k€), forme en S
canaux = ["TV", "Search", "Social", "Affichage"]
plafond = np.array([420, 260, 200, 150]) # ventes maximales atteignables par canal
demi = np.array([60, 15, 25, 30]) # investissement qui donne la moitié du plafond
budget = 150
def ventes(poids): # poids positifs -> répartition du budget
invest = budget * poids / poids.sum()
return np.sum(plafond * invest ** 2 / (invest ** 2 + demi ** 2))
rng = np.random.default_rng(42)
n, dim = 30, 4
pos = rng.uniform(0.01, 1, (n, dim))
vit = np.zeros((n, dim))
perso, perso_val = pos.copy(), np.array([ventes(p) for p in pos])
for it in range(200):
groupe = perso[perso_val.argmax()] # meilleure position trouvée par l'essaim
r1, r2 = rng.uniform(size=(2, n, dim))
# Inertie + attirance vers son propre record + attirance vers le record du groupe
vit = 0.7 * vit + 1.5 * r1 * (perso - pos) + 1.5 * r2 * (groupe - pos)
pos = np.clip(pos + vit, 1e-6, 1)
val = np.array([ventes(p) for p in pos])
mieux = val > perso_val
perso[mieux], perso_val[mieux] = pos[mieux], val[mieux]
meilleur = perso[perso_val.argmax()]
print("Répartition (k€) :", dict(zip(canaux, (budget * meilleur / meilleur.sum()).round(1).tolist())))
print("Ventes attendues :", round(perso_val.max(), 1), "k€")
print("Répartition égale :", round(ventes(np.ones(dim)), 1), "k€")
C'est une métaheuristique proposée par Kennedy et Eberhart en 1995. Un ensemble de solutions, les particules, se déplace dans l'espace de recherche. Chaque particule combine son élan, l'attirance vers la meilleure position qu'elle a trouvée et l'attirance vers la meilleure position trouvée par le groupe.
Le PSO est en général plus simple et plus rapide sur les problèmes à variables continues, comme des montants ou des dosages. L'algorithme génétique s'adapte plus naturellement aux problèmes discrets ou combinatoires. Les deux restent des heuristiques : aucun ne garantit l'optimum.
Trois approches courantes : reformuler le problème pour que la contrainte soit respectée par construction, comme ici avec des poids ramenés au budget ; ajouter une pénalité à la fonction quand la contrainte est violée ; ou ramener chaque particule dans la zone autorisée après chaque déplacement.
Sélection, croisement, mutation : mieux adaptés aux choix discrets comme une liste de projets.
Voir la fiche → une seule solutionFait évoluer une solution unique en acceptant parfois de reculer. Très utilisé pour les tournées et plannings.
Voir la fiche → quand chaque essai coûte cherChoisit chaque essai avec soin grâce à un modèle du score. Bien moins d'évaluations.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus