Incertitude de prédiction & confiance en R : intervalles conformes
Une prédiction ponctuelle ne raconte que la moitié de l’histoire — entourez la prédiction de n’importe quel modèle d’un intervalle statistiquement valide, et signalez les prédictions auxquelles vous ne devriez pas vous fier
Un guide pratique de l’incertitude de prédiction en R : construisez des intervalles de prédiction sans hypothèse de distribution autour de N’IMPORTE QUEL modèle avec la prédiction conforme (probably::int_conformal_split() et int_conformal_cv()), vérifiez que la garantie de couverture à 90 % tient réellement sur des données de test, et signalez les classifications incertaines avec une zone équivoque (make_two_class_pred()). Illustré sur les données immobilières de Boston avec le package probably de tidymodels — la leçon la plus approfondie sur « peut-on se fier à cette prédiction ? » du pilier.
Date de publication
25 juin 2026
Modifié
7 juillet 2026
AstuceL’essentiel à retenir
Une prédiction ponctuelle sans incertitude ne raconte que la moitié de l’histoire. « Ce logement vaut $24k » est bien moins utile que « ce logement vaut $24k, et nous sommes sûrs à 90 % que la vraie valeur se situe entre $16k et $32k. »
La prédiction conforme transforme la prédiction ponctuelle de n’importe quel modèle en un intervalle de prédiction statistiquement valide — sans hypothèse de distribution (aucune hypothèse de normalité) et indépendant du modèle (fonctionne autour d’un modèle linéaire, d’une forêt aléatoire, de n’importe quoi). Il s’accompagne d’une garantie de couverture en échantillon fini : demandez des intervalles à 90 % et environ 90 % d’entre eux contiendront vraiment la vérité.
probably::int_conformal_split() est l’outil de référence : ajustez sur une portion, calibrez sur une portion mise de côté, puis prédisez des intervalles sur de nouvelles données. int_conformal_cv() fait la même chose en utilisant la validation croisée, vous évitant ainsi de sacrifier un jeu de calibration.
Vérifiez toujours la couverture. La garantie est la théorie ; la preuve, c’est de réexécuter le modèle et de compter combien de fois l’intervalle piège réellement la vraie valeur. The runtime is the judge.
Une seconde question de confiance est « cette prédiction devrait-elle seulement être faite ? » Pour la classification, la zone équivoque (make_two_class_pred() avec un buffer) signale les cas trop proches de la frontière de décision pour être tranchés avec assurance — le modèle s’abstient au lieu de deviner.
Ensemble, elles répondent à la question peut-on se fier à une prédiction, de façon exécutable — ce qu’un chatbot générique peut affirmer mais ne peut pas prouver sur vos données.
Chaque modèle prédictif que vous avez construit jusqu’ici renvoie un seul nombre pour chaque nouveau cas : un prix de logement prédit, une probabilité de diabète prédite, une classe prédite. Ce nombre arrive avec la même assurance, que le cas se situe en plein cœur de vos données d’entraînement ou loin en terrain inconnu. Un modèle vous donnera toujours une réponse. Il ne vous dira pas, de lui-même, si cette réponse vaut quoi que ce soit.
Prenez un modèle qui prédit les prix des logements et renvoie $24,000 pour un nouveau bien. Le vendeur devrait-il afficher $24k ? Cela dépend entièrement de l’incertitude : si le modèle veut dire « quelque part entre $23k et $25k », c’est une estimation exploitable ; s’il veut dire « quelque part entre $8k et $40k », ce n’est guère mieux qu’une supposition. La prédiction ponctuelle est identique dans les deux cas — seul l’intervalle distingue une réponse fiable d’une réponse inutile.
Cette leçon enseigne deux outils complémentaires, tous deux issus du package probably de tidymodels, pour entourer les prédictions d’une incertitude honnête :
Les intervalles de prédiction conformes (régression) — une manière sans hypothèse de distribution et indépendante du modèle d’entourer la prédiction de n’importe quel modèle d’un intervalle avec un taux de couverture garanti. Nous les construisons, puis vérifions que la garantie tient en comptant.
La zone équivoque (classification) — signaler les prédictions situées trop près de la frontière de décision pour être dignes de confiance, afin que le modèle puisse s’abstenir plutôt que de deviner.
C’est l’expression la plus profonde de l’atout différenciateur de Datanovia : non pas ce que le modèle prédit, mais si vous pouvez vous fier à la prédiction, démontré avec du code que vous pouvez exécuter. Un chatbot généraliste peut vous dire qu’une prédiction est incertaine ; il ne peut pas prouver la couverture sur vos données de test. Le runtime, lui, le peut.
NotePrérequis
Nous utilisons le workflow découpage → ajustement → prédiction de construire des modèles avec tidymodels et les idées de rééchantillonnage de validation croisée. Si ces notions ne vous sont pas familières, commencez par là ; cette leçon suppose que vous savez déjà ajuster un modèle et prédire sur de nouvelles données.
Les données et un modèle de référence
Nous travaillons avec Boston (le package MASS) : 506 secteurs de recensement de Boston avec 13 prédicteurs numériques (taux de criminalité, nombre moyen de pièces, ratio élèves-enseignant, …) et la variable de sortie medv — la valeur médiane des logements en milliers de $. La régression est le domaine où les intervalles de prédiction sont les plus clairs : la sortie est un nombre sur une échelle réelle, donc un intervalle a un sens immédiat et physique (« entre $16k et $32k »).
Nous mettons de côté un jeu de test auquel nous ne toucherons jamais jusqu’à la toute fin, puis ajustons un simple modèle linéaire et examinons ses prédictions ponctuelles :
library(MASS)library(rsample)library(parsnip)library(workflows)library(recipes)data("Boston", package ="MASS")set.seed(2025)split <-initial_split(Boston, prop =0.75)train_data <-training(split)test_data <-testing(split)# A baseline linear model via the tidymodels workflowwf <-workflow() |>add_recipe(recipe(medv ~ ., data = train_data)) |>add_model(linear_reg() |>set_engine("lm"))fit_lm <-fit(wf, data = train_data)# Point predictions on the held-out test setpoint_pred <-predict(fit_lm, test_data)head(point_pred, 4)
Chaque secteur de test possède désormais une seule valeur médiane prédite. Utile — mais de combien chacune peut-elle s’écarter ? Le moteur lmpeut produire un intervalle de prédiction classique à 95 % (predict(..., type = "pred_int")), mais cet intervalle se fie aux hypothèses du modèle : des résidus normaux et homoscédastiques. Quand ces hypothèses fléchissent — et sur des données réelles elles fléchissent toujours un peu — la couverture annoncée de l’intervalle est une promesse qu’il pourrait ne pas tenir. La prédiction conforme tient la promesse sans ces hypothèses.
Prédiction conforme : un intervalle sans hypothèse de distribution autour de n’importe quel modèle
L’idée derrière la prédiction conforme par découpage est d’une simplicité désarmante. Mettez de côté une nouvelle portion de données que le modèle n’a jamais vue à l’entraînement — le jeu de calibration. Exécutez le modèle dessus et examinez les résidus absolus\(|y - \hat{y}|\) : à quel point le modèle s’est trompé, cas par cas. Pour obtenir un intervalle à 90 %, prenez le 90e centile de ces erreurs — appelez-le \(q\) — et formez l’intervalle de chaque nouvelle prédiction comme \(\hat{y} \pm q\). Parce que les erreurs de calibration sont échangeables avec les erreurs sur les données futures, l’ intervalle est garanti de contenir la vérité environ 90 % du temps. Aucune distribution n’est supposée ; les données se calibrent elles-mêmes.
probably::int_conformal_split() fait exactement cela. Il lui faut le workflow ajusté et un jeu de calibration que le modèle n’a pas vu, alors nous découpons les données d’entraînement en une portion d’ajustement et une portion de calibration, puis réajustons sur la plus petite portion d’ajustement :
library(MASS)library(rsample)library(parsnip)library(workflows)library(recipes)library(probably)data("Boston", package ="MASS")set.seed(2025)split <-initial_split(Boston, prop =0.75)train_data <-training(split)test_data <-testing(split)# Carve TRAIN into a fit slice and a calibration slice (the model must not see calibration data)set.seed(99)cal_split <-initial_split(train_data, prop =0.70)fit_data <-training(cal_split)cal_data <-testing(cal_split)wf <-workflow() |>add_recipe(recipe(medv ~ ., data = fit_data)) |>add_model(linear_reg() |>set_engine("lm"))fit_split <-fit(wf, data = fit_data)# Build the split-conformal object, then predict 90% intervals on the test setconf_split <-int_conformal_split(fit_split, cal_data = cal_data)pred_int <-predict(conf_split, test_data, level =0.90)head(pred_int, 4)
Chaque secteur de test porte désormais trois nombres : la prédiction ponctuelle .pred et les bornes inférieure/supérieure d’un intervalle à 90 %. L’intervalle a une interprétation limpide — « nous sommes sûrs à 90 % que la vraie valeur médiane de ce secteur se situe dans cette plage » — et il a gagné cette affirmation à partir des résidus de calibration, non d’une hypothèse sur leur forme.
NoteLes intervalles conformes par découpage ont une largeur constante — et c’est là le compromis
Remarquez que l’intervalle a la même largeur pour chaque logement (\(\hat{y} \pm q\), avec un unique \(q\)). La prédiction conforme par découpage achète sa garantie sans hypothèse de distribution au prix d’un intervalle de largeur constante — elle vous indique la bande d’erreur typique, non une bande propre à chaque cas. Si vous avez besoin de largeurs adaptatives (étroites là où le modèle est confiant, larges là où il ne l’est pas), utilisez la régression quantile conformalisée via int_conformal_quantile(), qui ajuste d’abord un modèle quantile ; elle est plus lourde mais les intervalles respirent au gré de la difficulté locale. Nous utilisons ici la version à largeur constante car c’est l’illustration la plus claire de la garantie.
Le geste signature : vérifier la couverture
Voici la partie qu’un chatbot ne peut pas faire à votre place. Le 90 % est une garantie théorique ; la seule façon de vous y fier sur votre problème est d’exécuter le modèle et de compter combien de fois l’intervalle contient réellement la vérité. Nous avons mis le jeu de test de côté précisément pour cela. Nous marquons chaque secteur comme couvert si sa vraie medv tombe à l’intérieur de son intervalle, puis nous comptons :
library(MASS)library(rsample)library(parsnip)library(workflows)library(recipes)library(probably)data("Boston", package ="MASS")set.seed(2025)split <-initial_split(Boston, prop =0.75)train_data <-training(split); test_data <-testing(split)set.seed(99)cal_split <-initial_split(train_data, prop =0.70)fit_data <-training(cal_split); cal_data <-testing(cal_split)wf <-workflow() |>add_recipe(recipe(medv ~ ., data = fit_data)) |>add_model(linear_reg() |>set_engine("lm"))fit_split <-fit(wf, data = fit_data)conf_split <-int_conformal_split(fit_split, cal_data = cal_data)pred_int <-predict(conf_split, test_data, level =0.90)# Did the true value land inside the 90% interval?res <-cbind(test_data["medv"], pred_int)res$covered <- res$medv >= res$.pred_lower & res$medv <= res$.pred_upperempirical_coverage <-mean(res$covered)mean_width <-mean(res$.pred_upper - res$.pred_lower)round(c(target =0.90, empirical = empirical_coverage, mean_width = mean_width), 3)
target empirical mean_width
0.900 0.921 15.240
La couverture empirique tombe juste autour des 90 % demandés — la garantie tient sur des données que le modèle n’a jamais vues. La largeur moyenne nous indique le prix de cette couverture : une bande d’environ $15k de large. (N’attendez pas exactement 0.90 — la couverture est elle-même une quantité aléatoire sur un jeu de test fini ; ce qui compte, c’est qu’elle soit proche et non, disons, de 0.6.) Cette étape de comptage est tout l’enjeu de la leçon : l’intervalle n’est digne de confiance que parce que nous avons réexécuté le modèle et l’avons vu tenir sa promesse.
Place maintenant à la figure qui rend l’incertitude tangible. Nous trions les secteurs de test selon leur valeur prédite et dessinons chacun comme un point avec son intervalle ; la vraie valeur se pose par-dessus, colorée selon que l’intervalle l’a attrapée ou non :
library(MASS)library(rsample)library(parsnip)library(workflows)library(recipes)library(probably)library(ggplot2)data("Boston", package ="MASS")set.seed(2025)split <-initial_split(Boston, prop =0.75)train_data <-training(split); test_data <-testing(split)set.seed(99)cal_split <-initial_split(train_data, prop =0.70)fit_data <-training(cal_split); cal_data <-testing(cal_split)wf <-workflow() |>add_recipe(recipe(medv ~ ., data = fit_data)) |>add_model(linear_reg() |>set_engine("lm"))fit_split <-fit(wf, data = fit_data)conf_split <-int_conformal_split(fit_split, cal_data = cal_data)pred_int <-predict(conf_split, test_data, level =0.90)res <-cbind(test_data["medv"], pred_int)res$covered <-ifelse(res$medv >= res$.pred_lower & res$medv <= res$.pred_upper,"inside interval", "missed")res <- res[order(res$.pred), ]res$rank <-seq_len(nrow(res))ggplot(res, aes(x = rank)) +geom_ribbon(aes(ymin = .pred_lower, ymax = .pred_upper),fill ="#3a86d4", alpha =0.15) +geom_line(aes(y = .pred), color ="#3a86d4", linewidth =0.8) +geom_point(aes(y = medv, color = covered), size =1.4) +scale_color_manual(values =c("inside interval"="#1f9e6b", "missed"="#e2542f")) +labs(x ="Held-out tracts, sorted by predicted value",y ="Median home value ($1000s)", color =NULL,subtitle ="90% conformal interval (band) vs the true value (points)") +theme_minimal() +theme(legend.position ="top")
Lisez l’image : la ligne bleue est la prédiction ponctuelle de chaque secteur, la bande ombrée est son intervalle conforme à 90 %, et chaque point est une vraie valeur. La plupart des points tombent à l’intérieur de la bande (vert) ; une petite minorité s’échappe (rouge) — et cette minorité est, par construction, d’environ un sur dix. Le graphique transforme une garantie abstraite en quelque chose que vous pouvez voir : la bande est assez large pour être honnête, les évadés sont rares, et vous savez désormais à quel point vous fier à une prédiction quelconque de ce modèle.
Une alternative économe en données : la prédiction conforme par validation croisée
La prédiction conforme par découpage sacrifie une part des données à la calibration. Quand les données sont rares, la prédiction conforme par validation croisée (int_conformal_cv()) la récupère : elle exécute une validation croisée, rassemble les résidus hors-pli de chaque pli comme réservoir de calibration, et ne met jamais définitivement de données de côté. Vous lui fournissez un résultat de rééchantillonnage qui a sauvegardé ses prédictions et conservé le workflow ajusté de chaque pli :
library(MASS)library(rsample)library(parsnip)library(workflows)library(recipes)library(tune)library(probably)data("Boston", package ="MASS")set.seed(2025)split <-initial_split(Boston, prop =0.75)train_data <-training(split); test_data <-testing(split)wf <-workflow() |>add_recipe(recipe(medv ~ ., data = train_data)) |>add_model(linear_reg() |>set_engine("lm"))# fit_resamples must SAVE predictions and EXTRACT each fold's trained workflow (extract = I)set.seed(7)folds <-vfold_cv(train_data, v =10)res_cv <-fit_resamples( wf, resamples = folds,control =control_resamples(save_pred =TRUE, extract = I))conf_cv <-int_conformal_cv(res_cv)pred_cv <-predict(conf_cv, test_data, level =0.90)# Same coverage check — does the CV interval keep its 90% promise too?chk <-cbind(test_data["medv"], pred_cv)chk$covered <- chk$medv >= chk$.pred_lower & chk$medv <= chk$.pred_upperround(c(cv_coverage =mean(chk$covered),cv_mean_width =mean(chk$.pred_upper - chk$.pred_lower)), 3)
cv_coverage cv_mean_width
0.929 14.709
L’intervalle par validation croisée couvre lui aussi à environ 90 %, et parce qu’il a utilisé toutes les données d’entraînement pour la calibration sa bande est généralement un brin plus étroite que la version par découpage — la même garantie, achetée plus efficacement. Les deux réglages de control_resamples() sont le piège :save_pred = TRUE conserve les prédictions hors-pli et extract = I remet à int_conformal_cv() le workflow entraîné de chaque pli. Omettez l’un ou l’autre et il lève une erreur.
AstuceLa prédiction conforme fonctionne autour de n’importe quel modèle
Nous avons utilisé un modèle linéaire pour que les résidus soient faciles à raisonner, mais rien de ce qui précède n’a touché aux rouages internes de lm. Remplacez linear_reg() par rand_forest() ou boost_tree() et chaque ligne s’exécute encore — la prédiction conforme enveloppe le modèle comme une boîte noire et se calibre sur ses résidus. Cette indépendance vis-à-vis du modèle est tout l’attrait : une seule recette d’intervalle honnête pour toute la ménagerie de modèles.
L’autre question de confiance : le modèle devrait-il seulement prédire ?
Les intervalles quantifient l’incertitude en régression. Pour la classification, la question parallèle est plus tranchante : certaines prédictions sont trop proches de la frontière de décision pour être dignes de confiance, et le geste honnête est de s’abstenir. Un modèle qui annonce « 51 % de risque de maladie » vous dit qu’il ne sait presque rien ; forcer cela en un « positif » net jette l’avertissement à la poubelle. La zone équivoque préserve l’avertissement : tout cas dont la probabilité prédite se situe à l’intérieur d’un buffer du seuil de 0.5 est signalé [EQ] (équivoque) au lieu d’être étiqueté.
Nous ajustons un rapide modèle logistique sur PimaIndiansDiabetes2 (diabète oui/non) et marquons chaque prédiction à ±0.15 du seuil comme équivoque avec probably::make_two_class_pred() :
library(mlbench)library(rsample)library(probably)library(yardstick)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)pima$diabetes <-factor(pima$diabetes, levels =c("neg", "pos"))set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split); test_data <-testing(split)model <-glm(diabetes ~ ., data = train_data, family = binomial)prob_pos <-predict(model, test_data, type ="response") # P(diabetes = pos)lvls <-levels(pima$diabetes)# make_two_class_pred takes the probability of the FIRST level ("neg") = 1 - prob_pos.# A buffer of 0.15 flags anything within 0.50 +/- 0.15 as equivocal.pred_eqz <-make_two_class_pred(estimate =1- prob_pos, levels = lvls, buffer =0.15)table(pred_eqz, useNA ="ifany")
pred_eqz
<NA> neg pos
11 49 19
Le décompte NA est la zone équivoque — les patients que le modèle refuse de trancher. Le taux de cas reportables est la fraction sur laquelle il acceptera de s’engager :
Environ 86 % des patients reçoivent un verdict confiant ; les ~14 % restants atterrissent dans la zone équivoque, où la bonne action n’est pas une étiquette tirée à pile ou face mais un second test, plus de données, ou une revue humaine. Le bénéfice : l’exactitude sur les cas que le modèle accepte de reporter est plus élevée, parce que les cas vraiment ambigus ne la tirent plus vers le bas. C’est la question « puis-je me fier à cette prédiction ? » répondue cas par cas — le miroir de classification de l’intervalle de régression.
NoteZones équivoques, intervalles de prédiction et domaine d’applicabilité
Trois idées apparentées, toutes au sujet de la confiance. Les intervalles de prédiction (ci-dessus) quantifient l’incertitude sur la sortie. La zone équivoque signale l’incertitude sur la classe prédite. Une troisième, le domaine d’applicabilité, demande si un nouveau cas ressemble seulement aux données d’entraînement — une prédiction loin au-delà de la plage des prédicteurs est une extrapolation à laquelle vous ne devriez pas vous fier, aussi serré que soit son intervalle nominal. Tidy Modeling with R (ch. 19) développe l’idée de domaine d’applicabilité avec le package applicable ; c’est l’étape naturelle suivante une fois que les intervalles et les zones équivoques sont devenus une seconde nature.
NoteComment la prédiction conforme par découpage garantit sa couverture (optionnel)
Soit un jeu de calibration de \(n\) points avec des résidus absolus \(R_i = |y_i - \hat{y}_i|\), \(i = 1, \dots,
n\). Pour construire un intervalle \(1 - \alpha\) (ici \(\alpha = 0.10\) pour 90 %), calculez le quantile conforme
où \(R_{(k)}\) est le \(k\)-ième plus petit résidu de calibration — essentiellement le quantile empirique \((1-\alpha)\) des erreurs, avec une petite correction en échantillon fini \(\frac{n+1}{n}\). L’intervalle pour un nouveau point est alors
\[
\hat{y}_{new} \pm q .
\]
La garantie repose sur l’échangeabilité : si les résidus de calibration et le résidu du nouveau point sont échangeables (une condition plus faible que i.i.d. — elle dit seulement que leur distribution conjointe est invariante au réordonnancement), alors le nouveau résidu a une chance égale de tomber à n’importe quel rang parmi les \(n + 1\) résidus. La probabilité qu’il dépasse \(q = R_{(k)}\) est donc au plus \(\alpha\), ce qui donne
Aucune forme distributionnelle pour les résidus n’est supposée nulle part — seulement l’échangeabilité — ce qui explique pourquoi la prédiction conforme est dite sans hypothèse de distribution, et pourquoi elle enveloppe n’importe quel modèle. Le prix est la largeur constante \(q\) ; la régression quantile conformalisée remplace l’unique \(q\) par une bande variant localement pour retrouver l’adaptativité.
Quel outil, quand
Un repère de décision rapide :
Votre situation
Choisissez
Régression ; vous voulez un intervalle honnête autour de chaque prédiction
Conforme par découpage (int_conformal_split)
Régression ; les données sont rares, vous ne voulez pas perdre un jeu de calibration
Conforme par validation croisée (int_conformal_cv)
Classification ; signaler les prédictions trop proches de la frontière
Zone équivoque (make_two_class_pred, buffer=)
Un nouveau cas ressemble-t-il seulement aux données d’entraînement ? (extrapolation)
Domaine d’applicabilité (package applicable)
Vous devez vérifier l’un des points ci-dessus sur VOS données
Réexécuter + compter la couverture — the runtime is the judge
🟢 Avec un agent IA
Pas sûr que les prédictions de votre modèle soient dignes de confiance ? Demandez à Prova« entoure les prédictions de mon modèle de régression d’intervalles conformes à 90 % et vérifie la couverture sur mes données de test » — elle répond avec du code R que vous pouvez exécuter sur votre propre modèle, construit le graphique d’intervalles de prédiction, compte la couverture empirique, et vous aide à juger si la garantie tient. Pour un classifieur, elle définit la zone équivoque et affiche le taux de cas reportables. The runtime is the judge.Ask Prova →
Problèmes courants
int_conformal_cv() lève l’erreur « x must be a workflow, not a <lm> ». Votre appel à fit_resamples() n’a pas conservé les workflows des plis. Passez control_resamples(save_pred = TRUE, extract = I) — extract = I (la fonction identité) remet le workflow entraîné de chaque pli à la routine conforme ; save_pred = TRUE conserve les prédictions hors-pli sur lesquelles elle se calibre.
La couverture empirique est loin de la cible (par ex. 0.70 alors que vous demandiez 0.90). Presque toujours un problème de fuite : le modèle a vu les données de calibration. Avec int_conformal_split(), le jeu de calibration doit être des données sur lesquelles le modèle n’a pas été ajusté — ajustez sur fit_data, calibrez sur un cal_data séparé, jamais sur les mêmes lignes. (Un léger flottement autour de la cible sur un petit jeu de test est normal ; un écart important et constant est une fuite.)
La zone équivoque signale les mauvais cas (ou aucun).make_two_class_pred() lit la probabilité du premier niveau de facteur. Si votre événement est le second niveau (comme pos ici), passez estimate = 1 - prob_pos, ou reclassez les niveaux pour que la classe que vous notez soit première — sinon le buffer est centré sur la mauvaise probabilité.
reportable_rate() renvoie NA ou 1. Un buffer de 0 (ou NULL) ne crée aucune zone équivoque, donc chaque cas est reportable ; élargissez le buffer pour en découper réellement une. Si c’est NA, vous avez probablement passé un simple facteur plutôt que l’objet class_pred que renvoie make_two_class_pred().
Questions fréquentes
NoteQu’est-ce que la prédiction conforme en R, et quel package la fournit ?
La prédiction conforme est une manière sans hypothèse de distribution et indépendante du modèle de transformer une prédiction ponctuelle en un intervalle de prédiction avec un taux de couverture garanti — demandez 90 % et environ 90 % des intervalles contiennent la vérité, sans aucune hypothèse sur la distribution des résidus. En R, le package probably de tidymodels la fournit : int_conformal_split() (calibrer sur une portion mise de côté), int_conformal_cv() (calibrer par validation croisée), et int_conformal_quantile() (intervalles à largeur adaptative).
NoteComment obtenir un intervalle de prédiction pour un modèle de machine learning en R ?
Utilisez la prédiction conforme avec probably. Ajustez votre modèle sur une portion des données, construisez un objet conforme sur une portion de calibration séparée avec int_conformal_split(fitted_workflow, cal_data = cal), puis predict(conf, new_data, level = 0.90) renvoie .pred, .pred_lower et .pred_upper pour chaque cas. Elle fonctionne autour de n’importe quel modèle (linéaire, forêt aléatoire, boosting) parce qu’elle se calibre sur les résidus du modèle, en le traitant comme une boîte noire.
NoteComment mesurer l’incertitude de prédiction en R ?
Pour une sortie numérique, construisez un intervalle de prédiction conforme et reportez sa largeur — un intervalle étroit signifie une prédiction confiante, un intervalle large une prédiction incertaine — puis vérifiez la couverture en comptant combien de fois l’intervalle contient la vraie valeur sur des données de test. Pour une classification, signalez les prédictions incertaines avec une zone équivoque (make_two_class_pred() avec un buffer) et reportez le taux de cas reportables. Les deux sont dans le package probably.
NoteQuand devrais-je me fier à la prédiction d’un modèle ?
Fiez-vous à une prédiction quand (1) son incertitude est acceptable pour votre décision — un intervalle conforme assez étroit pour agir, ou une classe prédite hors de la zone équivoque ; (2) la garantie de couverture se vérifie sur vos données de test (vous avez réexécuté le modèle et compté) ; et (3) le nouveau cas se situe dans le domaine d’applicabilité — il ressemble aux données d’entraînement, donc la prédiction n’est pas une extrapolation. Une prédiction ponctuelle d’apparence confiante sur un cas très hors plage est exactement celle dont il faut se méfier.
NoteQuelle est la différence entre un intervalle de confiance et un intervalle de prédiction conforme ?
Un intervalle de prédiction classique issu de lm suppose des résidus normaux et homoscédastiques ; si ces hypothèses fléchissent, sa couverture annoncée est peu fiable. Un intervalle de prédiction conforme ne fait aucune hypothèse de distribution — il se calibre directement sur les résidus observés et garantit la couverture sous la condition bien plus faible d’échangeabilité. Il fonctionne aussi autour de modèles (forêts aléatoires, boosting) qui n’ont aucun intervalle classique propre du tout.
Testez vos connaissances
ImportantExercice : raisonner sur couverture, largeur et confiance
Vous ajustez deux modèles de prix immobiliers. Les intervalles conformes à 90 % du modèle A ont une largeur moyenne de $8k et couvrent la vérité 0.91 du temps sur le jeu de test. Les intervalles à 90 % du modèle B ont une largeur moyenne de $30k et couvrent 0.90 du temps. (a) Les deux atteignent leur cible de couverture — cela les rend-il aussi utiles l’un que l’autre ? (b) Un collègue rapporte des intervalles à 90 % qui ne couvrent que 0.68 des cas de test. Quel est le bug le plus probable ? (c) Vous devez maintenant signaler lesquelles des prédictions de classification d’un autre modèle sont trop incertaines pour agir. Quel outil probably, et que contrôle son argument buffer ?
AstuceIndice
Pour (a), la couverture est nécessaire mais pas suffisante — de quoi d’autre un intervalle a-t-il besoin pour être utile ? Pour (b), réfléchissez à ce qui pourrait amener les résidus de calibration à sous-estimer la vraie erreur. Pour (c), rappelez-vous l’outil de confiance pour la classification et la signification de la bande autour de 0.5.
AstuceSolution
(a) Non. Tous deux tiennent leur promesse de 90 %, mais le modèle A est bien plus utile parce que ses intervalles sont bien plus étroits ($8k contre $30k) — la même garantie, une information bien plus nette. La couverture vous dit que l’ intervalle est honnête ; la largeur vous dit s’il est informatif. Reportez toujours les deux.
(b) Fuite de données dans la calibration. Une couverture bien en deçà de la cible signifie presque toujours que le modèle a vu les données de calibration, donc ses résidus là-bas sont optimistement petits et l’intervalle est trop serré. Correction : calibrez sur une portion sur laquelle le modèle n’a jamais été ajusté (int_conformal_split avec un cal_data propre, ou int_conformal_cv avec extract = I).
(c) La zone équivoque :make_two_class_pred(estimate, levels, buffer = ...). Le buffer est la demi-largeur de la bande autour du seuil de 0.5 ; toute probabilité prédite à l’intérieur de 0.5 ± buffer est signalée [EQ] (équivoque) et le modèle s’abstient. Un buffer plus grand s’abstient sur plus de cas (taux de cas reportables plus bas) mais relève l’exactitude sur ceux qu’il accepte de reporter.
Vérification rapide. Un modèle prédit un nouveau logement à $24k avec un intervalle conforme à 90 % de [$8k, $40k], et les prédicteurs de ce logement se situent loin hors de la plage de tous les logements d’entraînement. Deux choses clochent dans le fait de se fier à l’estimation ponctuelle de $24k ici — nommez-les.
NoteAfficher la réponse
D’abord, l’intervalle est énorme — [$8k, $40k] est une bande de $32k de large, donc l’estimation ponctuelle ne porte presque aucune information ; agir sur « $24k » ignore à quel point le modèle est incertain. Ensuite, le logement est une extrapolation — ses prédicteurs se situent hors de la plage d’entraînement (hors du domaine d’applicabilité), donc même la garantie de couverture conforme repose sur des bases fragiles (l’échangeabilité avec les données de calibration est douteuse). La lecture honnête : ne vous fiez pas au $24k. Reportez l’intervalle large, signalez l’extrapolation, et rassemblez une vente comparable avant de vous engager.
Conclusion
Une prédiction ponctuelle ne raconte que la moitié de l’histoire. Cette leçon vous a donné l’autre moitié — une incertitude honnête, démontrée de façon exécutable. Pour la régression, la prédiction conforme (probably::int_conformal_split() / int_conformal_cv()) entoure la prédiction de n’importe quel modèle d’un intervalle sans hypothèse de distribution avec une garantie de couverture — et le geste qui la rend digne de confiance est de réexécuter le modèle et de compter que la couverture tient, le graphique d’intervalles de prédiction signature. Pour la classification, la zone équivoque (make_two_class_pred()) laisse le modèle s’abstenir sur les cas trop proches de la frontière, ne reportant que les prédictions qu’il peut assumer. Ensemble, elles répondent à la question la plus profonde du pilier — puis-je me fier à cette prédiction ? — non comme une affirmation mais comme quelque chose que vous prouvez sur vos propres données. C’est là l’atout différenciateur : the runtime is the judge.
Seuils de probabilité & calibration — le compagnon de classification : une fois que vous vous fiez à une prédiction, choisissez le seuil et vérifiez que les probabilités sont honnêtes. · Valeurs SHAP — pourquoi un modèle a fait une prédiction ; cette leçon demande peut-on s’y fier.
Prouvez que vous savez le faire. Maîtrisez toute la série Explicabilité des modèles en R — suivez votre parcours, construisez des projets et obtenez un certificat.
Cette leçon est reproductible : chaque intervalle, chaque chiffre de couverture et chaque figure a été produit par le code montré — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.
Références
Kuhn, M., & Silge, J. Tidy Modeling with R — « When Should You Trust Your Predictions? » (zones équivoques, domaines d’applicabilité) et les outils d’inférence conforme de probably. Gratuit en ligne (CC BY-NC-SA).
Angelopoulos, A. N., & Bates, S. A Gentle Introduction to Conformal Prediction and Distribution-Free Uncertainty Quantification — la référence accessible sur la prédiction conforme et sa garantie de couverture.
La documentation du package probably — int_conformal_split(), int_conformal_cv(), int_conformal_quantile(), et make_two_class_pred() pour les zones équivoques.