La maîtrise statistique des procédés (MSP) est une méthode essentielle pour assurer la qualité et l’efficacité des processus industriels. Elle utilise des outils statistiques pour surveiller, contrôler et améliorer la performance des systèmes de production. Fondée sur les travaux de Walter A. Shewhart, la MSP se concentre sur la réduction de la variabilité des processus et la détection rapide des anomalies.
Dans un environnement industriel compétitif, la MSP aide à minimiser les défauts, réduire les coûts et garantir la conformité aux spécifications. Les outils principaux incluent les cartes de contrôle, l’analyse de capabilité et les méthodes d’amélioration continue.
Un graphique de contrôle (ou carte de contrôle), traduit de l’anglais control chart, est un outil utilisé dans le domaine du contrôle de la qualité afin de maîtriser un processus. Il permet de déterminer le moment où apparaît une cause particulière de variation d’une caractéristique, entraînant une altération du processus.
Par exemple, un processus de fabrication pourra être mis à l’arrêt avant de produire des pièces non conformes.
Selon la norme internationale ISO, un processus est dit sous contrôle (ou encore stable) lorsque les écarts entre les résultats observés sur un échantillon peuvent être attribués à un ensemble de causes aléatoires qui ne paraît pas se modifier dans le temps.
Une carte de contrôle est composée de trois éléments essentiels :
Par convention, selon la règle de Shewhart, ces limites sont placées à \(\pm 3\sigma\) de la moyenne, ce qui correspond à un intervalle de confiance de 99,73%.
Si \(X \sim \mathcal{N}(\mu, \sigma)\) alors : \[P[\mu - 3\sigma < X < \mu + 3\sigma] = 0{,}9973\]
On distingue généralement deux types de cartes selon la phase du processus :
Phase I (Cartes d’étude initiale) : Lorsque le processus sous contrôle est de loi \(\mathcal{N}(\mu, \sigma)\) avec \(\mu\) et \(\sigma\) inconnus. On doit alors estimer ces paramètres.
Phase II (Cartes aux valeurs standard) : Lorsque le processus sous contrôle est de loi \(\mathcal{N}(\mu_0, \sigma_0)\) avec \(\mu_0\) et \(\sigma_0\) connus (donnés par des normes ou établis en Phase I).
On considère un procédé qui, sous contrôle, suit une loi normale \(\mathcal{N}(10, 0{,}1)\). Nous disposons de 30 échantillons (sous-groupes rationnels) de taille \(n=5\) prélevés régulièrement.
Objectif : Vérifier si le processus reste centré sur la valeur cible \(\mu_0 = 10\).
Carte X : Pour ce type de carte, l’idée est de s’intéresser aux moyennes de chacun des sous-groupes rationnels, c’est-à-dire aux réalisations des variables aléatoires réelles \(\bar{X}_i\) pour \(i = 1, \ldots, k\). Chaque variable aléatoire \(\bar{X}_i\) est définie comme :
\[\bar{X}_i = \frac{1}{n} \sum_{j=1}^{n} X_{ij}\]
Si chacune des variables aléatoires réelles \(X_{ij}\) suit une loi normale \(\mathcal{N}(\mu, \sigma)\), il est alors immédiat que, d’après l’hypothèse d’indépendance de ces variables aléatoires :
\[\bar{X}_i \sim \mathcal{N}\left(\mu, \frac{\sigma}{\sqrt{n}}\right)\]
Cela signifie que la moyenne \(\bar{X}_i\) suit une loi normale avec une moyenne \(\mu\) et un écart-type réduit par le facteur \(\frac{1}{\sqrt{n}}\).
Les limites de contrôle pour la carte \(\bar{X}\) en Phase II (paramètres connus) sont définies comme suit selon la règle des 3σ :
\[\begin{align} \text{LSC} &= \mu_0 + 3 \cdot \frac{\sigma_0}{\sqrt{n}} \\[0.3cm] \text{LC} &= \mu_0 \\[0.3cm] \text{LCI} &= \mu_0 - 3 \cdot \frac{\sigma_0}{\sqrt{n}} \end{align}\]
où : - LSC représente la limite de contrôle supérieure - LC correspond à la ligne centrale (ou moyenne cible) - LCI désigne la limite de contrôle inférieure - Dans ces formules, \(\mu_0\) est la moyenne du processus sous contrôle, \(\sigma_0\) est l’écart-type du processus sous contrôle, et \(n\) est la taille de chaque échantillon.
# Chargement des données
Exemple1 <- read.csv("Exemple1.txt", sep = "", header = FALSE)
# Affichage des premières lignes
kable(head(Exemple1),
col.names = c("Échantillon", "Valeur"),
caption = "Aperçu des données - Exemple 1",
align = "c") |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE)
| Échantillon | Valeur |
|---|---|
| 1 | 9.937568 |
| 1 | 9.953563 |
| 1 | 10.015903 |
| 1 | 10.077521 |
| 1 | 9.975793 |
| 2 | 10.092923 |
Nos données comportent deux variables et 150 observations, réparties en 30 échantillons de 5 mesures chacun.
# Initialiser des vecteurs pour stocker les statistiques des échantillons
x <- numeric(30)
s <- numeric(30)
# Calcul des moyennes et écarts-types des échantillons
for (i in 1:30) {
echantillon <- Exemple1$V2[Exemple1$V1 == i]
x[i] <- mean(echantillon)
s[i] <- sd(echantillon)
}
# Paramètres pour le calcul des limites de contrôle (Phase II - connus)
mu0 <- 10
sigma <- 0.1
n <- 5
# Calcul des limites de contrôle
LIC <- mu0 - 3 * sigma / sqrt(n) # Limite inférieure
LSC <- mu0 + 3 * sigma / sqrt(n) # Limite supérieure
# Affichage élégant des limites
afficher_limites(LSC, mu0, LIC, sigma/sqrt(n), "Carte X̄")
┌─────────────────────────────────────────────┐
│ LIMITES DE CONTRÔLE (Carte X̄ ) │
├─────────────────────────────────────────────┤
│ LSC = 10.1342 │
│ LC = 10.0000 │
│ LCI = 9.8658 │
├─────────────────────────────────────────────┤
│ σ = 0.0447 │
└─────────────────────────────────────────────┘
Analyse des limites : L’écart-type de \(\bar{X}\) vaut \(\sigma_{\bar{X}} = \frac{0{,}1}{\sqrt{5}} \approx 0{,}0447\), soit une réduction d’un facteur \(\sqrt{5} \approx 2{,}24\) par rapport à \(\sigma\). Les limites sont placées à \(\pm 0{,}134\) de la moyenne cible, ce qui correspond à un intervalle très étroit rendant la détection sensible.
# Tableau complet des moyennes calculées
moyennes_df <- data.frame(
Echantillon = 1:30,
Moyenne = round(x, 4)
)
# Affichage en 3 blocs de 10
kable(moyennes_df[1:10, ],
caption = "Moyennes des échantillons 1 à 10",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Moyenne |
|---|---|
| 1 | 9.9921 |
| 2 | 9.9975 |
| 3 | 10.0587 |
| 4 | 9.9110 |
| 5 | 9.9745 |
| 6 | 9.9435 |
| 7 | 9.9323 |
| 8 | 9.9902 |
| 9 | 10.0251 |
| 10 | 9.9766 |
kable(moyennes_df[11:20, ],
caption = "Moyennes des échantillons 11 à 20",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Moyenne |
|---|---|
| 11 | 9.9621 |
| 12 | 9.9600 |
| 13 | 10.0307 |
| 14 | 10.0439 |
| 15 | 10.0021 |
| 16 | 9.9449 |
| 17 | 9.9276 |
| 18 | 9.9993 |
| 19 | 9.9767 |
| 20 | 10.0617 |
kable(moyennes_df[21:30, ],
caption = "Moyennes des échantillons 21 à 30",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Moyenne |
|---|---|
| 21 | 10.0354 |
| 22 | 9.9441 |
| 23 | 10.0302 |
| 24 | 10.0119 |
| 25 | 10.0587 |
| 26 | 10.0136 |
| 27 | 9.9926 |
| 28 | 10.0197 |
| 29 | 9.9613 |
| 30 | 10.0090 |
# Préparation des données pour ggplot
df_xbar <- data.frame(
echantillon = 1:30,
moyenne = x,
hors_limite = ifelse(x > LSC | x < LIC, "Hors contrôle", "Sous contrôle")
)
# Création du graphique avec les palettes
ggplot(df_xbar, aes(x = echantillon, y = moyenne)) +
# Zone de contrôle (±1σ) - zone idéale
annotate("rect", xmin = 0, xmax = 31,
ymin = mu0 - sigma/sqrt(n),
ymax = mu0 + sigma/sqrt(n),
alpha = 0.3, fill = couleurs$zone_ideale) +
# Zone de contrôle (±3σ) - zone acceptable
annotate("rect", xmin = 0, xmax = 31,
ymin = LIC, ymax = LSC,
alpha = 0.2, fill = couleurs$zone_acceptable) +
# Limites de surveillance ±2σ
geom_hline(yintercept = mu0 + 2*sigma/sqrt(n),
color = couleurs$surveillance, linewidth = 0.8,
linetype = "dotted", alpha = 0.7) +
geom_hline(yintercept = mu0 - 2*sigma/sqrt(n),
color = couleurs$surveillance, linewidth = 0.8,
linetype = "dotted", alpha = 0.7) +
# Limites de contrôle principales
geom_hline(yintercept = mu0, color = couleurs$vert_principal,
linewidth = 1.3, linetype = "solid") +
geom_hline(yintercept = LSC, color = couleurs$rouge_principal,
linewidth = 1.2, linetype = "dashed") +
geom_hline(yintercept = LIC, color = couleurs$rouge_principal,
linewidth = 1.2, linetype = "dashed") +
# Tracé des données
geom_line(color = couleurs$bleu_principal, linewidth = 1.1) +
geom_point(aes(color = hors_limite), size = 3.5, shape = 19) +
# Annotations des limites
annotate("text", x = 28, y = LSC,
label = paste("LSC =", round(LSC, 4)),
vjust = -0.7, color = couleurs$rouge_principal,
fontface = "bold", size = 4) +
annotate("text", x = 28, y = LIC,
label = paste("LCI =", round(LIC, 4)),
vjust = 1.7, color = couleurs$rouge_principal,
fontface = "bold", size = 4) +
annotate("text", x = 28, y = mu0,
label = paste("LC =", mu0),
vjust = -0.7, color = couleurs$vert_principal,
fontface = "bold", size = 4) +
# Mise en forme
scale_color_manual(values = c("Sous contrôle" = couleurs$sous_controle,
"Hors contrôle" = couleurs$hors_controle)) +
labs(
title = expression(paste("Carte de Contrôle ", bar(X), " - Phase II")),
subtitle = expression(paste(mu[0], " = 10, ", sigma[0], " = 0.1, n = 5")),
x = "Numéro d'échantillon",
y = expression(paste("Moyenne de l'échantillon (", bar(X), ")")),
color = "État du processus"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5,
color = couleurs$bleu_principal),
plot.subtitle = element_text(size = 11, hjust = 0.5, color = couleurs$gris_fonce),
plot.caption = element_text(size = 9, hjust = 0.5, color = "gray50",
face = "italic", margin = margin(t = 10)),
panel.grid.minor = element_blank(),
panel.grid.major = element_line(color = "gray90", linewidth = 0.3),
panel.border = element_rect(color = "gray70", fill = NA, linewidth = 0.6),
legend.position = "bottom",
legend.title = element_text(face = "bold", size = 11),
legend.background = element_rect(fill = couleurs$gris_clair,
color = "gray70", linewidth = 0.4),
legend.margin = margin(5, 5, 5, 5),
axis.title = element_text(face = "bold", size = 11),
axis.text = element_text(size = 10)
) +
scale_x_continuous(breaks = seq(0, 30, 5)) +
scale_y_continuous(breaks = seq(floor(min(x)*10)/10,
ceiling(max(x)*10)/10, 0.05))
Carte de contrôle X̄ - Phase II avec paramètres connus
# Analyse statistique
points_hors_controle <- sum(df_xbar$hors_limite == "Hors contrôle")
moyenne_globale <- mean(x)
ecart_type_observe <- sd(x)
writeLines(c(
"",
"═══════════════════════════════════════════",
" ANALYSE DE LA CARTE X̄",
"═══════════════════════════════════════════",
sprintf("Points hors contrôle : %d sur 30", points_hors_controle),
sprintf("Moyenne observée (X̄̄) : %.4f", moyenne_globale),
sprintf("Écart de la cible : %.4f", moyenne_globale - mu0),
sprintf("Écart-type observé : %.4f", ecart_type_observe),
sprintf("Écart-type théorique : %.4f", sigma/sqrt(n)),
"═══════════════════════════════════════════",
""
))
═══════════════════════════════════════════
ANALYSE DE LA CARTE X̄
═══════════════════════════════════════════
Points hors contrôle : 0 sur 30
Moyenne observée (X̄̄) : 9.9929
Écart de la cible : -0.0071
Écart-type observé : 0.0412
Écart-type théorique : 0.0447
═══════════════════════════════════════════
Conclusions :
Le processus semble être sous contrôle, il n’y a aucun point qui sort. Plus précisément :
Décision : Le processus de fabrication fonctionne normalement concernant sa position (centrage). Aucune action corrective n’est nécessaire.
Tandis que la carte \(\bar{X}\) surveille le centrage du processus, la carte \(S\) surveille sa dispersion (variabilité). Un processus peut être bien centré mais trop variable, produisant alors des pièces hors tolérances.
Considérons toujours \(k\) sous-groupes rationnels de taille \(n\). La carte \(S\) consiste en la représentation des diverses valeurs \(s_i\) (pour \(1 \leq i \leq k\)) qui sont des réalisations des variables aléatoires \(S_i\) telles que :
\[S_i^2 = \frac{1}{n-1} \sum_{j=1}^{n} (X_{ij} - \bar{X}_i)^2\]
D’après la Proposition 02 du cours, lorsque les variables aléatoires réelles \(X_{ij}\) sont indépendantes avec \(\forall i = 1, \ldots, k\), \(\forall j = 1, \ldots, n\), \(X_{ij} \sim \mathcal{N}(\mu, \sigma)\) alors :
\[(n-1) \frac{S_i^2}{\sigma^2} \sim \chi^2_{n-1}\]
Remarque importante du cours : Attention au fait que généralement \(S\) n’est pas un estimateur sans biais de \(\sigma\) !
Pour une loi normale, on a \(\mathbb{E}[S_i] = c_4(n) \cdot \sigma\) où \(c_4(n)\) est un coefficient de correction dépendant de \(n\) et tabulé. De même :
\[\text{Var}(S_i) = \mathbb{E}[S_i^2] - [\mathbb{E}[S_i]]^2 = \sigma^2 - (c_4(n) \cdot \sigma)^2 = \sigma^2(1 - c_4^2(n))\]
Donc : \(\sigma(S_i) = \sigma\sqrt{1 - c_4^2(n)}\)
Les limites de contrôle pour la carte \(S\) en Phase II sont :
\[\begin{align} \text{LSC} &= c_4(n)\sigma_0 + 3\sigma_0\sqrt{1 - c_4^2(n)} \\[0.3cm] \text{LC} &= c_4(n)\sigma_0 \\[0.3cm] \text{LCI} &= c_4(n)\sigma_0 - 3\sigma_0\sqrt{1 - c_4^2(n)} \end{align}\]
Note importante : Si LCI < 0, on pose LCI = 0 car l’écart-type ne peut être négatif.
# Initialisation d'un vecteur pour stocker les écarts-types
variances <- numeric(30)
# Boucle pour calculer l'écart-type pour chaque groupe
for (i in 1:30) {
sous_groupe <- Exemple1$V2[Exemple1$V1 == i]
n <- length(sous_groupe)
mean_group <- mean(sous_groupe)
variances[i] <- sum((sous_groupe - mean_group)^2) / (n - 1)
}
# Calcul des écarts-types
sd_vals <- sqrt(variances)
# Paramètres pour la carte S
mu0 <- 10
sigma <- 0.1
C4 <- 0.940 # Coefficient c4 pour n=5
# Calcul des limites
S_bar <- C4 * sigma
LIC_s <- C4*sigma - 3*sigma*sqrt(1 - C4^2)
LSC_s <- C4*sigma + 3*sigma*sqrt(1 - C4^2)
# Si LIC négatif, on le fixe à 0
if (LIC_s < 0) LIC_s <- 0
# Affichage des limites
afficher_limites(LSC_s, S_bar, LIC_s, NULL, "Carte S")
┌─────────────────────────────────────────────┐
│ LIMITES DE CONTRÔLE (Carte S ) │
├─────────────────────────────────────────────┤
│ LSC = 0.1964 │
│ LC = 0.0940 │
│ LCI = 0.0000 │
└─────────────────────────────────────────────┘
writeLines(sprintf("Coefficient c4 pour n=5 : %.3f", C4))
Coefficient c4 pour n=5 : 0.940
# Tableau complet des écarts-types calculés
ecarts_df <- data.frame(
Echantillon = 1:30,
Ecart_type = round(sd_vals, 4)
)
# Affichage en 3 blocs de 10
kable(ecarts_df[1:10, ],
caption = "Écarts-types des échantillons 1 à 10",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Ecart_type |
|---|---|
| 1 | 0.0561 |
| 2 | 0.0937 |
| 3 | 0.1131 |
| 4 | 0.0999 |
| 5 | 0.1714 |
| 6 | 0.0509 |
| 7 | 0.0633 |
| 8 | 0.1012 |
| 9 | 0.1057 |
| 10 | 0.0861 |
kable(ecarts_df[11:20, ],
caption = "Écarts-types des échantillons 11 à 20",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Ecart_type |
|---|---|
| 11 | 0.0853 |
| 12 | 0.0761 |
| 13 | 0.1798 |
| 14 | 0.1685 |
| 15 | 0.0719 |
| 16 | 0.0925 |
| 17 | 0.1835 |
| 18 | 0.0624 |
| 19 | 0.1419 |
| 20 | 0.0730 |
kable(ecarts_df[21:30, ],
caption = "Écarts-types des échantillons 21 à 30",
align = "c", row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, position = "center")
| Echantillon | Ecart_type |
|---|---|
| 21 | 0.1169 |
| 22 | 0.1041 |
| 23 | 0.1123 |
| 24 | 0.1232 |
| 25 | 0.1075 |
| 26 | 0.0545 |
| 27 | 0.0491 |
| 28 | 0.2305 |
| 29 | 0.1644 |
| 30 | 0.0695 |
# Préparation des données
df_s <- data.frame(
echantillon = 1:30,
ecart_type = sd_vals,
hors_limite = ifelse(sd_vals > LSC_s | sd_vals < LIC_s,
"Hors contrôle", "Sous contrôle")
)
# Graphique
ggplot(df_s, aes(x = echantillon, y = ecart_type)) +
# Zone de contrôle
annotate("rect", xmin = 0, xmax = 31,
ymin = LIC_s, ymax = LSC_s,
alpha = 0.15, fill = "lightblue") +
# Limites de contrôle
geom_hline(yintercept = S_bar, color = "#2E7D32",
linewidth = 1.2) +
geom_hline(yintercept = LSC_s, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_hline(yintercept = LIC_s, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
# Données
geom_line(color = "#1976D2", linewidth = 1) +
geom_point(aes(color = hors_limite), size = 3.5) +
# Annotations
annotate("text", x = 28, y = LSC_s,
label = paste("LSC =", round(LSC_s, 4)),
vjust = -0.7, color = "#D32F2F",
fontface = "bold", size = 4) +
annotate("text", x = 28, y = S_bar,
label = paste("S̄ =", round(S_bar, 4)),
vjust = -0.7, color = "#2E7D32",
fontface = "bold", size = 4) +
# Mise en forme
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte de Contrôle S - Phase II",
subtitle = "Ecart-type = 0.1, n = 5, c4 = 0.940",
x = "Numéro d'échantillon",
y = "Écart-type de l'échantillon (S)",
color = "État du processus"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 15, hjust = 0.5),
plot.subtitle = element_text(size = 11, hjust = 0.5, color = "gray30"),
panel.grid.minor = element_blank(),
legend.position = "bottom",
legend.title = element_text(face = "bold"),
axis.title = element_text(face = "bold", size = 11)
) +
scale_x_continuous(breaks = seq(0, 30, 5))
Carte de contrôle S - Surveillance de la dispersion
points_hors_s <- sum(df_s$hors_limite == "Hors contrôle")
s_moyen <- mean(sd_vals)
writeLines(c(
"",
"═══════════════════════════════════════════",
" ANALYSE DE LA CARTE S",
"═══════════════════════════════════════════",
sprintf("Points hors contrôle : %d", points_hors_s),
sprintf("Écart-type moyen obs. : %.4f", s_moyen),
sprintf("Écart-type cible (c4×σ0): %.4f", S_bar),
"═══════════════════════════════════════════",
""
))
═══════════════════════════════════════════
ANALYSE DE LA CARTE S
═══════════════════════════════════════════
Points hors contrôle : 1
Écart-type moyen obs. : 0.1069
Écart-type cible (c4×σ0): 0.0940
═══════════════════════════════════════════
En passant par la carte \(S\), on voit qu’il y a un point qui sort de la limite supérieure, donc le processus n’est pas sous contrôle.
Conclusion Exemple 1 :
Le processus est centré correctement, comme l’indique la carte de contrôle \(\bar{X}\) qui montre que les moyennes des sous-groupes restent en conformité avec la valeur cible. Cependant, la carte \(S\) révèle une variabilité interne anormale, signalée par un point hors des limites de contrôle.
Cela suggère que, bien que la position moyenne du processus soit stable, une cause assignable pourrait perturber la dispersion du processus. Cette anomalie peut être liée à des facteurs tels qu’une machine instable, une matière première non homogène, ou un opérateur changeant.
Recommandation : Il est donc recommandé d’analyser ce sous-groupe particulier pour identifier et corriger la source de la variabilité.
Une entreprise fabrique des alarmes incendie et teste leur qualité en mesurant leur rapidité de réaction. Chaque alarme teste l’atmosphère une fois par seconde.
D’après les normes à respecter, le temps de réaction doit être en moyenne égal à 5 secondes.
Voici les résultats observés pour 20 alarmes :
5 3 3 6 1 4 2 3 8 7
4 5 5 3 17 6 5 1 8 4
Question : Le responsable pense que cette production n’est pas sous contrôle (à cause de l’alarme à 17 secondes). Êtes-vous d’accord ?
# Données
alarmes <- c(5, 3, 3, 6, 1, 4, 2, 3, 8, 7,
4, 5, 5, 3, 17, 6, 5, 1, 8, 4)
# Statistiques de base
n <- length(alarmes)
moyenne <- mean(alarmes)
mediane <- median(alarmes)
ecart_type <- sd(alarmes)
minimum <- min(alarmes)
maximum <- max(alarmes)
# Quartiles
Q1 <- quantile(alarmes, 0.25)
Q3 <- quantile(alarmes, 0.75)
IQR <- Q3 - Q1
# Tableau des statistiques descriptives
stats_alarmes <- data.frame(
Statistique = c("Nombre d'observations", "Moyenne", "Médiane",
"Écart-type", "Minimum", "Maximum", "Q1", "Q3", "IQR"),
Valeur = c(n,
round(moyenne, 2),
mediane,
round(ecart_type, 2),
minimum,
maximum,
Q1,
Q3,
IQR)
)
kable(stats_alarmes,
caption = "Statistiques descriptives des temps de réaction",
align = "lr",
col.names = c("Statistique", "Valeur")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
row_spec(2, bold = TRUE, color = "red") # Mettre la moyenne en rouge
| Statistique | Valeur |
|---|---|
| Nombre d’observations | 20.00 |
| Moyenne | 5.00 |
| Médiane | 4.50 |
| Écart-type | 3.46 |
| Minimum | 1.00 |
| Maximum | 17.00 |
| Q1 | 3.00 |
| Q3 | 6.00 |
| IQR | 3.00 |
Une valeur est considérée comme atypique si elle se situe : - Au-dessus de Q3 + 1.5 × IQR - En-dessous de Q1 - 1.5 × IQR
# Limites des moustaches
limite_sup <- Q3 + 1.5 * IQR
limite_inf <- Q1 - 1.5 * IQR
# Identification des valeurs atypiques
atypiques <- alarmes[alarmes > limite_sup | alarmes < limite_inf]
# Identification des valeurs atypiques
atypiques <- alarmes[alarmes > limite_sup | alarmes < limite_inf]
# Tableau des limites
limites_df <- data.frame(
Type = c("Limite supérieure (Q3 + 1.5×IQR)",
"Limite inférieure (Q1 - 1.5×IQR)",
"Nombre de valeurs atypiques"),
Valeur = c(paste(round(limite_sup, 1), "secondes"),
paste(round(limite_inf, 1), "secondes"),
length(atypiques))
)
kable(limites_df,
caption = "Détection des valeurs atypiques",
align = "lr",
col.names = c("Critère", "Valeur")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE)
| Critère | Valeur |
|---|---|
| Limite supérieure (Q3 + 1.5×IQR) | 10.5 secondes |
| Limite inférieure (Q1 - 1.5×IQR) | -1.5 secondes |
| Nombre de valeurs atypiques | 1 |
if (length(atypiques) > 0) {
atypiques_df <- data.frame(
Valeur = atypiques,
Statut = "Atypique"
)
kable(atypiques_df,
caption = "Valeurs atypiques détectées",
align = "cr",
col.names = c("Temps de réaction (sec)", "Statut")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
row_spec(0, bold = TRUE, background = "#ffcccc")
}
| Temps de réaction (sec) | Statut |
|---|---|
| 17 | Atypique |
# Graphique avec ggplot2
df_alarmes <- data.frame(
valeur = alarmes,
type = "Temps de réaction"
)
ggplot(df_alarmes, aes(x = type, y = valeur)) +
geom_boxplot(fill = "#E3F2FD", color = "#1976D2",
linewidth = 1, outlier.color = "#D32F2F",
outlier.size = 4, outlier.shape = 17) +
geom_jitter(width = 0.15, alpha = 0.5, size = 3, color = "#1976D2") +
geom_hline(yintercept = 5, color = "#2E7D32",
linewidth = 1.2, linetype = "dashed") +
geom_hline(yintercept = limite_sup, color = "#D32F2F",
linewidth = 1, linetype = "dotted") +
annotate("text", x = 1.35, y = 5,
label = "Norme (5 sec)", color = "#2E7D32",
fontface = "bold", vjust = -0.5, size = 4) +
annotate("text", x = 1.35, y = limite_sup,
label = paste0("Q3 + 1.5×IQR = ", round(limite_sup, 1)),
color = "#D32F2F", fontface = "bold", vjust = -0.5, size = 3.5) +
labs(
title = "Boîte de dispersion - Temps de réaction des alarmes",
subtitle = "Détection des valeurs atypiques",
x = "",
y = "Temps de réaction (secondes)"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "gray30"),
axis.title.y = element_text(face = "bold"),
panel.grid.major.x = element_blank()
)
Conclusion Méthode 1 : La valeur 17 secondes est ATYPIQUE car elle dépasse Q3 + 1.5×IQR = 10.5
Le test de Shapiro-Wilk (Chapitre 1.2.5) vérifie si les données suivent une loi normale. Ce test est adapté aux petits échantillons (n ≤ 50).
Hypothèses : - H₀ : Les données suivent une loi normale - H₁ : Les données ne suivent pas une loi normale
# Test de Shapiro-Wilk
test_shapiro <- shapiro.test(alarmes)
# Test de Shapiro-Wilk
test_shapiro <- shapiro.test(alarmes)
# Tableau des résultats du test
shapiro_df <- data.frame(
Critère = c("Statistique W", "P-value", "Décision (α = 0.05)", "Interprétation"),
Résultat = c(
round(test_shapiro$statistic, 4),
round(test_shapiro$p.value, 4),
ifelse(test_shapiro$p.value < 0.05, "Rejet de H₀", "Acceptation de H₀"),
ifelse(test_shapiro$p.value < 0.05,
"Données non normales - Anomalies présentes",
"Données normales")
)
)
kable(shapiro_df,
caption = "Test de Shapiro-Wilk",
align = "lr",
col.names = c("Critère", "Résultat")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
row_spec(3:4, bold = TRUE,
background = ifelse(test_shapiro$p.value < 0.05, "#ffcccc", "#ccffcc"))
| Critère | Résultat |
|---|---|
| Statistique W | 0.7911 |
| P-value | 6e-04 |
| Décision (α = 0.05) | Rejet de H₀ |
| Interprétation | Données non normales - Anomalies présentes |
Conclusion Méthode 2 : Les données ne suivent pas une loi normale (p < 0.05), ce qui confirme la présence d’anomalies
Si le processus suit une loi normale N(μ₀, σ₀), alors d’après la règle des 3σ (Proposition 01 du cours) :
99.73% des observations doivent être dans l’intervalle [μ₀ - 3σ₀, μ₀ + 3σ₀]
# Paramètres
mu_0 <- 5 # Norme
sigma_0 <- ecart_type # Estimation
# Limites théoriques 3σ
limite_inf_3sigma <- mu_0 - 3 * sigma_0
limite_sup_3sigma <- mu_0 + 3 * sigma_0
# Observations hors limites
hors_limites <- alarmes[alarmes < limite_inf_3sigma | alarmes > limite_sup_3sigma]
# Observations hors limites
hors_limites <- alarmes[alarmes < limite_inf_3sigma | alarmes > limite_sup_3sigma]
# Tableau des limites 3sigma
limites_3sigma_df <- data.frame(
Paramètre = c("Norme μ₀", "Écart-type σ (estimé)",
"Limite inférieure (μ₀ - 3σ)",
"Limite supérieure (μ₀ + 3σ)",
"Observations hors limites"),
Valeur = c(
paste(mu_0, "secondes"),
paste(round(sigma_0, 2), "secondes"),
paste(round(limite_inf_3sigma, 2), "secondes"),
paste(round(limite_sup_3sigma, 2), "secondes"),
length(hors_limites)
)
)
kable(limites_3sigma_df,
caption = "Règle des 3σ",
align = "lr",
col.names = c("Paramètre", "Valeur")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE)
| Paramètre | Valeur |
|---|---|
| Norme μ₀ | 5 secondes |
| Écart-type σ (estimé) | 3.46 secondes |
| Limite inférieure (μ₀ - 3σ) | -5.39 secondes |
| Limite supérieure (μ₀ + 3σ) | 15.39 secondes |
| Observations hors limites | 1 |
if (length(hors_limites) > 0) {
hors_limites_df <- data.frame(
Valeur = hors_limites,
Statut = "Hors limites 3σ"
)
kable(hors_limites_df,
caption = "Observations hors des limites 3σ",
align = "cr",
col.names = c("Temps de réaction (sec)", "Statut")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
row_spec(0, bold = TRUE, background = "#ffcccc")
}
| Temps de réaction (sec) | Statut |
|---|---|
| 17 | Hors limites 3σ |
# Graphique avec ggplot2
df_hist <- data.frame(
valeur = alarmes
)
ggplot(df_hist, aes(x = valeur)) +
geom_histogram(bins = ceiling(sqrt(n)),
fill = "#E3F2FD", color = "#1976D2",
linewidth = 0.8, alpha = 0.8) +
geom_vline(xintercept = mu_0, color = "#2E7D32",
linewidth = 1.5, linetype = "dashed") +
geom_vline(xintercept = limite_inf_3sigma, color = "#D32F2F",
linewidth = 1.2, linetype = "dotted") +
geom_vline(xintercept = limite_sup_3sigma, color = "#D32F2F",
linewidth = 1.2, linetype = "dotted") +
annotate("text", x = mu_0, y = Inf,
label = "Norme (5 sec)", color = "#2E7D32",
fontface = "bold", vjust = 2, angle = 90, size = 4) +
annotate("text", x = limite_sup_3sigma, y = Inf,
label = paste0("μ₀ + 3σ = ", round(limite_sup_3sigma, 1)),
color = "#D32F2F", fontface = "bold",
vjust = 2, angle = 90, size = 3.5) +
labs(
title = "Histogramme - Temps de réaction des alarmes",
subtitle = "Règle des 3σ",
x = "Temps de réaction (secondes)",
y = "Fréquence"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "gray30"),
axis.title = element_text(face = "bold")
)
Conclusion Méthode 3 : 1 observation HORS des limites 3σ
Analyse de la configuration des données :
writeLines(c(
"",
"═══════════════════════════════════════════════════════════════",
" CONFIGURATION DES DONNÉES",
"═══════════════════════════════════════════════════════════════",
"",
sprintf("Nombre d'alarmes testées : %d", n),
"Mesures par alarme : 1 (temps de réaction unique)",
"Taille d'échantillon (n) : 1",
"",
"PRÉREQUIS CARTE X̄ (Cours MSP - Chapitre 3) :",
" • Sous-groupes rationnels de taille n ≥ 2 (idéalement n = 4 ou 5)",
" • Calcul de la moyenne X̄ᵢ pour chaque sous-groupe",
" • Calcul de l'étendue Rᵢ = max - min pour chaque sous-groupe",
"",
"PROBLÈME AVEC n=1 :",
" Impossible de calculer une moyenne intra-groupe (X̄ᵢ = Xᵢ)",
" Impossible de calculer Rᵢ (besoin de ≥ 2 valeurs)",
" La carte X̄-R classique est STRICTEMENT NON APPLICABLE",
"",
"CONCLUSION :",
" → La carte X̄ du Chapitre 3 NE PEUT PAS être utilisée ici",
" → Nécessité d'une carte adaptée aux valeurs individuelles",
"",
"═══════════════════════════════════════════════════════════════",
""
))
═══════════════════════════════════════════════════════════════
CONFIGURATION DES DONNÉES
═══════════════════════════════════════════════════════════════
Nombre d'alarmes testées : 20
Mesures par alarme : 1 (temps de réaction unique)
Taille d'échantillon (n) : 1
PRÉREQUIS CARTE X̄ (Cours MSP - Chapitre 3) :
• Sous-groupes rationnels de taille n ≥ 2 (idéalement n = 4 ou 5)
• Calcul de la moyenne X̄ᵢ pour chaque sous-groupe
• Calcul de l'étendue Rᵢ = max - min pour chaque sous-groupe
PROBLÈME AVEC n=1 :
Impossible de calculer une moyenne intra-groupe (X̄ᵢ = Xᵢ)
Impossible de calculer Rᵢ (besoin de ≥ 2 valeurs)
La carte X̄-R classique est STRICTEMENT NON APPLICABLE
CONCLUSION :
→ La carte X̄ du Chapitre 3 NE PEUT PAS être utilisée ici
→ Nécessité d'une carte adaptée aux valeurs individuelles
═══════════════════════════════════════════════════════════════
Référence cours : Chapitre 3 définit la carte X̄ pour des sous-groupes de taille n ≥ 2. Notre configuration (n=1) viole cette condition fondamentale.
Principe (Cours MSP - Chapitre 5) :
Pour des valeurs individuelles (n=1), le cours recommande la Carte X-mR :
Avantage clé : Estimation robuste de σ via les étendues mobiles :
\[\hat{\sigma} = \frac{\overline{mR}}{d_2} \quad \text{où} \quad \overline{mR} = \frac{1}{k-1}\sum_{i=2}^{k}|X_i - X_{i-1}|\]
avec \(d_2 = 1.128\) pour des paires de valeurs consécutives.
Pourquoi robuste ? Cette méthode utilise les différences locales entre valeurs successives, ce qui réduit l’influence des valeurs aberrantes isolées.
# ═══════════════════════════════════════════════════════════════
# CARTE X-mR (Individus et Étendues Mobiles)
# ═══════════════════════════════════════════════════════════════
# Calcul des étendues mobiles
mR <- abs(diff(alarmes))
mR_bar <- mean(mR)
# Constante pour n=2 (paires consécutives)
d2_mR <- 1.128
# Estimation ROBUSTE de σ
sigma_hat_mR <- mR_bar / d2_mR
# Paramètres
mu_norme <- 5
# Limites de contrôle pour Carte X (Individus)
LSC_X <- mu_norme + 3 * sigma_hat_mR
LC_X <- mu_norme
LIC_X <- max(0, mu_norme - 3 * sigma_hat_mR)
# Détection points hors contrôle
hors_X <- which(alarmes > LSC_X | alarmes < LIC_X)
# Affichage des calculs
writeLines(c(
"",
"┌─────────────────────────────────────────────────────────────┐",
"│ CALCULS CARTE X (Individus) - Méthode X-mR │",
"├─────────────────────────────────────────────────────────────┤",
sprintf("│ Étendue mobile moyenne (mR̄) = %.3f │", mR_bar),
sprintf("│ Constante d₂ (n=2) = %.3f │", d2_mR),
sprintf("│ σ̂ = mR̄/d₂ = %.3f │", sigma_hat_mR),
"├─────────────────────────────────────────────────────────────┤",
sprintf("│ LSC = μ₀ + 3σ̂ = %.2f │", LSC_X),
sprintf("│ LC = μ₀ = %.2f │", LC_X),
sprintf("│ LIC = μ₀ - 3σ̂ = %.2f │", LIC_X),
"├─────────────────────────────────────────────────────────────┤",
sprintf("│ Points hors contrôle : %d / %d │", length(hors_X), n),
"└─────────────────────────────────────────────────────────────┘",
""
))
┌─────────────────────────────────────────────────────────────┐
│ CALCULS CARTE X (Individus) - Méthode X-mR │
├─────────────────────────────────────────────────────────────┤
│ Étendue mobile moyenne (mR̄) = 3.632 │
│ Constante d₂ (n=2) = 1.128 │
│ σ̂ = mR̄/d₂ = 3.219 │
├─────────────────────────────────────────────────────────────┤
│ LSC = μ₀ + 3σ̂ = 14.66 │
│ LC = μ₀ = 5.00 │
│ LIC = μ₀ - 3σ̂ = 0.00 │
├─────────────────────────────────────────────────────────────┤
│ Points hors contrôle : 1 / 20 │
└─────────────────────────────────────────────────────────────┘
# Tableau des résultats
resultats_xmr <- data.frame(
Alarme = 1:n,
Temps = alarmes,
Statut = ifelse(alarmes > LSC_X | alarmes < LIC_X,
"Hors contrôle", "Sous contrôle")
)
# Afficher seulement les points hors contrôle
if (length(hors_X) > 0) {
kable(resultats_xmr[hors_X, ],
caption = "Points hors contrôle détectés (Carte X-mR)",
align = "c",
row.names = FALSE) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
row_spec(0, bold = TRUE, background = "#ffcccc")
}
| Alarme | Temps | Statut |
|---|---|---|
| 15 | 17 | Hors contrôle |
# Graphique
df_xmr <- data.frame(
Alarme = 1:n,
Temps = alarmes,
Statut = ifelse(alarmes > LSC_X | alarmes < LIC_X,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_xmr, aes(x = Alarme, y = Temps)) +
geom_hline(yintercept = LSC_X, color = "#D32F2F",
linewidth = 1.2, linetype = "dashed") +
geom_hline(yintercept = LC_X, color = "#2E7D32",
linewidth = 1.3) +
geom_hline(yintercept = LIC_X, color = "#D32F2F",
linewidth = 1.2, linetype = "dashed") +
geom_line(color = "#1976D2", linewidth = 1, alpha = 0.6) +
geom_point(aes(color = Statut), size = 4) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
annotate("text", x = 17, y = LSC_X,
label = sprintf("LSC = %.2f", LSC_X),
vjust = -0.7, color = "#D32F2F",
fontface = "bold", size = 4) +
annotate("text", x = 17, y = LC_X,
label = "Norme = 5 sec",
vjust = -0.7, color = "#2E7D32",
fontface = "bold", size = 4) +
annotate("text", x = 17, y = LIC_X,
label = sprintf("LIC = %.2f", LIC_X),
vjust = 1.7, color = "#D32F2F",
fontface = "bold", size = 4) +
labs(
title = "Carte X (Individus) - Méthode X-mR",
subtitle = "Approche conforme pour valeurs individuelles (n=1)",
x = "Numéro d'alarme",
y = "Temps de réaction (secondes)",
color = "Statut"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "#2E7D32"),
legend.position = "bottom",
panel.grid.minor = element_blank()
) +
scale_y_continuous(breaks = seq(0, max(alarmes) + 2, 2))
Carte X (Individus) - Méthode X-mR recommandée
Interprétation :
writeLines(c(
"",
"═══════════════════════════════════════════════════════════════",
" INTERPRÉTATION CARTE X-mR",
"═══════════════════════════════════════════════════════════════",
"",
sprintf("Points hors contrôle : %d / %d (%.0f%%)",
length(hors_X), n, 100*length(hors_X)/n),
"",
if (length(hors_X) > 0) {
paste0("Alarmes concernées : ", paste(hors_X, collapse = ", "))
} else {
"Aucune alarme hors contrôle"
},
"",
if (length(hors_X) > 0) {
paste0("Valeurs : ", paste(alarmes[hors_X], collapse = ", "), " secondes")
} else {
""
},
"",
if (length(hors_X) > 0) {
sprintf("Dépassements : %.2f secondes au-dessus de LSC",
max(alarmes[hors_X] - LSC_X))
} else {
""
},
"",
"CONCLUSION :",
if (length(hors_X) > 0) {
" ️ PROCESSUS HORS CONTRÔLE"
} else {
" Processus sous contrôle"
},
"",
"═══════════════════════════════════════════════════════════════",
""
))
═══════════════════════════════════════════════════════════════
INTERPRÉTATION CARTE X-mR
═══════════════════════════════════════════════════════════════
Points hors contrôle : 1 / 20 (5%)
Alarmes concernées : 15
Valeurs : 17 secondes
Dépassements : 2.34 secondes au-dessus de LSC
CONCLUSION :
️ PROCESSUS HORS CONTRÔLE
═══════════════════════════════════════════════════════════════
Question : L’alarme n°15 (17 sec) est-elle un cas isolé ou révèle-t-elle un problème systémique ?
Méthode : Refaire l’analyse en excluant cette alarme.
# ═══════════════════════════════════════════════════════════════
# ANALYSE SANS L'ALARME ABERRANTE (17 sec)
# ═══════════════════════════════════════════════════════════════
# Identification de l'alarme aberrante
alarme_aberrante <- which(alarmes == max(alarmes))
# Données sans l'alarme aberrante
alarmes_filtrees <- alarmes[-alarme_aberrante]
n_filtrees <- length(alarmes_filtrees)
# Recalcul des étendues mobiles
mR_filtrees <- abs(diff(alarmes_filtrees))
mR_bar_filtrees <- mean(mR_filtrees)
# Nouvelle estimation de σ (réutilisation de d2_mR déjà défini)
sigma_hat_filtrees <- mR_bar_filtrees / d2_mR
# Nouvelles limites
LSC_X_filtrees <- mu_norme + 3 * sigma_hat_filtrees
LIC_X_filtrees <- max(0, mu_norme - 3 * sigma_hat_filtrees)
# Détection
hors_X_filtrees <- which(alarmes_filtrees > LSC_X_filtrees |
alarmes_filtrees < LIC_X_filtrees)
# Statistiques comparatives
moyenne_originale <- mean(alarmes)
moyenne_filtree <- mean(alarmes_filtrees)
writeLines(c(
"",
"═══════════════════════════════════════════════════════════════",
" COMPARAISON : AVEC vs SANS alarme à 17 secondes",
"═══════════════════════════════════════════════════════════════",
"",
"AVEC alarme à 17 sec (données originales) :",
sprintf(" • Nombre d'alarmes : %d", n),
sprintf(" • Moyenne : %.2f sec", moyenne_originale),
sprintf(" • Écart-type estimé (σ̂) : %.3f", sigma_hat_mR),
sprintf(" • LSC : %.2f", LSC_X),
sprintf(" • Points hors contrôle : %d", length(hors_X)),
"",
"SANS alarme à 17 sec (données filtrées) :",
sprintf(" • Nombre d'alarmes : %d", n_filtrees),
sprintf(" • Moyenne : %.2f sec", moyenne_filtree),
sprintf(" • Écart-type estimé (σ̂) : %.3f", sigma_hat_filtrees),
sprintf(" • LSC : %.2f", LSC_X_filtrees),
sprintf(" • Points hors contrôle : %d", length(hors_X_filtrees)),
"",
"IMPACT DE L'ALARME ABERRANTE :",
sprintf(" • Variation moyenne : %+.2f sec (%.0f%%)",
moyenne_originale - moyenne_filtree,
100*(moyenne_originale - moyenne_filtree)/moyenne_filtree),
sprintf(" • Variation σ̂ : %+.3f (%.0f%%)",
sigma_hat_mR - sigma_hat_filtrees,
100*(sigma_hat_mR - sigma_hat_filtrees)/sigma_hat_filtrees),
sprintf(" • Variation LSC : %+.2f",
LSC_X - LSC_X_filtrees),
"",
"═══════════════════════════════════════════════════════════════",
""
))
═══════════════════════════════════════════════════════════════
COMPARAISON : AVEC vs SANS alarme à 17 secondes
═══════════════════════════════════════════════════════════════
AVEC alarme à 17 sec (données originales) :
• Nombre d'alarmes : 20
• Moyenne : 5.00 sec
• Écart-type estimé (σ̂) : 3.219
• LSC : 14.66
• Points hors contrôle : 1
SANS alarme à 17 sec (données filtrées) :
• Nombre d'alarmes : 19
• Moyenne : 4.37 sec
• Écart-type estimé (σ̂) : 2.315
• LSC : 11.94
• Points hors contrôle : 0
IMPACT DE L'ALARME ABERRANTE :
• Variation moyenne : +0.63 sec (14%)
• Variation σ̂ : +0.905 (39%)
• Variation LSC : +2.71
═══════════════════════════════════════════════════════════════
# Tableau comparatif
comparaison_df <- data.frame(
Critère = c("Nombre d'alarmes", "Moyenne (sec)", "Écart-type σ̂",
"LSC", "LIC", "Points hors contrôle", "Conclusion"),
Avec_17sec = c(
n,
sprintf("%.2f", moyenne_originale),
sprintf("%.3f", sigma_hat_mR),
sprintf("%.2f", LSC_X),
sprintf("%.2f", LIC_X),
length(hors_X),
ifelse(length(hors_X) > 0, "Hors contrôle", "Sous contrôle")
),
Sans_17sec = c(
n_filtrees,
sprintf("%.2f", moyenne_filtree),
sprintf("%.3f", sigma_hat_filtrees),
sprintf("%.2f", LSC_X_filtrees),
sprintf("%.2f", LIC_X_filtrees),
length(hors_X_filtrees),
ifelse(length(hors_X_filtrees) > 0, "Hors contrôle", "Sous contrôle")
)
)
kable(comparaison_df,
caption = "Comparaison : Impact de l'alarme à 17 secondes",
align = "lcc",
col.names = c("Critère", "Avec alarme 17 sec", "Sans alarme 17 sec")) |>
kable_styling(bootstrap_options = c("striped", "hover", "bordered"),
full_width = FALSE) |>
column_spec(1, bold = TRUE) |>
row_spec(7, bold = TRUE, font_size = 13,
background = ifelse(length(hors_X_filtrees) > 0, "#ffcccc", "#ccffcc"))
| Critère | Avec alarme 17 sec | Sans alarme 17 sec |
|---|---|---|
| Nombre d’alarmes | 20 | 19 |
| Moyenne (sec) | 5.00 | 4.37 |
| Écart-type σ̂ |
3.219
|
par(mfrow = c(2, 1), mar = c(4, 4, 3, 2))
# Graphique 1 : Avec alarme à 17 sec
plot(1:n, alarmes, type = "b", pch = 19, col = "#1976D2",
main = "AVEC alarme à 17 secondes (données originales)",
xlab = "Numéro d'alarme", ylab = "Temps (sec)",
ylim = c(0, max(alarmes) + 2), cex = 1.2, lwd = 1.5)
abline(h = LSC_X, col = "#D32F2F", lty = 2, lwd = 2)
abline(h = LC_X, col = "#2E7D32", lwd = 2)
abline(h = LIC_X, col = "#D32F2F", lty = 2, lwd = 2)
if (length(hors_X) > 0) {
points(hors_X, alarmes[hors_X], col = "#D32F2F", pch = 19, cex = 2)
}
text(17, LSC_X, sprintf("LSC = %.2f", LSC_X),
pos = 3, col = "#D32F2F", font = 2)
legend("topleft",
legend = sprintf("%d point(s) hors contrôle", length(hors_X)),
bty = "n", text.col = "#D32F2F", cex = 1.1)
# Graphique 2 : Sans alarme à 17 sec
indices_filtres <- (1:n)[-alarme_aberrante]
plot(indices_filtres, alarmes_filtrees, type = "b", pch = 19, col = "#1976D2",
main = "SANS alarme à 17 secondes (données filtrées)",
xlab = "Numéro d'alarme", ylab = "Temps (sec)",
ylim = c(0, max(alarmes) + 2), cex = 1.2, lwd = 1.5)
abline(h = LSC_X_filtrees, col = "#D32F2F", lty = 2, lwd = 2)
abline(h = LC_X, col = "#2E7D32", lwd = 2)
abline(h = LIC_X_filtrees, col = "#D32F2F", lty = 2, lwd = 2)
if (length(hors_X_filtrees) > 0) {
points(indices_filtres[hors_X_filtrees],
alarmes_filtrees[hors_X_filtrees],
col = "#D32F2F", pch = 19, cex = 2)
}
text(17, LSC_X_filtrees, sprintf("LSC = %.2f", LSC_X_filtrees),
pos = 3, col = "#D32F2F", font = 2)
legend("topleft",
legend = sprintf("%d point(s) hors contrôle", length(hors_X_filtrees)),
bty = "n",
text.col = ifelse(length(hors_X_filtrees) > 0, "#D32F2F", "#2E7D32"),
cex = 1.1)
Comparaison graphique : Avec vs Sans alarme à 17 sec
par(mfrow = c(1, 1))
Conclusion de l’analyse de sensibilité :
writeLines(c(
"",
"═══════════════════════════════════════════════════════════════",
" CONCLUSION : NATURE DE L'ANOMALIE",
"═══════════════════════════════════════════════════════════════",
"",
if (length(hors_X_filtrees) == 0 && length(hors_X) > 0) {
c(
"ANOMALIE ISOLÉE",
"",
"OBSERVATIONS :",
" • Avec alarme 17 sec : processus hors contrôle",
" • Sans alarme 17 sec : processus sous contrôle",
sprintf(" • Moyenne baisse de %.2f sec (%.0f%%)",
moyenne_originale - moyenne_filtree,
100*(moyenne_originale - moyenne_filtree)/moyenne_filtree),
"",
"INTERPRÉTATION :",
" → L'alarme à 17 sec est un cas isolé (défaut ponctuel)",
" → Le Processus de fabrication est globalement correct",
" → Les 19 autres alarmes sont conformes",
"",
"RECOMMANDATIONS :",
" 1. Analyser l'alarme n°15 individuellement (défaut matériel ?)",
" 2. La remplacer ou la réparer",
" 3. Ne pas remettre en cause tout le processus de fabrication",
" 4. Continuer la surveillance avec carte X-mR"
)
} else if (length(hors_X_filtrees) > 0) {
c(
" PROBLÈME SYSTÉMIQUE",
"",
"OBSERVATIONS :",
" • AVEC alarme 17 sec : processus hors contrôle",
" • SANS alarme 17 sec : processus encore hors contrôle",
sprintf(" • %d alarme(s) hors contrôle même après filtrage",
length(hors_X_filtrees)),
"",
"INTERPRÉTATION :",
" → Le problème ne se limite pas à l'alarme 17 sec",
" → Le Processus de Fabrication présente des défauts multiples",
" → Cause assignable générale à identifier",
"",
"RECOMMANDATIONS :",
" 1. Revoir complètement le processus de fabrication",
" 2. Identifier les causes racines (matière, machine, méthode...)",
" 3. Mettre en place des actions correctives globales",
" 4. Refaire une validation complète après corrections"
)
} else {
c(
"Processus sous contrôle",
"",
"Aucune anomalie détectée (même avec l'alarme à 17 sec)"
)
},
"",
"═══════════════════════════════════════════════════════════════",
""
))
═══════════════════════════════════════════════════════════════
CONCLUSION : NATURE DE L'ANOMALIE
═══════════════════════════════════════════════════════════════
ANOMALIE ISOLÉE
OBSERVATIONS :
• Avec alarme 17 sec : processus hors contrôle
• Sans alarme 17 sec : processus sous contrôle
• Moyenne baisse de 0.63 sec (14%)
INTERPRÉTATION :
→ L'alarme à 17 sec est un cas isolé (défaut ponctuel)
→ Le Processus de fabrication est globalement correct
→ Les 19 autres alarmes sont conformes
RECOMMANDATIONS :
1. Analyser l'alarme n°15 individuellement (défaut matériel ?)
2. La remplacer ou la réparer
3. Ne pas remettre en cause tout le processus de fabrication
4. Continuer la surveillance avec carte X-mR
═══════════════════════════════════════════════════════════════
# Tableau récapitulatif des critères
conclusion_df <- data.frame(
Critère = c(
"1. Valeurs atypiques",
"2. Test de normalité",
"3. Règle des 3σ",
"4. Conformité à la norme"
),
Résultat = c(
ifelse(length(atypiques) > 0,
paste(length(atypiques), "valeur atypique détectée"),
"Aucune valeur atypique"),
ifelse(test_shapiro$p.value < 0.05,
"Rejet normalité (anomalies présentes)",
"Données normales"),
ifelse(length(hors_limites) > 0,
paste(length(hors_limites), "observation hors limites"),
"Toutes observations dans les limites"),
ifelse(moyenne > mu_0,
paste("Moyenne =", round(moyenne, 2), "sec > norme (5 sec)"),
"Conforme à la norme")
),
Statut = c(
ifelse(length(atypiques) > 0, "Problème", "OK"),
ifelse(test_shapiro$p.value < 0.05, "Problème", "OK"),
ifelse(length(hors_limites) > 0, "Problème", "OK"),
ifelse(moyenne > mu_0, "Problème", "OK")
)
)
kable(conclusion_df,
caption = "Synthèse des critères d'analyse",
align = "llc",
col.names = c("Critère", "Résultat", "Statut")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
column_spec(3, bold = TRUE)
| Critère | Résultat | Statut |
|---|---|---|
|
1 valeur atypique détectée | Problème |
|
Rejet normalité (anomalies présentes) | Problème |
|
1 observation hors limites | Problème |
|
Conforme à la norme | OK |
Question : Le responsable pense que cette production n’est pas sous contrôle (principalement à cause de l’alarme qui a mis 17 secondes pour réagir). Êtes-vous d’accord avec lui ?
Réponse : OUI, nous sommes d’accord avec le responsable.
Justification : Sur les 4 critères analysés, 3 indiquent un problème :
Recommandations :
Nous considérons un procédé industriel qui, sous contrôle, suit une loi normale avec paramètres inconnus. L’objectif est de construire une carte de contrôle de Shewhart \((\bar{X}, R)\) de Phase I en utilisant les observations issues de 20 sous-groupes rationnels de taille \(n=4\).
Cette carte sera utilisée pour surveiller la position (\(\bar{X}\)) et la dispersion (\(R\)) du processus. Une analyse des résultats permettra de déterminer si le processus est sous contrôle ou nécessite des ajustements.
Dans le cas d’une carte de contrôle de phase I, il est nécessaire d’estimer les quantités \(\mu\) et \(\sigma\). L’idée est alors d’utiliser un maximum d’information, c’est-à-dire la totalité des \(nk\) observations.
Nous avons déjà vu que, pour chaque sous-groupe rationnel, \(\bar{X}_i\) est un estimateur sans biais de \(\mu\). Ces variables aléatoires ayant toutes une même dispersion, on sait qu’alors un estimateur sans biais plus efficace que chacun des \(\bar{X}_i\) est obtenu à partir de la population totale via la relation suivante :
\[\hat{\mu} = \bar{\bar{X}} = \frac{1}{k} \sum_{i=1}^k \bar{X}_i\]
De même, pour chaque sous-groupe rationnel, \(\frac{R_i}{d_2(n)}\) est un estimateur sans biais de \(\sigma\). Ces variables aléatoires ayant toutes une même dispersion, on sait qu’alors un estimateur sans biais plus efficace que chacun des \(\frac{R_i}{d_2(n)}\) est obtenu à partir de la population totale via la relation suivante :
\[\hat{\sigma} = \frac{\bar{R}}{d_2(n)} = \frac{1}{kd_2(n)} \sum_{i=1}^k R_i\]
où : - \(R_i = X_{i(n)} - X_{i(1)} = \max(X_{ij}) - \min(X_{ij})\) est l’étendue de l’échantillon \(i\) - \(\bar{R} = \frac{1}{k}\sum_{i=1}^k R_i\) est l’étendue moyenne - \(d_2(n)\) est une constante tabulée dépendant de \(n\)
Remarque du cours : Lorsque les \(X_{ij}\) sont des variables aléatoires indépendantes de même loi normale alors \(R_i\) suit une loi de probabilité complexe mais que l’on peut néanmoins déterminer explicitement. On montre alors que si \(X_{ij}\) suit une loi normale \(\mathcal{N}(\mu, \sigma)\) et si chaque sous-groupe rationnel est de taille \(n\) alors :
\[\mathbb{E}(R_i) = d_2(n) \cdot \sigma \quad \text{et} \quad \sigma(R_i) = d_3(n) \cdot \sigma\]
où les coefficients \(d_2\) et \(d_3\) sont tabulés.
# Chargement des données
Exemple3 <- read.csv("Exemple3.txt", sep = "", header = FALSE)
Nos données comportent deux variables et 80 observations, réparties en 20 échantillons, chacun comportant 4 éléments.
# Initialisation des vecteurs pour stocker les moyennes et les étendues
k <- 20 # Nombre d'échantillons
x_ex3 <- numeric(k)
r_ex3 <- numeric(k)
# Boucle pour calculer la moyenne et l'étendue pour chaque groupe
for (i in 1:k) {
sous_groupe <- Exemple3$V2[Exemple3$V1 == i]
n <- length(sous_groupe)
r_ex3[i] <- max(sous_groupe) - min(sous_groupe)
x_ex3[i] <- mean(sous_groupe)
}
# Constantes pour n=4 (valeurs tabulées du cours)
d2 <- 2.059 # Coefficient d2
d3 <- 0.880 # Coefficient d3
# Estimation des paramètres
mu_hat <- mean(x_ex3) # Estimation de μ
r_bar <- mean(r_ex3) # Étendue moyenne
sigma_hat <- r_bar / d2 # Estimation de σ
# Affichage des résultats
writeLines(c(
"",
"═══════════════════════════════════════════════════",
" ESTIMATION DES PARAMÈTRES (PHASE I)",
"═══════════════════════════════════════════════════",
sprintf("Moyenne estimée (μ̂) : %.4f", mu_hat),
sprintf("Étendue moyenne (R̄) : %.4f", r_bar),
sprintf("Écart-type estimé (σ̂) : %.4f", sigma_hat),
sprintf("Constante d2 pour n=%d : %.3f", n, d2),
"═══════════════════════════════════════════════════",
""
))
═══════════════════════════════════════════════════
ESTIMATION DES PARAMÈTRES (PHASE I)
═══════════════════════════════════════════════════
Moyenne estimée (μ̂) : 20.0449
Étendue moyenne (R̄) : 2.3194
Écart-type estimé (σ̂) : 1.1265
Constante d2 pour n=4 : 2.059
═══════════════════════════════════════════════════
Interprétation : Ces valeurs estimées (\(\hat{\mu}\) et \(\hat{\sigma}\)) serviront de référence pour la surveillance future du processus (Phase II).
Le principe de construction est le suivant :
1. Positionnement de la ligne centrale à la valeur théorique moyenne : \[\mathbb{E}[\bar{X}_i] = \mu \simeq \hat{\mu} = \bar{\bar{X}}\]
2. Positionnement des limites de contrôle selon la règle des \(3\sigma\) :
\[\begin{align} \text{LSC} &= \hat{\mu} + 3 \cdot \frac{\hat{\sigma}}{\sqrt{n}} = \bar{\bar{X}} + 3 \cdot \frac{\bar{R}}{d_2\sqrt{n}} \\[0.3cm] \text{LC} &= \hat{\mu} = \bar{\bar{X}} \\[0.3cm] \text{LCI} &= \hat{\mu} - 3 \cdot \frac{\hat{\sigma}}{\sqrt{n}} = \bar{\bar{X}} - 3 \cdot \frac{\bar{R}}{d_2\sqrt{n}} \end{align}\]
# Calcul des limites pour carte X̄
sigma_xbar <- sigma_hat / sqrt(n)
LIC_xbar3 <- mu_hat - 3 * sigma_xbar
LSC_xbar3 <- mu_hat + 3 * sigma_xbar
# Affichage des limites
afficher_limites(LSC_xbar3, mu_hat, LIC_xbar3, sigma_xbar, "Carte X̄ Phase I")
┌─────────────────────────────────────────────┐
│ LIMITES DE CONTRÔLE (Carte X̄ Phase I) │
├─────────────────────────────────────────────┤
│ LSC = 21.7346 │
│ LC = 20.0449 │
│ LCI = 18.3553 │
├─────────────────────────────────────────────┤
│ σ = 0.5632 │
└─────────────────────────────────────────────┘
df_xbar3 <- data.frame(
echantillon = 1:k,
moyenne = x_ex3,
hors_limite = ifelse(x_ex3 > LSC_xbar3 | x_ex3 < LIC_xbar3,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_xbar3, aes(x = echantillon, y = moyenne)) +
annotate("rect", xmin = 0, xmax = k+1,
ymin = LIC_xbar3, ymax = LSC_xbar3,
alpha = 0.15, fill = "lightgreen") +
geom_hline(yintercept = mu_hat, color = "#2E7D32", linewidth = 1.2) +
geom_hline(yintercept = LSC_xbar3, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_hline(yintercept = LIC_xbar3, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_line(color = "#1976D2", linewidth = 1) +
geom_point(aes(color = hors_limite), size = 3.5) +
annotate("text", x = k-2, y = LSC_xbar3,
label = paste("LSC =", round(LSC_xbar3, 3)),
vjust = -0.7, color = "#D32F2F", fontface = "bold") +
annotate("text", x = k-2, y = LIC_xbar3,
label = paste("LCI =", round(LIC_xbar3, 3)),
vjust = 1.7, color = "#D32F2F", fontface = "bold") +
annotate("text", x = k-2, y = mu_hat,
label = paste("μ̂ =", round(mu_hat, 3)),
vjust = -0.7, color = "#2E7D32", fontface = "bold") +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte X barre - Phase I",
subtitle = "Paramètres estimés à partir des données",
x = "Numéro d'échantillon",
y = "Moyenne",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "gray30"),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte X̄ Phase I - Paramètres estimés
Le processus semble être sous contrôle en moyenne. Aucun échantillon ne présente de moyenne anormalement élevée ou basse.
Le principe de construction est le suivant :
1. Positionnement de la ligne centrale à la valeur théorique moyenne suivante : \[\mathbb{E}[R_i] = d_2(n) \cdot \sigma \simeq d_2(n) \cdot \hat{\sigma} = \bar{R}\]
2. Positionnement des limites de contrôle selon la règle des \(3\sigma\) à partir de :
\[\sigma(R_i) = d_3(n) \cdot \sigma \simeq d_3(n) \cdot \hat{\sigma} = \frac{d_3(n)}{d_2(n)} \cdot \bar{R}\]
Il vient donc :
\[\begin{align} \text{LSC} &= \bar{R} + 3 \cdot \frac{d_3(n)}{d_2(n)} \cdot \bar{R} \\[0.3cm] \text{LC} &= \bar{R} \\[0.3cm] \text{LCI} &= \bar{R} - 3 \cdot \frac{d_3(n)}{d_2(n)} \cdot \bar{R} \end{align}\]
Remarque du cours : Attention au fait que, contrairement à la carte de contrôle \(\bar{X}\), les quantités représentées sont ici des réalisations des variables aléatoires réelles \(R_i\) qui, même sous hypothèse de normalité des observations, ne suivent pas naturellement une loi normale ! Il peut en découler des problèmes concernant les limites de contrôle ainsi calculées (par exemple obtenir LCI négative, ce qui n’a pas de sens). Dans ce cas, on pose LCI = 0.
# Limites carte R
sigma_r <- (d3/d2) * r_bar
LIC_r <- r_bar - 3 * sigma_r
LSC_r <- r_bar + 3 * sigma_r
if (LIC_r < 0) LIC_r <- 0
# Affichage des limites
afficher_limites(LSC_r, r_bar, LIC_r, sigma_r, "Carte R")
┌─────────────────────────────────────────────┐
│ LIMITES DE CONTRÔLE (Carte R ) │
├─────────────────────────────────────────────┤
│ LSC = 5.2932 │
│ LC = 2.3194 │
│ LCI = 0.0000 │
├─────────────────────────────────────────────┤
│ σ = 0.9913 │
└─────────────────────────────────────────────┘
df_r <- data.frame(
echantillon = 1:k,
etendue = r_ex3,
hors_limite = ifelse(r_ex3 > LSC_r | r_ex3 < LIC_r,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_r, aes(x = echantillon, y = etendue)) +
annotate("rect", xmin = 0, xmax = k+1,
ymin = LIC_r, ymax = LSC_r,
alpha = 0.15, fill = "lightblue") +
geom_hline(yintercept = r_bar, color = "#2E7D32", linewidth = 1.2) +
geom_hline(yintercept = LSC_r, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_hline(yintercept = LIC_r, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_line(color = "#1976D2", linewidth = 1) +
geom_point(aes(color = hors_limite), size = 3.5) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte R - Phase I",
subtitle = "Surveillance de la variabilité par l'étendue",
x = "Numéro d'échantillon",
y = "Étendue (R)",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "gray30"),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte R - Surveillance de l’étendue
Le processus semble être sous contrôle en termes de dispersion.
Conclusion Exemple 3 :
Nous avons établi une carte de contrôle de Shewhart \((\bar{X}, R)\) de Phase I. Le processus semble être sous contrôle tant en termes de moyenne qu’en termes d’étendue. Les deux cartes montrent un processus sous contrôle statistique.
Les paramètres estimés peuvent être utilisés comme référence pour la surveillance future : - \(\mu_0 = \hat{\mu} = 20.0449\) - \(\sigma_0 = \hat{\sigma} = 1.1265\)
Une entreprise s’intéresse au nombre total de défauts d’aspect comptabilisés sur un produit fini. Pour être sous contrôle, la production doit être réalisée avec un nombre moyen de défauts d’aspect de l’ordre de 8. Ces divers nombres ont été relevés pour un échantillon de 50 observations.
On impose ici une étude à l’aide d’une carte de contrôle de phase II avec des limites probabilistes associées à un risque d’erreur de première espèce ne dépassant pas 10%.
Nous nous intéressons au nombre moyen de défauts, c’est pourquoi nous utiliserons des cartes de contrôle pour attributs, et plus précisément la carte c.
Les cartes de contrôle aux attributs s’appliquent lorsque la caractéristique de qualité n’est pas mesurable numériquement mais peut être classée en catégories (conforme/non conforme, nombre de défauts, etc.).
Types de cartes aux attributs :
Quand on compte des événements rares sur une unité (défauts, non-conformités), le nombre \(C\) suit une loi de Poisson de paramètre \(\lambda\) :
\[C \sim \mathcal{P}(\lambda) \quad \Rightarrow \quad P(C = k) = \frac{\lambda^k e^{-\lambda}}{k!}\]
Propriétés de la loi de Poisson :
La carte \(c\) est utilisée pour surveiller le nombre de défauts lorsque :
Dans le cas standard, les limites de contrôle sont données par :
\[\begin{align} \text{LSC} &= \lambda_0 + 3\sqrt{\lambda_0} \\[0.3cm] \text{LC} &= \lambda_0 \\[0.3cm] \text{LCI} &= \lambda_0 - 3\sqrt{\lambda_0} \end{align}\]
Si LCI < 0, on pose LCI = 0.
Pour trouver les limites de contrôle avec un risque \(\alpha\), il est nécessaire de déterminer les quantiles de la distribution de Poisson avec \(\lambda = \lambda_0\) qui couvrent \((1-\alpha) \times 100\%\) de la probabilité.
Construction des limites probabilistes :
En pratique, pour une carte de contrôle en phase II avec limites probabilistes, les limites sont calculées en trouvant les valeurs \(c\) telles que :
\[P(C \leq \text{LCI}) \leq \frac{\alpha}{2} \quad \text{et} \quad P(C \geq \text{LSC}) \leq \frac{\alpha}{2}\]
où \(\alpha\) est le risque total d’erreur de première espèce, donc \(\frac{\alpha}{2}\) de chaque côté.
Formulation mathématique :
En utilisant les quantiles de la loi de Poisson :
\[\begin{align} \text{LCI} &= Q_{\alpha/2}(\lambda_0) \\[0.3cm] \text{LC} &= \lambda_0 \\[0.3cm] \text{LSC} &= Q_{1-\alpha/2}(\lambda_0) \end{align}\]
où \(Q_p(\lambda)\) désigne le quantile d’ordre \(p\) de la loi \(\mathcal{P}(\lambda)\).
# Chargement des données
Exemple4 <- read.csv("Exemple4.txt", header = FALSE)
x_ex4 <- as.numeric(Exemple4$V1)
Nos données comportent une variable et 50 observations.
lambda <- 8
sigma <- sd(Exemple4$V1)
alpha <- 0.10
# Limites probabilistes (quantiles de la loi de Poisson)
# Recherche de LIC
LIC_c <- 0
for (k in 0:20) {
if (ppois(k, lambda) <= alpha/2) {
LIC_c <- k
} else {
break
}
}
# Recherche de LSC
LSC_c <- 20
for (k in 1:20) {
if (1 - ppois(k - 1, lambda) <= alpha/2) {
LSC_c <- k
break
}
}
# Affichage des limites
writeLines(c(
"",
"================================================================",
" LIMITES PROBABILISTES (alpha = 10%)",
"================================================================",
sprintf("Risque total : alpha = %.0f%%", alpha*100),
sprintf("Risque par queue : alpha/2 = %.0f%%", (alpha/2)*100),
"",
sprintf("LCI = %d", LIC_c),
sprintf(" Cible : P(C <= LCI) = alpha/2 = %.0f%%", (alpha/2)*100),
sprintf(" Reel : P(C <= %d) = %.1f%%", LIC_c, 100*ppois(LIC_c, lambda)),
"",
sprintf("LC = %d", lambda),
"",
sprintf("LSC = %d", LSC_c),
sprintf(" Cible : P(C >= LSC) = alpha/2 = %.0f%%", (alpha/2)*100),
sprintf(" Reel : P(C >= %d) = %.1f%%", LSC_c, 100*(1-ppois(LSC_c-1, lambda))),
"",
sprintf("Probabilite d'etre dans les limites : %.1f%%",
100*(ppois(LSC_c-1, lambda) - ppois(LIC_c, lambda)),
"",
"NOTE : En raison de la nature discrete de la loi de Poisson,",
" les probabilites reelles different des cibles theoriques.",
"================================================================",
""
)))
================================================================
LIMITES PROBABILISTES (alpha = 10%)
================================================================
Risque total : alpha = 10%
Risque par queue : alpha/2 = 5%
LCI = 3
Cible : P(C <= LCI) = alpha/2 = 5%
Reel : P(C <= 3) = 4.2%
LC = 8
LSC = 14
Cible : P(C >= LSC) = alpha/2 = 5%
Reel : P(C >= 14) = 3.4%
Probabilite d'etre dans les limites : 92.3%
Interprétation :
Les limites sont déterminées par les quantiles de la loi de Poisson :
- LCI = 3 : Plus petit entier k tel que P(C ≤ k) ≥ α/2
- Valeur réelle : P(C ≤ 3) ≈ 4.2% - Cible théorique : 5% - LSC =
14 : Plus petit entier k tel que P(C ≤ k) ≥ 1-α/2
- Valeur réelle : P(C ≥ 14) ≈ 3.4% - Cible théorique : 5%
df_c <- data.frame(
observation = 1:length(x_ex4),
defauts = x_ex4,
hors_limite = ifelse(x_ex4 > LSC_c | x_ex4 < LIC_c,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_c, aes(x = observation, y = defauts)) +
annotate("rect", xmin = 0, xmax = length(x_ex4)+1,
ymin = LIC_c, ymax = LSC_c,
alpha = 0.15, fill = "lightyellow") +
geom_hline(yintercept = lambda, color = "#2E7D32", linewidth = 1.2) +
geom_hline(yintercept = LSC_c, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_hline(yintercept = LIC_c, color = "#D32F2F",
linewidth = 1, linetype = "dashed") +
geom_line(color = "#1976D2", linewidth = 1) +
geom_point(aes(color = hors_limite), size = 3) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte c - Nombre de Défauts d'Aspect",
subtitle = "Loi de Poisson, lambda = 8, risque alpha = 10%",
x = "Numéro d'observation",
y = "Nombre de défauts",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5),
panel.grid.minor = element_blank(),
legend.position = "bottom"
) +
scale_y_continuous(breaks = seq(0, max(x_ex4), 2))
Carte c - Nombre de défauts avec limites probabilistes
Le processus semble être hors de contrôle, car deux points dépassent les limites.
Interprétation : Les limites probabilistes sont plus larges que les limites \(3\sigma\) classiques car on accepte un risque de 10% au lieu de 0,27%. Cela réduit les fausses alarmes mais peut retarder la détection de déréglages.
On considère ici un procédé industriel qui, sous contrôle, doit suivre une loi normale de type \(\mathcal{N}(50, 1)\). On aimerait savoir si le procédé est sous contrôle ou non en moyenne sachant qu’un déréglage lent est suspecté. Pour cela, 50 échantillons de 10 observations ont été prélevés.
Question : Proposer une méthode d’étude pour ces observations et commenter les résultats obtenus.
D’après le Chapitre 5 du cours :
“Les cartes de contrôle de type Shewhart (\(\bar{X}\), \(R\), \(S\)) sont très efficaces pour détecter les grands déréglages (variations importantes et brutales), mais elles sont peu sensibles aux petits déréglages ou aux dérives lentes du processus.”
Démonstration pour notre cas :
Pour une carte \(\bar{X}\) classique avec \(n=10\), \(\mu_0 = 50\), \(\sigma_0 = 1\) :
\[\text{LSC} = \mu_0 + 3\frac{\sigma_0}{\sqrt{n}} = 50 + 3\frac{1}{\sqrt{10}} = 50 + 3 \times 0.316 = 50.949\] \[\text{LCI} = \mu_0 - 3\frac{\sigma_0}{\sqrt{n}} = 50 - 0.949 = 49.051\]
Problème : Si le processus dérive lentement (ex: \(+0.2\) par échantillon), chaque observation reste dans les limites \([49.051; 50.949]\) pendant plusieurs échantillons. La carte \(\bar{X}\) ne détecte rien car elle traite chaque échantillon indépendamment sans tenir compte de l’historique.
Exemple numérique :
================================================================
SIMULATION : Derive lente (+0.05 par echantillon)
================================================================
Echantillon 1 : X̄ = 50.10 [Dans limites] V
Echantillon 2 : X̄ = 50.15 [Dans limites] V
Echantillon 3 : X̄ = 50.20 [Dans limites] V
Echantillon 4 : X̄ = 50.25 [Dans limites] V
Echantillon 5 : X̄ = 50.30 [Dans limites] V
Echantillon 6 : X̄ = 50.35 [Dans limites] V
Echantillon 7 : X̄ = 50.40 [Dans limites] V
-> Carte X-bar classique : AUCUNE DETECTION
-> Derive de 0.4 (soit 40%% de sigma) NON DETECTEE !
================================================================
Principe:
Les cartes à mémoire (MA et EWMA) accumulent l’information des échantillons passés pour détecter les tendances et les dérives progressives.
Deux approches complémentaires :
On considère un procédé industriel qui, lorsqu’il est sous contrôle, suit une loi normale de type \(\mathcal{N}(50, 1)\). L’objectif est de déterminer si le procédé est sous contrôle, notamment en moyenne, en prenant en compte la possibilité d’un déréglage lent.
À cette fin, 50 échantillons de 10 observations chacun ont été prélevés.
Une carte de contrôle de type \(\bar{X}\) repose sur la représentation des moyennes des sous-groupes rationnels \(\bar{x}_1, \bar{x}_2, \ldots, \bar{x}_k\). L’objectif des cartes de contrôle de type MA (Moving Average) est de remplacer ces moyennes par des moyennes mobiles d’ordre \(h\), afin de détecter les petits dérèglements dans le processus.
Définition 10 du cours : Une carte de contrôle de type MA, construite avec des moyennes mobiles d’ordre \(h\), consiste en la représentation des valeurs \(m_1, \ldots, m_k\) réalisations des variables aléatoires \(M_1, \ldots, M_k\) définies par :
\[M_i = \begin{cases} \displaystyle\frac{\bar{X}_i + \bar{X}_{i-1} + \ldots + \bar{X}_1}{i} & \text{si } i < h \\[0.5cm] \displaystyle\frac{\bar{X}_i + \bar{X}_{i-1} + \ldots + \bar{X}_{i-h+1}}{h} & \text{si } i \geq h \end{cases}\]
On parlera de moyennes mobiles incomplètes pour les \((h-1)\) premiers relevés et de moyennes mobiles complètes ensuite.
Remarque du cours : Il est clair que dans la situation où \(h = 1\) on retombe alors sur la carte classique de type \(\bar{X}\). Lorsque \(h \geq k\) alors la carte de contrôle utilisée tient compte de l’intégralité du passé quel que soit le sous-groupe rationnel considéré.
On utilise ici la méthode classique de construction avec la ligne centrale positionnée à la valeur moyenne théorique et les limites de contrôle découlant de la règle des \(3\sigma\). Il en découle que :
1. Positionnement de la ligne centrale à la valeur théorique \(\mathbb{E}[M_i]\) avec donc (valeur identique pour le cas des moyennes mobiles incomplètes) :
\[\mathbb{E}[M_i] = \mathbb{E}\left[\frac{\bar{X}_i + \bar{X}_{i-1} + \ldots + \bar{X}_{i-h+1}}{h}\right] = \frac{1}{h} \sum_{j=0}^{h-1} \mathbb{E}[\bar{X}_{i-j}] = \frac{h\mu_0}{h} = \mu_0\]
puisque si le processus est sous contrôle chaque observation est une réalisation de la loi normale \(\mathcal{N}(\mu_0, \sigma_0)\) et donc \(\mathbb{E}[\bar{X}_{i-j}] = \mu_0\).
2. Positionnement des limites de contrôle selon la règle des \(3\sigma\). Il faut alors distinguer le cas des moyennes mobiles complètes ou incomplètes puisqu’il vient (d’après l’indépendance des observations) :
Si \(M_i = \frac{\bar{X}_i + \bar{X}_{i-1} + \ldots + \bar{X}_1}{i}\) alors : \[\text{Var}(M_i) = \frac{1}{i^2} \sum_{j=0}^{i-1} \text{Var}(\bar{X}_{i-j}) = \frac{i \cdot \frac{\sigma_0^2}{n}}{i^2} = \frac{\sigma_0^2}{ni}\]
Si \(M_i = \frac{\bar{X}_i + \bar{X}_{i-1} + \ldots + \bar{X}_{i-h+1}}{h}\) alors : \[\text{Var}(M_i) = \frac{1}{h^2} \sum_{j=0}^{h-1} \text{Var}(\bar{X}_{i-j}) = \frac{h \cdot \frac{\sigma_0^2}{n}}{h^2} = \frac{\sigma_0^2}{nh}\]
Proposition 11 du cours : Une carte de contrôle de type MA, utilisée avec des moyennes mobiles d’ordre \(h\), est déterminée par :
La ligne centrale à la valeur \(\mu_0\)
Les limites de contrôle de valeurs (pour le sous-groupe rationnel \(i = 1, 2, \ldots, k\)) :
\[\text{LCI}_i = \mu_0 - 3 \cdot \frac{\sigma_0}{\sqrt{ni}} \quad \text{et} \quad \text{LSC}_i = \mu_0 + 3 \cdot \frac{\sigma_0}{\sqrt{ni}} \quad \text{si } i < h\]
\[\text{LCI}_i = \mu_0 - 3 \cdot \frac{\sigma_0}{\sqrt{nh}} \quad \text{et} \quad \text{LSC}_i = \mu_0 + 3 \cdot \frac{\sigma_0}{\sqrt{nh}} \quad \text{si } i \geq h\]
Ceci conduit graphiquement à des limites de contrôle en créneaux comme sur la carte suivante (construite ici avec des moyennes mobiles d’ordre \(h = 3\)).
# Chargement des données
Exemple5 <- read.csv("Exemple5.txt", sep = "", header = FALSE)
Nos données comportent deux variables et 500 observations, réparties en 50 échantillons, chacun comportant 10 éléments.
# Calcul unifié de toutes les moyennes mobiles (ordres 3, 4, 5)
# Calcul des moyennes des échantillons
x_ex5 <- numeric(50)
for (i in 1:50) {
x_ex5[i] <- mean(Exemple5$V2[Exemple5$V1 == i])
}
# Paramètres
mu_0 <- 50
sigma_0 <- 1
n_obs <- 10
# -------------------- MA ORDRE 3 --------------------
h3 <- 3
M3 <- numeric(50)
LSC_ma3 <- numeric(50)
LIC_ma3 <- numeric(50)
for (i in 1:50) {
if (i < h3) {
M3[i] <- mean(x_ex5[1:i])
LIC_ma3[i] <- mu_0 - 3 * sigma_0 / sqrt(i * n_obs)
LSC_ma3[i] <- mu_0 + 3 * sigma_0 / sqrt(i * n_obs)
} else {
M3[i] <- mean(x_ex5[(i-h3+1):i])
LIC_ma3[i] <- mu_0 - 3 * sigma_0 / sqrt(h3 * n_obs)
LSC_ma3[i] <- mu_0 + 3 * sigma_0 / sqrt(h3 * n_obs)
}
}
# -------------------- MA ORDRE 4 --------------------
h4 <- 4
M4 <- numeric(50)
LSC_ma4 <- numeric(50)
LIC_ma4 <- numeric(50)
for (i in 1:50) {
if (i < h4) {
M4[i] <- mean(x_ex5[1:i])
LIC_ma4[i] <- mu_0 - 3 * sigma_0 / sqrt(i * n_obs)
LSC_ma4[i] <- mu_0 + 3 * sigma_0 / sqrt(i * n_obs)
} else {
M4[i] <- mean(x_ex5[(i-h4+1):i])
LIC_ma4[i] <- mu_0 - 3 * sigma_0 / sqrt(h4 * n_obs)
LSC_ma4[i] <- mu_0 + 3 * sigma_0 / sqrt(h4 * n_obs)
}
}
# -------------------- MA ORDRE 5 --------------------
h5 <- 5
M5 <- numeric(50)
LSC_ma5 <- numeric(50)
LIC_ma5 <- numeric(50)
for (i in 1:50) {
if (i < h5) {
M5[i] <- mean(x_ex5[1:i])
LIC_ma5[i] <- mu_0 - 3 * sigma_0 / sqrt(i * n_obs)
LSC_ma5[i] <- mu_0 + 3 * sigma_0 / sqrt(i * n_obs)
} else {
M5[i] <- mean(x_ex5[(i-h5+1):i])
LIC_ma5[i] <- mu_0 - 3 * sigma_0 / sqrt(h5 * n_obs)
LSC_ma5[i] <- mu_0 + 3 * sigma_0 / sqrt(h5 * n_obs)
}
}
# -------------------- COMPTAGE POINTS HC --------------------
hors_ma3 <- sum(M3 > LSC_ma3 | M3 < LIC_ma3)
hors_ma4 <- sum(M4 > LSC_ma4 | M4 < LIC_ma4)
hors_ma5 <- sum(M5 > LSC_ma5 | M5 < LIC_ma5)
# Affichage résumé
writeLines(c(
"",
"================================================================",
" COMPTAGE POINTS HORS CONTROLE (CARTES MA)",
"================================================================",
sprintf("MA ordre 3 (h=3) : %d points HC / 50", hors_ma3),
sprintf("MA ordre 4 (h=4) : %d points HC / 50", hors_ma4),
sprintf("MA ordre 5 (h=5) : %d points HC / 50", hors_ma5),
"================================================================",
""
))
================================================================
COMPTAGE POINTS HORS CONTROLE (CARTES MA)
================================================================
MA ordre 3 (h=3) : 1 points HC / 50
MA ordre 4 (h=4) : 1 points HC / 50
MA ordre 5 (h=5) : 1 points HC / 50
================================================================
# Pour compatibilité avec le reste du code
M <- M3
LSC_ma <- LSC_ma3
LIC_ma <- LIC_ma3
Tableau récapitulatif des résultats :
# Sélection d'échantillons représentatifs
echantillons_cles <- c(1, 10, 20, 30, 40, 45, 50)
tableau_ma3 <- data.frame(
Ech = echantillons_cles,
LSC = round(LSC_ma[echantillons_cles], 3),
M = round(M[echantillons_cles], 3),
LIC = round(LIC_ma[echantillons_cles], 3)
)
kable(tableau_ma3,
caption = "Résultats MA ordre 3 (échantillons sélectionnés)",
align = "c",
col.names = c("Éch.", "LSC", "M", "LIC")) |>
kable_styling(bootstrap_options = c("striped", "condensed"),
full_width = FALSE, font_size = 10)
| Éch. | LSC | M | LIC |
|---|---|---|---|
| 1 | 50.949 | 50.333 | 49.051 |
| 10 | 50.548 | 50.235 | 49.452 |
| 20 | 50.548 | 50.231 | 49.452 |
| 30 | 50.548 | 50.222 | 49.452 |
| 40 | 50.548 | 50.218 | 49.452 |
| 45 | 50.548 | 50.461 | 49.452 |
| 50 | 50.548 | 50.396 | 49.452 |
df_ma <- data.frame(
echantillon = 1:50,
moyenne_mobile = M,
LSC = LSC_ma,
LIC = LIC_ma,
hors_limite = ifelse(M > LSC_ma | M < LIC_ma,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_ma, aes(x = echantillon)) +
# Zone de contrôle avec limites variables
geom_ribbon(aes(ymin = LIC, ymax = LSC),
alpha = 0.2, fill = "lightgreen") +
geom_line(aes(y = LSC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_line(aes(y = LIC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_hline(yintercept = mu_0, color = "#2E7D32", linewidth = 1.2) +
geom_line(aes(y = moyenne_mobile), color = "#1976D2", linewidth = 1) +
geom_point(aes(y = moyenne_mobile, color = hors_limite), size = 3) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte MA (Moyennes Mobiles) - Ordre 3",
subtitle = "Processus : moyenne = 50, ecart-type = 1, n = 10",
x = "Numéro d'échantillon",
y = "Moyenne mobile",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte MA ordre 3 - Détection des dérives lentes
Avec la moyenne mobile d’ordre 3, on a un point qui sort, donc le processus semble ne pas être sous contrôle.
h <- 4
M4 <- numeric(50)
for (i in 1:50) {
if (i < h) {
M4[i] <- mean(x_ex5[1:i])
} else {
M4[i] <- mean(x_ex5[(i-h+1):i])
}
}
LIC_ma4 <- numeric(50)
LSC_ma4 <- numeric(50)
for (i in 1:50) {
if (i < h) {
LIC_ma4[i] <- mu_0 - 3 * sigma_0 / sqrt(i * n_obs)
LSC_ma4[i] <- mu_0 + 3 * sigma_0 / sqrt(i * n_obs)
} else {
LIC_ma4[i] <- mu_0 - 3 * sigma_0 / sqrt(h * n_obs)
LSC_ma4[i] <- mu_0 + 3 * sigma_0 / sqrt(h * n_obs)
}
}
df_ma4 <- data.frame(
echantillon = 1:50,
moyenne_mobile = M4,
LSC = LSC_ma4,
LIC = LIC_ma4,
hors_limite = ifelse(M4 > LSC_ma4 | M4 < LIC_ma4,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_ma4, aes(x = echantillon)) +
geom_ribbon(aes(ymin = LIC, ymax = LSC),
alpha = 0.2, fill = "lightgreen") +
geom_line(aes(y = LSC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_line(aes(y = LIC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_hline(yintercept = mu_0, color = "#2E7D32", linewidth = 1.2) +
geom_line(aes(y = moyenne_mobile), color = "#1976D2", linewidth = 1) +
geom_point(aes(y = moyenne_mobile, color = hors_limite), size = 3) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte MA - Ordre 4",
subtitle = "Lissage plus important, détection de dérive",
x = "Numéro d'échantillon",
y = "Moyenne mobile",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte MA ordre 4
Avec la moyenne mobile d’ordre 4, on a un point qui sort, donc le processus semble ne pas être sous contrôle.
h <- 5
M5 <- numeric(50)
for (i in 1:50) {
if (i < h) {
M5[i] <- mean(x_ex5[1:i])
} else {
M5[i] <- mean(x_ex5[(i-h+1):i])
}
}
LIC_ma5 <- numeric(50)
LSC_ma5 <- numeric(50)
for (i in 1:50) {
if (i < h) {
LIC_ma5[i] <- mu_0 - 3 * sigma_0 / sqrt(i * n_obs)
LSC_ma5[i] <- mu_0 + 3 * sigma_0 / sqrt(i * n_obs)
} else {
LIC_ma5[i] <- mu_0 - 3 * sigma_0 / sqrt(h * n_obs)
LSC_ma5[i] <- mu_0 + 3 * sigma_0 / sqrt(h * n_obs)
}
}
df_ma5 <- data.frame(
echantillon = 1:50,
moyenne_mobile = M5,
LSC = LSC_ma5,
LIC = LIC_ma5,
hors_limite = ifelse(M5 > LSC_ma5 | M5 < LIC_ma5,
"Hors contrôle", "Sous contrôle")
)
ggplot(df_ma5, aes(x = echantillon)) +
geom_ribbon(aes(ymin = LIC, ymax = LSC),
alpha = 0.2, fill = "lightgreen") +
geom_line(aes(y = LSC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_line(aes(y = LIC), color = "#D32F2F",
linewidth = 0.8, linetype = "dashed") +
geom_hline(yintercept = mu_0, color = "#2E7D32", linewidth = 1.2) +
geom_line(aes(y = moyenne_mobile), color = "#1976D2", linewidth = 1) +
geom_point(aes(y = moyenne_mobile, color = hors_limite), size = 3) +
scale_color_manual(values = c("Sous contrôle" = "#1976D2",
"Hors contrôle" = "#D32F2F")) +
labs(
title = "Carte MA - Ordre 5",
x = "Numéro d'échantillon",
y = "Moyenne mobile",
color = "État"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte MA ordre 5
Résultat : Avec la moyenne mobile d’ordre 5, on observe un point hors contrôle (visible sur le graphique autour de l’échantillon 47), donc le processus n’est pas sous contrôle.
Observation importante : Le fait que même MA ordre 5 (avec le lissage le plus fort) détecte une anomalie confirme la présence d’un déréglage lent significatif dans le processus. On observe une tendance à la hausse progressive, particulièrement marquée dans les derniers échantillons (échantillons 40-50).
# Tableau comparatif des trois ordres MA
comparaison_ma <- data.frame(
Ordre_h = c(3, 4, 5),
LSC_final = c(round(LSC_ma3[50], 4), round(LSC_ma4[50], 4), round(LSC_ma5[50], 4)),
LIC_final = c(round(LIC_ma3[50], 4), round(LIC_ma4[50], 4), round(LIC_ma5[50], 4)),
Largeur = c(
round(LSC_ma3[50] - LIC_ma3[50], 4),
round(LSC_ma4[50] - LIC_ma4[50], 4),
round(LSC_ma5[50] - LIC_ma5[50], 4)
),
Points_HC = c(hors_ma3, hors_ma4, hors_ma5),
Conclusion = c(
ifelse(hors_ma3 == 0, "Sous controle", "Hors controle"),
ifelse(hors_ma4 == 0, "Sous controle", "Hors controle"),
ifelse(hors_ma5 == 0, "Sous controle", "Hors controle")
)
)
kable(comparaison_ma,
caption = "Comparaison des cartes MA d'ordres 3, 4 et 5",
align = "c",
col.names = c("Ordre h", "LSC", "LCI", "Largeur", "Points HC", "Conclusion")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = TRUE) |>
column_spec(1, bold = TRUE, background = couleurs$zone_acceptable) |>
column_spec(6, bold = TRUE,
color = ifelse(comparaison_ma$Conclusion == "Sous controle", "darkgreen", "darkred"))
| Ordre h | LSC | LCI | Largeur | Points HC | Conclusion |
|---|---|---|---|---|---|
| 3 | 50.5477 | 49.4523 | 1.0954 | 1 | Hors controle |
| 4 | 50.4743 | 49.5257 | 0.9487 | 1 | Hors controle |
| 5 | 50.4243 | 49.5757 | 0.8485 | 1 | Hors controle |
La carte EWMA (Exponentially Weighted Moving Average) utilise une moyenne mobile à pondération exponentielle qui donne plus de poids aux observations récentes tout en conservant toute l’histoire du processus.
Définition : La statistique EWMA \(Z_i\) est définie récursivement par :
\[Z_i = \lambda \bar{X}_i + (1-\lambda) Z_{i-1} \quad \text{avec } Z_0 = \mu_0\]
où : - \(\lambda \in (0, 1]\) est la constante de lissage - \(\bar{X}_i\) est la moyenne de l’échantillon \(i\) - \(Z_{i-1}\) est la valeur EWMA de l’échantillon précédent
Développement : On peut montrer que :
\[Z_i = \lambda \sum_{j=0}^{i-1} (1-\lambda)^j \bar{X}_{i-j} + (1-\lambda)^i \mu_0\]
Interprétation : Les observations passées ont un poids qui décroît exponentiellement : - Observation actuelle \(\bar{X}_i\) : poids \(\lambda\) - Observation précédente \(\bar{X}_{i-1}\) : poids \(\lambda(1-\lambda)\) - Observation \(\bar{X}_{i-2}\) : poids \(\lambda(1-\lambda)^2\) - etc.
Remarque du cours : - \(\lambda\) proche de 1 (ex: 0.9) → carte réagit rapidement, peu de mémoire (≈ carte \(\bar{X}\) classique) - \(\lambda\) proche de 0 (ex: 0.1) → carte réagit lentement, forte mémoire du passé
Recommandation du cours : Pour détecter les petits déréglages (\(\leq 1.5\sigma\)), utiliser \(\lambda \in [0.1, 0.3]\).
Espérance de \(Z_i\) :
D’après le cours, si le processus est sous contrôle :
\[\mathbb{E}[Z_i] = \mu_0\]
Variance de \(Z_i\) :
D’après la Proposition 13 du cours :
\[\text{Var}(Z_i) = \frac{\omega^2 \sigma_0^2}{n} \cdot \frac{1 - (1-\omega)^{2i}}{1 - (1-\omega)^2}\]
En simplifiant \(\frac{1}{1 - (1-\omega)^2} = \frac{1}{2\omega - \omega^2} = \frac{1}{\omega(2-\omega)}\), on obtient :
\[\text{Var}(Z_i) = \frac{\sigma_0^2}{n} \cdot \frac{\omega}{2-\omega} \cdot \left[1 - (1-\omega)^{2i}\right]\]
Limites de contrôle exactes (Proposition 13) :
Selon la règle des \(3\sigma\), les limites de contrôle sont représentées par les fonctions :
\[t \to \mu_0 \pm 3\sigma_0\sqrt{\frac{\omega}{n(2-\omega)} \left[1 - (1-\omega)^{2t}\right]}\]
Pour l’échantillon \(i\), on a donc :
\[\text{LSC}_i = \mu_0 + 3\sigma_0\sqrt{\frac{\omega}{n(2-\omega)} \left[1 - (1-\omega)^{2i}\right]}\]
\[\text{LCI}_i = \mu_0 - 3\sigma_0\sqrt{\frac{\omega}{n(2-\omega)} \left[1 - (1-\omega)^{2i}\right]}\]
Remarque importante : Ces limites convergent lorsque \(i \to \infty\) vers les limites asymptotiques :
\[\text{LSC}_\infty = \mu_0 + 3\sigma_0\sqrt{\frac{\omega}{n(2-\omega)}}\]
\[\text{LCI}_\infty = \mu_0 - 3\sigma_0\sqrt{\frac{\omega}{n(2-\omega)}}\]
car \(\lim_{i \to \infty} (1-\omega)^{2i} = 0\).
Pourquoi utiliser les limites exactes plutôt qu’asymptotiques ?
Note sur la notation : Dans le cours, le paramètre est noté \(\omega\) (oméga). Ici, nous utilisons \(\lambda = \omega = 0.2\).
# Paramètre de lissage (ω dans le cours, λ en pratique)
# Recommandé pour petits déréglages : ω ∈ [0.1, 0.3]
lambda <- 0.2 # Équivaut à ω = 0.2 dans le cours
# CALCUL DE LA STATISTIQUE EWMA (Définition 12 du cours)
# Relation de récurrence : Z_i = ω·X̄_i + (1-ω)·Z_{i-1}
# avec Z_0 = μ_0
Z <- numeric(50)
Z[1] <- mu_0 # Initialisation à la cible (Z_0 = μ_0)
for (i in 2:50) {
Z[i] <- lambda * x_ex5[i] + (1 - lambda) * Z[i-1]
}
# CALCUL DES LIMITES DE CONTRÔLE (Proposition 13 du cours)
# Limites ASYMPTOTIQUES (pour i → ∞)
# LSC_∞ = μ_0 + 3σ_0√[ω / (n(2-ω))]
sigma_ewma_asymptotique <- sigma_0 * sqrt(lambda / (n_obs * (2 - lambda)))
LSC_ewma_asymptotique <- mu_0 + 3 * sigma_ewma_asymptotique
LIC_ewma_asymptotique <- mu_0 - 3 * sigma_ewma_asymptotique
# Limites EXACTES (Proposition 13 : fonctions de t)
# LSC_i = μ_0 + 3σ_0√[ω/(n(2-ω)) · (1-(1-ω)^{2i})]
#
# IMPORTANT : On utilise les limites EXACTES car :
# 1. Conformité au cours (Proposition 13 définit des FONCTIONS de t)
# 2. Pour les premiers échantillons, (1-ω)^{2i} n'est pas négligeable
# 3. Les limites convergent progressivement vers les limites asymptotiques
# 4. Plus précis pour la détection sur tous les échantillons
LSC_ewma_exact <- numeric(50)
LIC_ewma_exact <- numeric(50)
for (i in 1:50) {
# Facteur de correction temporel : 1 - (1-ω)^{2i}
facteur_temps <- 1 - (1 - lambda)^(2*i)
# Écart-type de Z_i (Proposition 13)
sigma_i <- sigma_0 * sqrt((lambda / (n_obs * (2 - lambda))) * facteur_temps)
# Limites exactes pour l'échantillon i
LSC_ewma_exact[i] <- mu_0 + 3 * sigma_i
LIC_ewma_exact[i] <- mu_0 - 3 * sigma_i
}
# Affichage des limites
writeLines(c(
"",
"================================================================",
sprintf(" LIMITES DE CONTROLE EWMA (omega = %.1f)", lambda),
"================================================================",
"",
"LIMITES ASYMPTOTIQUES (i -> infini) :",
sprintf(" LSC_∞ = %.4f", LSC_ewma_asymptotique),
sprintf(" LC = %.4f", mu_0),
sprintf(" LCI_∞ = %.4f", LIC_ewma_asymptotique),
sprintf(" Largeur asymptotique : %.4f", LSC_ewma_asymptotique - LIC_ewma_asymptotique),
"",
"LIMITES EXACTES (Proposition 13 du cours) :",
sprintf(" LSC_1 = %.4f (échantillon 1)", LSC_ewma_exact[1]),
sprintf(" LSC_10 = %.4f (échantillon 10)", LSC_ewma_exact[10]),
sprintf(" LSC_50 = %.4f (échantillon 50)", LSC_ewma_exact[50]),
sprintf(" → Convergence vers LSC_∞ = %.4f", LSC_ewma_asymptotique),
"",
sprintf("Écart entre LSC_50 et LSC_∞ : %.6f", abs(LSC_ewma_exact[50] - LSC_ewma_asymptotique)),
"================================================================",
""
))
================================================================
LIMITES DE CONTROLE EWMA (omega = 0.2)
================================================================
LIMITES ASYMPTOTIQUES (i -> infini) :
LSC_∞ = 50.3162
LC = 50.0000
LCI_∞ = 49.6838
Largeur asymptotique : 0.6325
LIMITES EXACTES (Proposition 13 du cours) :
LSC_1 = 50.1897 (échantillon 1)
LSC_10 = 50.3144 (échantillon 10)
LSC_50 = 50.3162 (échantillon 50)
→ Convergence vers LSC_∞ = 50.3162
Écart entre LSC_50 et LSC_∞ : 0.000000
================================================================
Tableau récapitulatif EWMA :
tableau_ewma <- data.frame(
Echantillon = echantillons_cles,
LSC = round(LSC_ewma_exact[echantillons_cles], 5),
Z = round(Z[echantillons_cles], 5),
LIC = round(LIC_ewma_exact[echantillons_cles], 5),
Etat = ifelse(Z[echantillons_cles] > LSC_ewma_exact[echantillons_cles] |
Z[echantillons_cles] < LIC_ewma_exact[echantillons_cles],
"Hors controle", "Sous controle")
)
kable(tableau_ewma,
caption = "Resultats EWMA (lambda = 0.2) pour echantillons selectionnes",
align = "c",
col.names = c("Echantillon", "LSC", "Z (Statistique EWMA)", "LIC", "Etat")) |>
kable_styling(bootstrap_options = c("striped", "hover", "condensed"),
full_width = TRUE) |>
column_spec(5, bold = TRUE,
color = ifelse(tableau_ewma$Etat == "Sous controle", "darkgreen", "darkred"))
| Echantillon | LSC | Z (Statistique EWMA) | LIC | Etat |
|---|---|---|---|---|
| 1 | 50.18974 | 50.00000 | 49.81026 | Sous controle |
| 10 | 50.31440 | 50.13906 | 49.68560 | Sous controle |
| 20 | 50.31621 | 50.17101 | 49.68379 | Sous controle |
| 30 | 50.31623 | 50.18417 | 49.68377 | Sous controle |
| 40 | 50.31623 | 50.24387 | 49.68377 | Sous controle |
| 45 | 50.31623 | 50.30441 | 49.68377 | Sous controle |
| 50 | 50.31623 | 50.34323 | 49.68377 | Hors controle |
df_ewma <- data.frame(
echantillon = 1:50,
Z = Z,
LSC = LSC_ewma_exact,
LIC = LIC_ewma_exact,
hors_limite = ifelse(Z > LSC_ewma_exact | Z < LIC_ewma_exact,
"Hors controle", "Sous controle")
)
ggplot(df_ewma, aes(x = echantillon)) +
geom_ribbon(aes(ymin = LIC, ymax = LSC),
alpha = 0.25, fill = couleurs$zone_surveillance) +
geom_line(aes(y = LSC), color = couleurs$rouge_principal,
linewidth = 0.8, linetype = "dashed") +
geom_line(aes(y = LIC), color = couleurs$rouge_principal,
linewidth = 0.8, linetype = "dashed") +
geom_hline(yintercept = mu_0, color = couleurs$vert_principal, linewidth = 1.2) +
geom_line(aes(y = Z), color = couleurs$orange_principal, linewidth = 1.1) +
geom_point(aes(y = Z, color = hors_limite), size = 3) +
scale_color_manual(values = c("Sous controle" = couleurs$sous_controle,
"Hors controle" = couleurs$hors_controle)) +
labs(
title = "Carte EWMA (Exponentially Weighted Moving Average)",
subtitle = expression(paste(mu[0], " = 50, ", sigma[0], " = 1, n = 10, ", lambda, " = 0.2")),
x = "Numero d'echantillon",
y = "Statistique EWMA (Z)",
color = "Etat"
) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5),
panel.grid.minor = element_blank(),
legend.position = "bottom"
)
Carte EWMA - Detection optimale des petits dereglages
Résultat EWMA :
hors_ewma <- sum(Z > LSC_ewma_exact | Z < LIC_ewma_exact)
writeLines(c(
"",
"================================================================",
" RESULTAT CARTE EWMA",
"================================================================",
sprintf("Points hors controle : %d / 50", hors_ewma),
sprintf("Taux de conformite : %.1f%%", 100*(1 - hors_ewma/50)),
"",
ifelse(hors_ewma == 0,
"-> Processus SOUS CONTROLE",
"-> Processus HORS CONTROLE"),
"================================================================",
""
))
================================================================
RESULTAT CARTE EWMA
================================================================
Points hors controle : 3 / 50
Taux de conformite : 94.0%
-> Processus HORS CONTROLE
================================================================
# hors_ma3, hors_ma4, hors_ma5 sont déjà calculés
# On calcule seulement hors_ewma (déjà fait ci-dessus)
synthese_complete <- data.frame(
Methode = c("Carte X-bar classique", "MA (h=3)", "MA (h=4)", "MA (h=5)", "EWMA (omega=0.2)"),
Type = c("Shewhart", "A memoire", "A memoire", "A memoire", "A memoire"),
Largeur_zone = c(
round(2*0.949, 4),
round(LSC_ma3[50] - LIC_ma3[50], 4),
round(LSC_ma4[50] - LIC_ma4[50], 4),
round(LSC_ma5[50] - LIC_ma5[50], 4),
round(LSC_ewma_asymptotique - LIC_ewma_asymptotique, 4) # Largeur asymptotique
),
Points_HC = c("N/A", hors_ma3, hors_ma4, hors_ma5, hors_ewma),
Sensibilite = c("Faible", "Elevee", "Moyenne", "Faible", "Tres elevee"),
Conclusion = c(
"Inadaptee",
ifelse(hors_ma3 == 0, "Sous controle", "Hors controle"),
ifelse(hors_ma4 == 0, "Sous controle", "Hors controle"),
ifelse(hors_ma5 == 0, "Sous controle", "Hors controle"),
ifelse(hors_ewma == 0, "Sous controle", "Hors controle")
)
)
kable(synthese_complete,
caption = "Synthese comparative de toutes les methodes (Exemple 5)",
align = "c",
col.names = c("Methode", "Type", "Largeur zone", "Points HC", "Sensibilite", "Conclusion")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = TRUE) |>
column_spec(1, bold = TRUE) |>
column_spec(6, bold = TRUE,
color = c("gray",
ifelse(synthese_complete$Conclusion[2] == "Sous controle", "darkgreen", "darkred"),
ifelse(synthese_complete$Conclusion[3] == "Sous controle", "darkgreen", "darkred"),
ifelse(synthese_complete$Conclusion[4] == "Sous controle", "darkgreen", "darkred"),
ifelse(synthese_complete$Conclusion[5] == "Sous controle", "darkgreen", "darkred"))) |>
row_spec(1, background = "#FFEBEE")
| Methode | Type | Largeur zone | Points HC | Sensibilite | Conclusion |
|---|---|---|---|---|---|
| Carte X-bar classique | Shewhart | 1.8980 | N/A | Faible | Inadaptee |
| MA (h=3) | A memoire | 1.0954 | 1 | Elevee | Hors controle |
| MA (h=4) | A memoire | 0.9487 | 1 | Moyenne | Hors controle |
| MA (h=5) | A memoire | 0.8485 | 1 | Faible | Hors controle |
| EWMA (omega=0.2) | A memoire | 0.6325 | 3 | Tres elevee | Hors controle |
Carte MA (Moving Average) :
Avantages : - Calcul simple et intuitif (moyenne arithmétique) - Facile à expliquer aux opérateurs - Limites en créneaux visualisent bien la convergence
Inconvénients : - Mémoire limitée à \(h\) échantillons (oublie le passé lointain) - Pondération uniforme (pas de distinction ancien/récent) - Choix de \(h\) empirique
Carte EWMA (Exponentially Weighted Moving Average) :
Avantages : - Mémoire infinie avec pondération décroissante - Performance optimale théoriquement établie - Valeurs de \(\lambda\) recommandées - Convergence progressive des limites
Inconvénients : - ️ Moins intuitive (récursion, pondération exponentielle) - Plus difficile à calculer manuellement - Nécessite de stocker \(Z_{i-1}\)
D’après le Chapitre 5 du cours :
Pour déréglages très lents (dérive progressive) : → EWMA avec \(\lambda = 0.1\) ou \(\lambda = 0.15\)
Pour déréglages moyennement lents : → EWMA avec \(\lambda = 0.2\) ou MA avec \(h = 4\)
Pour contexte industriel : → EWMA (performance optimale, norme ISO)
Question : Le procédé est-il sous contrôle en moyenne sachant qu’un déréglage lent est suspecté ?
Réponse :
La carte \(\bar{X}\) classique est inadaptée car elle ne détecte pas les dérives lentes (limites trop larges, pas de mémoire)
Toutes les cartes à mémoire détectent une anomalie :
Le choix du paramètre est crucial :
Interprétation des résultats :
Conclusion finale : Le processus présente une anomalie détectée par toutes les cartes à mémoire (MA ordres 3, 4, 5 et EWMA). Cette détection unanime confirme sans ambiguïté la présence d’un déréglage lent significatif.
Action recommandée : - Identifier la cause assignable (usure d’outil, dérive température, etc.) - Corriger le processus - Surveiller avec carte EWMA \(\lambda = 0.2\) en continu (recommandation industrie)
Cette analyse démontre l’importance capitale du choix de la carte adaptée au type de déréglage suspecté, conformément aux enseignements du Chapitre 5 du cours.
recap <- data.frame(
Carte = c("X barre", "S", "R", "c", "MA", "EWMA"),
Objectif = c(
"Surveiller moyenne",
"Surveiller ecart-type",
"Surveiller etendue",
"Compter defauts",
"Detecter derives",
"Detecter petits dereglages"
),
Phase = c("I et II", "I et II", "I", "II", "II", "II"),
Sensibilite = c("Moyenne", "Moyenne", "Moyenne", "Faible", "Moyenne-Elevee", "Tres elevee")
)
kable(recap,
caption = "Synthese des cartes de controle",
align = "c",
col.names = c("Carte", "Objectif", "Phase", "Sensibilite")) |>
kable_styling(bootstrap_options = c("striped", "hover"),
full_width = FALSE) |>
column_spec(1, bold = TRUE) |>
row_spec(6, background = "#E3F2FD") # Highlighter EWMA
| Carte | Objectif | Phase | Sensibilite |
|---|---|---|---|
| X barre | Surveiller moyenne | I et II | Moyenne |
| S | Surveiller ecart-type | I et II | Moyenne |
| R | Surveiller etendue | I | Moyenne |
| c | Compter defauts | II | Faible |
| MA | Detecter derives | II | Moyenne-Elevee |
| EWMA | Detecter petits dereglages | II | Tres elevee |
Au cours de ce projet, nous avons exploré cinq exemples illustrant différentes facettes des cartes de contrôle :
Exemple 1 : Carte classique (\(\bar{X}\), \(S\)) en Phase II. Le processus est centré correctement mais présente une variabilité interne anormale (un point hors contrôle sur la carte \(S\)).
Exemple 2 : Analyse de valeurs aberrantes avec trois méthodes du cours (boîte de dispersion, test de Shapiro-Wilk, règle des 3σ). Détection d’une alarme défectueuse (17 secondes) identifiée comme valeur atypique, confirmant l’opinion du responsable sur un processus hors contrôle. Quatre critères indépendants valident cette conclusion.
Exemple 3 : Estimation des paramètres en Phase I avec cartes (\(\bar{X}\), \(R\)). Établissement des limites de référence pour un processus sous contrôle statistique.
Exemple 4 : Carte aux attributs (\(c\)) avec limites probabilistes adaptées au risque accepté (\(\alpha = 10\%\)). Deux points hors contrôle détectés.
Exemple 5 : Cartes MA et EWMA révélant l’importance du choix de l’ordre de la moyenne mobile et du paramètre de lissage pour la détection des déréglages lents.
Ces exemples démontrent la complémentarité des outils et l’importance de choisir la carte adaptée au contexte.
Pour une mise en œuvre réussie de la MSP :
constantes <- data.frame(
n = c(2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 30, 35, 40, 45, 50),
d2 = c(1.128, 1.693, 2.059, 2.326, 2.534, 2.704, 2.847, 2.970, 3.078,
3.173, 3.258, 3.336, 3.407, 3.472, 3.532, 3.588, 3.640, 3.689, 3.735,
3.778, 3.819, 3.858, 3.895, 3.931, 4.086, 4.213, 4.322, 4.415, 4.498),
d3 = c(0.853, 0.888, 0.880, 0.864, 0.848, 0.833, 0.820, 0.808, 0.797,
0.787, 0.778, 0.770, 0.763, 0.756, 0.750, 0.744, 0.739, 0.734, 0.729,
0.724, 0.720, 0.716, 0.712, 0.708, 0.693, 0.680, 0.670, 0.660, 0.652),
c4 = c(0.798, 0.886, 0.921, 0.940, 0.952, 0.959, 0.965, 0.969, 0.973,
0.975, 0.978, 0.979, 0.981, 0.982, 0.984, 0.985, 0.986, 0.987, 0.988,
0.988, 0.989, 0.990, 0.990, 0.991, 0.993, 0.994, 0.995, 0.996, 0.996)
)
kable(constantes,
caption = "Constantes pour cartes de contrôle (n = 2 à 50)",
col.names = c("n", "d2", "d3", "c4"),
align = "c") |>
kable_styling(bootstrap_options = c("striped"),
full_width = FALSE, font_size = 10)
| n | d2 | d3 | c4 |
|---|---|---|---|
| 2 | 1.128 | 0.853 | 0.798 |
| 3 | 1.693 | 0.888 | 0.886 |
| 4 | 2.059 | 0.880 | 0.921 |
| 5 | 2.326 | 0.864 | 0.940 |
| 6 | 2.534 | 0.848 | 0.952 |
| 7 | 2.704 | 0.833 | 0.959 |
| 8 | 2.847 | 0.820 | 0.965 |
| 9 | 2.970 | 0.808 | 0.969 |
| 10 | 3.078 | 0.797 | 0.973 |
| 11 | 3.173 | 0.787 | 0.975 |
| 12 | 3.258 | 0.778 | 0.978 |
| 13 | 3.336 | 0.770 | 0.979 |
| 14 | 3.407 | 0.763 | 0.981 |
| 15 | 3.472 | 0.756 | 0.982 |
| 16 | 3.532 | 0.750 | 0.984 |
| 17 | 3.588 | 0.744 | 0.985 |
| 18 | 3.640 | 0.739 | 0.986 |
| 19 | 3.689 | 0.734 | 0.987 |
| 20 | 3.735 | 0.729 | 0.988 |
| 21 | 3.778 | 0.724 | 0.988 |
| 22 | 3.819 | 0.720 | 0.989 |
| 23 | 3.858 | 0.716 | 0.990 |
| 24 | 3.895 | 0.712 | 0.990 |
| 25 | 3.931 | 0.708 | 0.991 |
| 30 | 4.086 | 0.693 | 0.993 |
| 35 | 4.213 | 0.680 | 0.994 |
| 40 | 4.322 | 0.670 | 0.995 |
| 45 | 4.415 | 0.660 | 0.996 |
| 50 | 4.498 | 0.652 | 0.996 |