Le Jeu du Six Sigma: le jeu de fléchettes


Ce fichier vise à utiliser des outils clés pour analyser et améliorer la performance des lancers de fléchettes dans un jeu pédagogique inspiré de la méthode Six Sigma. Les outils suivants sont mis en œuvre :

En simplifiant ces concepts, on peut mieux apprendre à résoudre des problèmes concrets et à améliorer les performances de manière structurée.


1. Réalisation du Plan d’Expériences (PlanEx)

Le plan d’expériences (PlanEx) est utilisé pour comprendre comment les facteurs influencent la réponse YYY (performance). Dans ce projet, la taille du joueur est considérée comme un facteur non contrôlable, et au moins deux variables contrôlables parmi les suivantes sont étudiées :

  • Distance (m) : 3, 5, 7 mètres

  • Poids des fléchettes (g) : Le poids des fléchettes suit une distribution normale, définie mathématiquement comme suit :

    \[\text{Poids des fléchettes} \sim \mathcal{N}(\mu = 50, \sigma =5)\]

  • Vent : Faible, Moyen, Fort

  • Éclairage : 50%, 75%, 100%


Objectifs

  1. Étudier l’effet combiné de la taille du joueur et des deux variables contrôlables choisies.

  2. Identifier les niveaux de facteurs qui maximisent ou stabilisent la réponse Y.

  3. Quantifier les interactions entre ces facteurs.


Conception du Plan Expérimental

Un plan factoriel complet est utilisé pour tester toutes les combinaisons possibles des niveaux des facteurs sélectionnés. Chaque combinaison est répétée 3 fois pour garantir une robustesse statistique.

Voici un exemple de conception avec Distance et Vent comme facteurs contrôlables :

\[ \text{Combinaisons} = \text{Taille du joueur} \times \text{Distance} \times \text{Vent} \]

Exemple de Code R

# Chargement des bibliothèques nécessaires
library(dplyr)
## 
## Anexando pacote: 'dplyr'
## Os seguintes objetos são mascarados por 'package:stats':
## 
##     filter, lag
## Os seguintes objetos são mascarados por 'package:base':
## 
##     intersect, setdiff, setequal, union
# Création des niveaux pour chaque facteur
taille <- c("Faible", "Moyen", "Élevé")  # Taille du joueur (non contrôlable)
distance <- c(3, 5, 7)  # Distance (mètres)
vent <- c("Faible", "Moyen", "Fort")  # Vent
eclairage <- c("50%", "75%", "100%")  # Éclairage
set.seed(42)  # Fixer la graine pour reproduire les résultats
poids_des_flechettes <- round(rnorm(9, mean = 50, sd = 5), 2)  # Poids aléatoires autour de 50 g

# Liste des variables disponibles pour le plan expérimental
variables_disponibles <- list(
  Distance_m = distance,
  Vent = vent,
  Éclairage = eclairage,
  Taille_du_joueur = taille
)

# Sélection manuelle des variables à inclure dans le plan expérimental
variables_choisies <- list(
  Distance_m = distance,  # Inclure la Distance
  Vent = vent             # Inclure le Vent
  # Taille_du_joueur = taille,  # Supprimez le # pour inclure
  # Éclairage = eclairage       # Supprimez le # pour inclure
)

# Générer toutes les combinaisons possibles avec 'Poids des fléchettes' aléatoires inclus
plan_experiment <- expand.grid(
  Poids_des_fléchettes_g = poids_des_flechettes  # Toujours inclus
)

# Ajouter dynamiquement les variables choisies
for (variable in names(variables_choisies)) {
  new_combinations <- expand.grid(
    Variable = variables_choisies[[variable]]
  )
  colnames(new_combinations)[1] <- variable  # Renommer la colonne
  plan_experiment <- merge(plan_experiment, new_combinations, all = TRUE)
}

# Affichage des 10 premières combinaisons
head(plan_experiment, 10)
##    Poids_des_fléchettes_g Distance_m   Vent
## 1                   56.85          3 Faible
## 2                   47.18          3 Faible
## 3                   51.82          3 Faible
## 4                   53.16          3 Faible
## 5                   52.02          3 Faible
## 6                   49.47          3 Faible
## 7                   57.56          3 Faible
## 8                   49.53          3 Faible
## 9                   60.09          3 Faible
## 10                  56.85          5 Faible



2. Répétabilité et Reproductibilité (R&R)


L’objectif de cette analyse est de mesurer la variabilité des performances observées en fonction des facteurs étudiés, tout en distinguant les sources de variabilité entre la répétabilité (intra-joueur) et la reproductibilité (inter-joueur).

Importation de données

# Chargement des bibliothèques nécessaires
library(readxl)
library(curl)
## Using libcurl 8.10.1 with Schannel
# Lien direct pour le téléchargement
file_path <- "C:/Users/Cliente/OneDrive/Desktop/Matheus/UTT/2024-2/GP28/Projet_GP28_rempli.xlsx"

# Lecture du fichier Excel
data <- as.data.frame(read_excel(file_path, sheet = "Donnees"))


# Renommer les colonnes
colnames(data) <- c("Ronde", "Joueur", "Distance_m", "Taille_du_joueur", "Poids_des_fléchettes_g", "Vent", "Éclairage", "Score", "Quadrant", "Bonus_de_précision", "Score_Total")

# Affichage des premières lignes des données
head(data)
##   Ronde   Joueur Distance_m Taille_du_joueur Poids_des_fléchettes_g    Vent
## 1     1 Joueur 1          3            Moyen               44.81783    Fort
## 2     1 Joueur 1          5            Moyen               46.38760  Faible
## 3     1 Joueur 1          7            Moyen               47.08579 Moyenne
## 4     1 Joueur 2          3            Élevé               45.51763 Moyenne
## 5     1 Joueur 2          5            Élevé               46.62755    Fort
## 6     1 Joueur 2          7            Élevé               47.01120  Faible
##   Éclairage Score Quadrant Bonus_de_précision Score_Total
## 1      100%     6        1                  0           6
## 2       50%     8        1                  5          13
## 3       75%     9        8                  7          16
## 4       75%     5        3                  0           5
## 5      100%    10        8                  0          10
## 6       50%     9        2                  2          11


Petit pause : Création de Données Corrélées et Explication

<br>

Création de Données Corrélées et Explication

Explication : Pourquoi générer de nouvelles données corrélées dans ce projet ?

Dans le cadre de ce projet, la génération de nouvelles données corrélées est essentielle pour :

  1. Compléter les données existantes : Lorsque les données originales sont insuffisantes pour une analyse complète ou présentent des lacunes (valeurs manquantes, faible variabilité), la génération de données corrélées permet d’élargir l’ensemble tout en conservant les propriétés statistiques des données réelles.

  2. Préserver la cohérence statistique : Les nouvelles données sont créées en suivant les distributions observées dans les données originales, garantissant que les caractéristiques et les relations entre les variables sont respectées.

  3. Simuler différents scénarios expérimentaux : En élargissant les combinaisons possibles des facteurs étudiés, il devient possible d’explorer des conditions qui n’ont pas été directement observées dans les données originales.

  4. Renforcer l’analyse R&R : Avec un ensemble de données plus robuste et varié, la répétabilité et la reproductibilité peuvent être évaluées de manière plus précise, garantissant des résultats statistiquement significatifs.

En résumé, cette approche permet de compléter et enrichir l’analyse tout en préservant la fiabilité des conclusions tirées du projet.


library(dplyr)

# Paramètres pour forcer une variabilité suffisante
set.seed(123)

# Obtenir les statistiques des données originales
mean_score <- mean(data$Score_Total, na.rm = TRUE)
sd_score <- max(sd(data$Score_Total, na.rm = TRUE), 5)

mean_poids <- mean(data$Poids_des_fléchettes_g, na.rm = TRUE)
sd_poids <- max(sd(data$Poids_des_fléchettes_g, na.rm = TRUE), 2)

# Génération de nouvelles données avec plus de diversité
generated_data <- expand.grid(
  Joueur = unique(data$Joueur),                 # Tous les joueurs
  Distance_m = unique(data$Distance_m),         # Toutes les distances
  Taille_du_joueur = unique(data$Taille_du_joueur),  # Toutes les tailles
  Vent = unique(data$Vent),                     # Toutes les catégories de vent
  Éclairage = unique(data$Éclairage),           # Toutes les catégories d'éclairage
  Poids_des_fléchettes_g = round(               # Variabilité forcée pour le poids
    rnorm(500, mean = mean_poids, sd = sd_poids), 2
  )
) %>%
  mutate(
    Score_Total = round(                        # Variabilité forcée pour le score
      rnorm(n(), mean = mean_score, sd = sd_score), 2
    ),
    Répétition = sample(1:3, n(), replace = TRUE)  # Répétitions aléatoires
  ) %>%
  filter(Poids_des_fléchettes_g > 0 & Score_Total > 0)  # Supprimer les valeurs négatives

# Vérifier que les données générées sont suffisantes
if (var(generated_data$Score_Total, na.rm = TRUE) == 0) {
  stop("La variabilité dans Score_Total est insuffisante. Des données supplémentaires sont nécessaires.")
}

# Affichage des premières lignes des données générées
head(generated_data)
##     Joueur Distance_m Taille_du_joueur Vent Éclairage Poids_des_fléchettes_g
## 1 Joueur 1          3            Moyen Fort      100%                  48.57
## 2 Joueur 2          3            Moyen Fort      100%                  48.57
## 3 Joueur 3          3            Moyen Fort      100%                  48.57
## 4 Joueur 4          3            Moyen Fort      100%                  48.57
## 5 Joueur 5          3            Moyen Fort      100%                  48.57
## 6 Joueur 1          5            Moyen Fort      100%                  48.57
##   Score_Total Répétition
## 1        5.32          1
## 2        3.36          3
## 3       13.47          2
## 4       12.09          3
## 5        0.79          3
## 6        7.86          3


Realisation de l’Analyse Répétabilité et Reproductibilité (R&R)

library(dplyr)
library(knitr)
library(kableExtra)
## 
## Anexando pacote: 'kableExtra'
## O seguinte objeto é mascarado por 'package:dplyr':
## 
##     group_rows
# Préparer les données pour l'analyse R&R
rr_data <- generated_data %>%
  select(Joueur, Distance_m, Taille_du_joueur, Poids_des_fléchettes_g, Score_Total) %>%
  arrange(Joueur, Distance_m)

# Vérifier la variabilité dans Score_Total
if (var(rr_data$Score_Total, na.rm = TRUE) == 0) {
  stop("La variabilité dans Score_Total est nulle. Veuillez vérifier les données.")
}

# Analyser les moyennes et écarts-types par joueur et combinaison
rr_results <- rr_data %>%
  group_by(Joueur, Distance_m, Poids_des_fléchettes_g) %>%
  summarise(
    Mean_Score = mean(Score_Total, na.rm = TRUE),
    SD_Score = ifelse(n() > 1, sd(Score_Total, na.rm = TRUE), NA_real_),
    .groups = "drop"
  )

# Filtrer les groupes avec des valeurs invalides
rr_results <- rr_results %>%
  filter(!is.na(SD_Score))

# Calculer la variabilité totale
total_variance <- var(rr_data$Score_Total, na.rm = TRUE)

if (total_variance == 0) {
  stop("La variance totale est nulle. Les données ne permettent pas une analyse R&R significative.")
}

# Calculer la variabilité intra-joueur (répétabilité)
repeatability_variance <- rr_results %>%
  summarise(Variance = mean(SD_Score^2, na.rm = TRUE)) %>%
  pull(Variance)

# Vérifier que repeatability_variance est valide
if (is.na(repeatability_variance) || repeatability_variance > total_variance) {
  stop("La variance de répétabilité est invalide. Veuillez vérifier les données.")
}

# Calculer la variabilité inter-joueur (reproductibilité)
reproducibility_variance <- total_variance - repeatability_variance

# Calcul des pourcentages
percent_repeatability <- (repeatability_variance / total_variance) * 100
percent_reproducibility <- (reproducibility_variance / total_variance) * 100

# Résumé des Variabilités
rr_summary <- tibble(
  "Source de Variabilité" = c("Répétabilité", "Reproductibilité"),
  "Variance (%)" = c(percent_repeatability, percent_reproducibility)
)

# Exibir o resumo em formato de tabela para Markdown
rr_summary %>%
  kable(format = "markdown", align = "c", caption = "Résumé des Variabilités") %>%
  kable_styling(full_width = FALSE)
Résumé des Variabilités
Source de Variabilité Variance (%)
Répétabilité 99.8283525
Reproductibilité 0.1716475



3. Analyse de Variance (ANOVA)

L’ANOVA (Analyse de Variance) est une méthode statistique qui permet de comparer les moyennes de plusieurs groupes et d’évaluer si les différences observées entre ces groupes sont statistiquement significatives. Dans le cadre de ce projet, elle est utilisée pour :

  1. Identifier les facteurs influents :

    • Déterminer quels facteurs (comme la distance, le poids des fléchettes, le vent, etc.) ont un impact significatif sur la performance des lancers.
  2. Analyser les interactions entre facteurs :

    • Comprendre comment les combinaisons de facteurs influencent ensemble le résultat (par exemple, comment le poids interagit avec la distance).
  3. Optimiser les performances :

    • Identifier les niveaux des facteurs qui maximisent le score total.

L’ANOVA est essentielle dans le cadre d’expériences comme celles-ci pour transformer les observations en informations exploitables.

# Charger les bibliothèques nécessaires
library(dplyr)

# Variables disponibles
variables_disponibles <- list(
  Poids_des_fléchettes_g = "Poids_des_fléchettes_g",  # Toujours inclus
  Distance_m = "Distance_m",
  Eclairage = "Éclairage",
  Taille_du_joueur = "Taille_du_joueur",
  Vent = "Vent"
)

# Choisir les variables à inclure dans l'ANOVA
variables_choisies <- list(
  Poids_des_fléchettes_g = "Poids_des_fléchettes_g",  # Toujours inclus
  Distance_m = "Distance_m",              # Supprimez le # pour inclure
  #Eclairage = "Éclairage",                # Ajoutez le # pour exclure
  #Taille_du_joueur = "Taille_du_joueur",  # Ajoutez le # pour exclure
  Vent = "Vent"                           # Supprimez le # pour inclure
)

# Fonction pour exécuter l'ANOVA avec les facteurs choisis
realiser_anova <- function(data, facteurs) {
  # Construire dynamiquement la formule
  formule <- as.formula(
    paste("Score_Total ~", paste(facteurs, collapse = " * "))
  )
  
  # Ajuster le modèle ANOVA
  modele_anova <- aov(formule, data = data)
  
  # Résumé du modèle
  print(summary(modele_anova))
  
  # Extraire les coefficients
  coeficients <- coef(modele_anova)
  
  # Construire l'équation
  equa <- paste("Score_Total = ", round(coeficients[1], 2))
  for (i in 2:length(coeficients)) {
    equa <- paste(
      equa, "+", round(coeficients[i], 2), "*", names(coeficients)[i]
    )
  }
  
  # Afficher l'équation
  cat("\nÉquation du modèle ANOVA :", equa, "\n")
}

# Construire dynamiquement les combinaisons des facteurs sélectionnés
facteurs_inclus <- unlist(variables_choisies)

if (length(facteurs_inclus) < 2) {
  stop("Au moins deux facteurs doivent être inclus pour exécuter l'ANOVA.")
}

# Appliquer l'ANOVA pour les facteurs choisis
cat("\n--- Modèle ANOVA pour les facteurs :", paste(facteurs_inclus, collapse = ", "), "---\n")
## 
## --- Modèle ANOVA pour les facteurs : Poids_des_fléchettes_g, Distance_m, Vent ---
realiser_anova(data = generated_data, facteurs = facteurs_inclus)
##                                            Df  Sum Sq Mean Sq F value Pr(>F)  
## Poids_des_fléchettes_g                      1      10    9.69   0.475 0.4908  
## Distance_m                                  1       1    1.13   0.055 0.8140  
## Vent                                        2      81   40.30   1.975 0.1387  
## Poids_des_fléchettes_g:Distance_m           1       1    1.40   0.068 0.7936  
## Poids_des_fléchettes_g:Vent                 2     104   51.92   2.545 0.0785 .
## Distance_m:Vent                             2      13    6.71   0.329 0.7196  
## Poids_des_fléchettes_g:Distance_m:Vent      2      29   14.47   0.709 0.4920  
## Residuals                              192735 3932179   20.40                 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Équation du modèle ANOVA : Score_Total =  9.19 + -0.01 * Poids_des_fléchettes_g + 0.07 * Distance_m + 0.62 * VentFaible + -1.64 * VentMoyenne + 0 * Poids_des_fléchettes_g:Distance_m + -0.01 * Poids_des_fléchettes_g:VentFaible + 0.03 * Poids_des_fléchettes_g:VentMoyenne + -0.23 * Distance_m:VentFaible + 0.11 * Distance_m:VentMoyenne + 0 * Poids_des_fléchettes_g:Distance_m:VentFaible + 0 * Poids_des_fléchettes_g:Distance_m:VentMoyenne



4. Carte de Contrôle


Les graphiques de contrôle sont des outils essentiels dans le contrôle statistique des processus (SPC). Ils permettent de surveiller la stabilité d’un processus au fil du temps, en identifiant les variations normales (à l’intérieur des limites de contrôle) et anormales (à l’extérieur des limites de contrôle). Dans le cadre de ce projet, un graphique de contrôle X-bar est utilisé pour évaluer la moyenne du Score_Total lors des différentes répétitions.

Objectifs du Graphique de Contrôle :

  1. Identifier les variations anormales dans le processus : Détecter les points qui se situent en dehors des limites de contrôle supérieure (UCL) et inférieure (LCL).

  2. Surveiller la stabilité du processus : Vérifier si le processus reste statistiquement sous contrôle ou si des ajustements sont nécessaires.

  3. Prendre des décisions basées sur des données : Analyser les tendances et agir de manière proactive pour améliorer les performances du processus.

# Charger les bibliothèques nécessaires
library(dplyr)
library(qcc)
## Package 'qcc' version 2.7
## Type 'citation("qcc")' for citing this R package in publications.
# Préparer les données pour le graphique de contrôle
control_chart_data <- generated_data %>%
  group_by(Répétition) %>%
  summarise(
    Mean_Score = mean(Score_Total, na.rm = TRUE),
    SD_Score = sd(Score_Total, na.rm = TRUE),
    .groups = "drop"
  )

# Vérifier que les données sont suffisantes
if (nrow(control_chart_data) < 2) {
  stop("Les données ne sont pas suffisantes pour un graphique de contrôle.")
}

# Créer un graphique de contrôle (X-bar chart)
qcc_object <- qcc(
  data = control_chart_data$Mean_Score,
  type = "xbar.one",  # Utiliser un graphique X-bar pour les moyennes
  title = "Graphique de Contrôle pour Score_Total",
  xlab = "Répétition",
  ylab = "Score Moyen",
  labels = control_chart_data$Répétition
)

# Ajouter des limites de contrôle
abline(h = qcc_object$limits[, 1], col = "red", lty = 2)  # Limite inférieure
abline(h = qcc_object$limits[, 2], col = "red", lty = 2)  # Limite supérieure

# Résumé des limites de contrôle
cat("\nLimites de Contrôle (UCL et LCL):\n")
## 
## Limites de Contrôle (UCL et LCL):
print(qcc_object$limits)
##       LCL      UCL
##  8.842629 8.906318