Analyse des données chez la femme

Voir les librairies
library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.4     ✔ readr     2.1.5
✔ forcats   1.0.0     ✔ stringr   1.5.1
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.3     ✔ tidyr     1.3.1
✔ purrr     1.0.2     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(RColorBrewer)
library(boot)
library(dplyr)
library(tidyr)
library(broom)
library(ggsignif)
library(ggplot2)
library(dunn.test)
library(reshape2)

Attaching package: 'reshape2'

The following object is masked from 'package:tidyr':

    smiths
library(plotly)

Attaching package: 'plotly'

The following object is masked from 'package:ggplot2':

    last_plot

The following object is masked from 'package:stats':

    filter

The following object is masked from 'package:graphics':

    layout
library(shiny)
library(patchwork)
library(khroma)
library(MASS)

Attaching package: 'MASS'

The following object is masked from 'package:patchwork':

    area

The following object is masked from 'package:plotly':

    select

The following object is masked from 'package:dplyr':

    select
library(lattice)

Attaching package: 'lattice'

The following object is masked from 'package:boot':

    melanoma
library(esquisse)
library(testthat)

Attaching package: 'testthat'

The following object is masked from 'package:khroma':

    compare

The following object is masked from 'package:dplyr':

    matches

The following object is masked from 'package:purrr':

    is_null

The following objects are masked from 'package:readr':

    edition_get, local_edition

The following object is masked from 'package:tidyr':

    matches
library(rsconnect)

Attaching package: 'rsconnect'

The following object is masked from 'package:shiny':

    serverInfo
library(ggcorrplot)
library(naniar)
library(explor)
library(visdat)
library(DescTools)
library(DMwR2)
Registered S3 method overwritten by 'quantmod':
  method            from
  as.zoo.data.frame zoo 
library(rpart)
library(RSEIS)

Attaching package: 'RSEIS'

The following object is masked from 'package:boot':

    envelope
library(FactoMineR)
library(gtsummary)

Attaching package: 'gtsummary'

The following object is masked from 'package:testthat':

    matches

The following object is masked from 'package:MASS':

    select
library(corrplot)
corrplot 0.92 loaded
library(devtools)
Loading required package: usethis

Attaching package: 'devtools'

The following object is masked from 'package:rsconnect':

    lint

The following object is masked from 'package:testthat':

    test_file
library(factoextra)
Welcome! Want to learn more? See two factoextra-related books at https://goo.gl/ve3WBa
library(corrr)
library(clusterSim)
Loading required package: cluster
library(DataExplorer)
library(caret)

Attaching package: 'caret'

The following objects are masked from 'package:DescTools':

    MAE, RMSE

The following object is masked from 'package:purrr':

    lift
library(rattle)
Loading required package: bitops

Attaching package: 'bitops'

The following object is masked from 'package:DescTools':

    %^%

Rattle: A free graphical interface for data science with R.
Version 5.5.1 Copyright (c) 2006-2021 Togaware Pty Ltd.
Type 'rattle()' to shake, rattle, and roll your data.
library(randomForest)
randomForest 4.7-1.2
Type rfNews() to see new features/changes/bug fixes.

Attaching package: 'randomForest'

The following object is masked from 'package:rattle':

    importance

The following object is masked from 'package:dplyr':

    combine

The following object is masked from 'package:ggplot2':

    margin
library(e1071)
library(pROC)
Type 'citation("pROC")' for a citation.

Attaching package: 'pROC'

The following objects are masked from 'package:stats':

    cov, smooth, var
library(ggpubr) 
library(psych) 

Attaching package: 'psych'

The following object is masked from 'package:randomForest':

    outlier

The following objects are masked from 'package:DescTools':

    AUC, ICC, SD

The following object is masked from 'package:testthat':

    describe

The following object is masked from 'package:boot':

    logit

The following objects are masked from 'package:ggplot2':

    %+%, alpha
library(knitr)
library(gridExtra) 

Attaching package: 'gridExtra'

The following object is masked from 'package:randomForest':

    combine

The following object is masked from 'package:dplyr':

    combine
setwd('/Users/mathisbouvet/Documents/Stage/Données Analytiques/Données Analytique')
APF=read.csv('ValeurF2.csv',sep=";",header=TRUE)
APF$MarcheMET=as.numeric(APF$MarcheMET)
APF$TotalMET=as.numeric(APF$TotalMET)

Partie I : Traitement des données brutes

'data.frame':   146 obs. of  7 variables:
 $ Score.fertilité: num  0.339 0.475 0.182 0.436 0.469 ...
 $ Fertile        : chr  "Non" "Non" "Non" "Non" ...
 $ TempsAssis     : int  300 240 180 300 840 240 780 120 600 240 ...
 $ MarcheMET      : num  742 0 495 0 165 ...
 $ ModéréeMET     : int  1000 4800 8400 1000 600 1200 600 12000 2400 3600 ...
 $ IntensitéMET   : int  0 0 0 0 0 2400 3600 0 0 0 ...
 $ TotalMET       : num  1742 4800 8895 1000 765 ...

Notre jeu de donnée APF se composent de 146 observations représentant les 146 femmes répondant à l’étude. Il est inclu 7 variables. Dans le cadre de l’ACP, seul les valeurs quantitatives seront utilisés, pour la suite du traitement on utilisera (d) comme l’ensemble des valeurs quantitatives.

d=APF[,c(1,3,4,5,6,7)]

1. Traitement des valeurs manquantes

nrow(d[!complete.cases(d),])
[1] 30

Sur les 146 questionnaires, l’ensemble des données liées à l’activité physique a été rempli. Pour le temps assis, 16 % des valeurs sont manquantes, et 9 % pour la marche, ce qui représente au total 30 valeurs manquantes. Plus précisément, on peut remarquer que 6 des valeurs manquantes sont attribuées à la fois pour le temps assis et pour la marche.

Imputation de données manquantes par les K plus proches voisins

Au vu du faible nombre de donnée, un K trop élevé peut inclure des voisins trop éloignés et diluer la précision de la prédiction. La moyenne pondéré est attribuée à la valeur manquante

d1 <- knnImputation(d, k = 7, scale = TRUE, meth = "weighAvg")

2. Traitement des valeurs aberrantes et extrêmes

Une valeurs aberrantes, ou extrême, est une observation distante des autres sur un phénomène semblable. L’argument d’une données issus d’une déclaration est suffisant pour imputer ces valeurs.

Des valeurs extrêmes sont visualisées dans l’ensemble des données liées à l’activité physique ainsi que sur les données de marche.

Technique d’imputation de données abérrantes par winzorisation

Pour éviter de supprimer les valeurs, on utilise la technique de winzorisation pour ramener les valeurs dans les limites des boîtes à moustache.

d1$MarcheMET<-Winsorize(d1$MarcheMET)
d1$ModéréeMET<-Winsorize(d1$ModéréeMET)
d1$IntensitéMET<-Winsorize(d1$IntensitéMET)
d1$TotalMET<-Winsorize(d1$TotalMET)

3. Distribution des données

Hypothèse H0 : les données d’activitées physiques et le score suivent une distribution de loi normale

Voir le code
data_df <- data.frame(
  value = c(d1$Score.fertilité,d1$TempsAssis,d1$MarcheMET,d1$ModéréeMET,d1$IntensitéMET,d1$TotalMET),
  group = rep(c("Score de fertilité","Temps Assis","Activité de marche","Activité modérée","Activité intense","Activité total"),each = 146)
)
shapiro_results <- data_df %>%
  group_by(group) %>%
  summarise(shapiro_p = shapiro.test(value)$p.value)

p <- ggplot(data_df, aes(x = value, fill = group)) +
  geom_histogram(bins = 30, alpha = 0.5) +
  labs(title = "Histogrammes par groupe avec p-values du test de Shapiro-Wilk", 
       x = "Valeurs", 
       y = "Fréquence") +
  facet_wrap(~ group, scales = "free") +
  theme_minimal() +
  theme(legend.position = "none") +
  geom_text(data = shapiro_results, 
            aes(x = Inf, y = Inf, 
                label = paste("p-value:", round(shapiro_p, 4))),
            hjust = 1.1, vjust = 1.1, size = 2.5)

Seules la variables du score de fertilité présente une p-value supérier à 0,05 acceptant donc l’hypothèse H0 et la normalité de la distributions des valeurs du score de fertilité. Les p-values des autres variables étant trop inférieur. Cependant, comme chez l’homme, on observe que le temps assis suit une tendance dans la normalité de ses distributions (observation graphique).

4. Conclusion

L’analyse des données brutes montrent un total de 30 valeurs manquantes répartie dans les mesures du temps assis et de l’activité de marche. Le nouveau jeu de donnée (d1) créer tient compte de notre analyse et comporte les données de (d) avec l’imputation par les proches voisins et la winzorisation des données. L’observation de la normalité des distribution révèle une distribution normal significative pour le score de fertilité. Sans être significatif, le temps assis semblent suivre une tendance de normalité dans sa distribution.

Partie II : Analyse des données brutes

1. Comparaison des moyennes selon le status de fertilité

Hypothèse H0 : il n’y a pas de différence entre les moyennes des variables d’activité issus du groupe fertile et celle issus du groupe infertile

Voir le code
d9=d1
d9 <- cbind(d9,APF$Fertile)
colnames(d9)[ncol(d9)] <- "Fertile"

d9_norm <- d9 %>%
  mutate(across(where(is.numeric), ~ (.-mean(.)) / sd(.)))

df_long <- d9_norm %>%
  pivot_longer(cols = c(Score.fertilité, TempsAssis, MarcheMET, ModéréeMET, IntensitéMET, TotalMET),
               names_to = "Variable", 
               values_to = "Valeur")

comparisons <- list(
  c("Oui", "Non"))

df_long_filtered <- df_long %>%
  filter(Valeur >= quantile(Valeur, 0.01, na.rm = TRUE),
         Valeur <= quantile(Valeur, 0.99, na.rm = TRUE))

Ici on observe dans un premier temps que le score de fertilité est significativement différent entre les groupes fertiles et infertile (p < 0,001). Dans les données d’activitées physique, l’activité physique intense et l’activité de marche se retrouve plus élevés pour les groupes fertiles (p < 0,05). Le reste des variables n’étant pas significatif.

2. Vérification d’un score représentant la fertilité

Hypothèse H0 : les distributions du score dans les groupes de fertilité suivent une loi normale

Fertile=subset(APF,Fertile=='Oui')$Score.fertilité
Infertile=subset(APF,Fertile=='Non')$Score.fertilité
Voir le code
data <- data.frame(Fertile,Infertile)

data_df2 <- data.frame(
  value = c(data$Fertile,data$Infertile),
  group = rep(c("Fertile","Infertile"),each = 73)
)

shapiro_Fertile <- shapiro.test(Fertile)
shapiro_Infertile <- shapiro.test(Infertile)

p2 <- ggplot(data_df2, aes(x = value, fill = group)) +
  geom_density(alpha = 0.5) +
  stat_function(fun = dnorm, 
                args = list(mean = mean(data_df2$value), sd = sd(data_df2$value)), 
                color = "black", size = 1, linetype = "dashed") + # Courbe normale
  labs(title = "Courbes de densité des distributions du score avec courbe normale", 
       x = "Valeurs", 
       y = "Densité") +
  theme_minimal() +
  theme(legend.position = "top")
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
p2 <- p2 + 
  annotate("text", x = Inf, y = Inf, 
           label = paste("Shapiro-Wilk:\nFertile: W =", round(shapiro_Fertile$statistic, 4), 
                         ", p =", round(shapiro_Fertile$p.value, 4), 
                         "\nInfertile: W =", round(shapiro_Infertile$statistic, 4), 
                         ", p =", round(shapiro_Infertile$p.value, 4)), 
           hjust = 1.1, vjust = 1.5, size = 2.5, color = "black", 
           parse = FALSE)

On accepte bien l’hypothèse H0 qui montrent la normalité des distributions du score au sein du groupe fertile et infertile. On peut réaliser un test d’homogénéité de Student

Hypothèse H0 : il n’y a pas de différence significative entre les groupes fertiles et infertiles sur le score de fertilité

Afficher/Masque le résultat
resultat_test

    Welch Two Sample t-test

data:  Fertile and Infertile
t = 8.9954, df = 141.24, p-value = 1.41e-15
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 0.1397730 0.2185128
sample estimates:
mean of x mean of y 
0.5729976 0.3938547 

Avec un t = 8,9954 on peut rejeté l’hypothèse nul avec un risque alpha de 0,001. Le score de fertilité est significativement différente entre le groupe fertile et infertile. De ce fait, un score élevé est associé au groupe d’individus fertile et un score plus faible, au groupe d’infertile.

Le score de fertilité permet bien de distinguer une population fertile d’une population infertile.

3. Corrélation des variables

Voir le code
# Matrice de corrélation non paramétrique de Spearman
cor_matrix <- cor(d1, use = "pairwise.complete.obs", method = "spearman")
# p-value
get_pvalue <- function(x, y) {
  test <- cor.test(x, y, method = "spearman")
  return(test$p.value)
}
# Matrice de p-values
p_matrix <- sapply(d1, function(x) sapply(d1, function(y) get_pvalue(x, y)))
p_adjusted <- p.adjust(as.vector(p_matrix), method = "BH")
cor_long <- as.data.frame(as.table(cor_matrix))
p_long <- as.data.frame(as.table(p_matrix))
colnames(cor_long) <- c("Var1", "Var2", "Correlation")
colnames(p_long) <- c("Var1", "Var2", "P_value")
# Ajouter les p-values corrigées
p_long$P_value_corrected <- p_adjusted

p_long$Significance <- cut(p_long$P_value, 
                           breaks = c(-Inf, 0.001, 0.01, 0.05, Inf), 
                           labels = c("***", "**", "*", ""), 
                           right = TRUE)
p_long$Significance <- as.character(p_long$Significance)  # Convertir en caractère

# Fusionner les matrices de corrélation et de p-values
cor_p_long <- merge(cor_long, p_long[, c("Var1", "Var2", "P_value_corrected")], by = c("Var1", "Var2"))

# Fusionner avec les p-values d'origine
cor_p_long <- merge(cor_long, p_long, by = c("Var1", "Var2"))

La corrélation des variables semblent montrer une cohérence nécessaire dans le cadre de mesure réaliser par autodéclaration. Le temps assis est corrélé négativement au temps d’activité de marche et à l’activité physique total. Quant a l’activité physiqsue total, elle est bien corrélé positivement au autre variable d’activité physique et négativement pour le temps passer en position assise. Le score de fertilité n’est ici corrélé qu’avec l’activité physique intense.

4. Régression linéaire sur le score de fertilité

Voir le code
# Restructurer les données
d1_melted <- melt(d1, id.vars = "Score.fertilité", variable.name = "Variable", value.name = "Valeur")
# Fonction pour ajuster le modèle et récupérer les coefficients, p-values, et symboles de significativité
get_regression_info <- function(data) {
  model <- lm(Score.fertilité ~ Valeur, data = data)
  summary_model <- summary(model)
  coeff <- summary_model$coefficients[2, 1]
  p_value <- summary_model$coefficients[2, 4]
  
  # Déterminer le symbole de significativité
  significance_symbol <- ifelse(p_value < 0.001, "***",
                                ifelse(p_value < 0.01, "**",
                                       ifelse(p_value < 0.05, "*", "")))
  
  return(data.frame(Coeff = coeff, p_value = p_value, Significance = significance_symbol))
}

# Appliquer la fonction à chaque variable
regression_results <- d1_melted %>%
  group_by(Variable) %>%
  do(get_regression_info(.)) %>%
  ungroup()  # Dégrouper les résultats pour éviter des problèmes lors de l'affichage

# Tracer les régressions avec coefficients et p-values
p3 <- ggplot(d1_melted, aes(x = Valeur, y = Score.fertilité, color = Variable)) +
  geom_point() +  # Ajoute les points
  geom_smooth(method = "lm", se = FALSE) +  # Ajoute les lignes de régression
  labs(title = "Régressions des Variables sur le Score de Fertilité", 
       x = "Valeur des Variables Explicatives", 
       y = "Score de Fertilité") +
  theme_minimal()

# Ajouter les coefficients et p-values sur le graphique avec symboles de significativité
# Créer une position pour chaque texte
text_positions <- data.frame(
  Variable = regression_results$Variable,
  x = max(d1_melted$Valeur, na.rm = TRUE) * 0.85,  # Position x fixe
  y = seq(max(d1$Score.fertilité, na.rm = TRUE) * 0.90, 
          max(d1$Score.fertilité, na.rm = TRUE) * 0.65, 
          length.out = nrow(regression_results))  # Position y avec espacement
)

# Joindre les résultats de régression aux positions
text_data <- merge(regression_results, text_positions, by = "Variable")

# Tracer le graphique avec les textes et les symboles
p3 <- p3 + geom_text(data = text_data, 
                   aes(x = x, y = y, 
                       label = sprintf("Coeff: %.2f\np-value: %.3f\n%s", Coeff, p_value, Significance)), 
                   hjust = 1, vjust = 1,  # Ajustement de la position
                   size = 4, check_overlap = TRUE)

# Convertir en graphique interactif
interactive_plot <- ggplotly(p3)
`geom_smooth()` using formula = 'y ~ x'



La corrélation linéaire nous informes que de quelque élement de plus. On confirme bien une corrélation positive entre le score et l’activitié phyique total. Et il semble y avoir également un lien entre le temps assis qui régulerais à la baisse le score de fertilité.

Visualisation en 3 dimensions

Les variables d’activités physique intense (p-value < 0,05) et d’activité physique total (p-value 0,3) semblent être les varirables les plus impactant sur le score de fertilité

5. Conclusion

L’analyse de nos données brutes chez la femme et plus convaincante que chez l’homme. En effet, la variable d’activité liés à la marche ce montre significatif entre les groupes fertiles et infertiles. Le score de fertilité est encore une fois bien représentatif, en test paramétrique, de la différence entre les individus fertiles et infertiles. Il semblerait cependant que celui-ci soit moins corrélé aux différentes activités physique là ou seule l’activité physique intense est corrélé au score. Toutes fois, l’activitié physique total est bien corrélé au reste de nos activité physique.



Partie III : Réalisation de l’Analyse factorielle

Cette étape va se consacrer à la projection et à la compression des données par ACP pour n’en garder que celles qui portent suffisament d’informations pour expliquer au mieux notre problématique. La normalisation des données est automatiquement réalisé par la fonction PCA de FactoMineR.

On utilise le test de KMO pour vérifier la fiabilité de nos interprétations. Les résultats sont regroupés dans le tableau suivant :

Variable Test de KMO
Score de fertilité 0,8
Temps Assis 0,68
Marche 0,11
Activité modérée 0,26
Activité intense 0,10
Activité total 0,31

Le score de KMO se trouve moins restreingant que les données issus de la population masculine. L’analyse en PCA revelera donc quelque élement concernant le regroupement des données.

1. Réalisation de la PCA

res.pca<-PCA(d1,graph = FALSE,ncp = 6)
Voir le code
p3 <- fviz_pca_var (res.pca, col.var = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE # Évite le chevauchement de texte
             ) 

p4 <- fviz_pca_ind (res.pca, col.ind = "cos2",
             gradient.cols = c("#00AFBB", "#E7B800", "#FC4E07"),
             repel = TRUE # Évite le chevauchement de texte
             )

# Rendre le graphique interactif avec `ggplotly`
p_interactive <- ggplotly(p4)

L’axe 1 semblent représenté la majorité de nos observation. Concernant le poids de variable, on voit que le score de fertilité semblent prendre plus d’importance (contrairement à ce qu’on peut observer chez l’homme). Les variables les plus influentes sont l’activité modérée, l’activité total et l’activité intense.

Visualisation de la distribution de l’inertie des axes

res <- get_pca_var(res.pca)

Les 2 premiers axes représentent plsu de 50% (56,7) des observations. A noter que l’axe 3 n’est pas si écarté que ça, en terme de représentation, que l’axe 2. Ce premiers axes est majoritairement influencé par l’activité total, l’axe 2 est quant a lui influencer par le score de fertilité et l’activité physique intense.

Analyse de la répartition des variables

Dans une première analyse, on observe que les individus ayant une activité physique sont regroupé à droite sur la dimension 1. L’activité de marche et le temps assis n’a pas montré de regroupement d’individus en particulier sur l’axe 1 et 2. Quant au score, il est principalement visualisé en haut à droite du graphique. Au final, il est assez difficile de voir des clusters d’individus, même si on a des variables qui s’apprêtent à une utilisation de la PCA

Visualisation interractif de la PCA

Si le bouton ne marche pas, utiliser le lien externe : faire la visualisation sur R

Résultat de la PCA sur la fertilité

Pour terminer l’analyse en PCA, on projette la fertilité sur les observations de la PCA. De manière distingtiuf, on remarque tout de même un regroupement des individus fertiles sur l’axe supérieur (dimension 1).

2. Analyse Discriminante Linéaire (LDA)

lda_result <- lda(Fertile ~ TempsAssis + MarcheMET + ModéréeMET + IntensitéMET + TotalMET, data = d9)

On remarque que les 2 groupes de fertilité sont bien distingué, mais on peut noter qu’il existe une hétérogénéité des individus au sein des groupes.

Validation croisée du modèle

Voir le code
set.seed(69)
# Définir le nombre de folds
k <- 10
# Définir la méthode de validation croisée
control <- trainControl(method = "cv", number = k)

# Ajuster le modèle LDA avec validation croisée
lda_model <- train(Fertile ~ TempsAssis + MarcheMET + ModéréeMET + IntensitéMET + TotalMET, data = d9, method = "lda", trControl = control)
print(lda_model$results)
  parameter  Accuracy     Kappa AccuracySD   KappaSD
1      none 0.5944048 0.1835586   0.108736 0.2163467

La précision du modèle ne classifie pas bien les observations, alié avec un Kappa inférieur à 0,2. Ça suggère que les prédictions du modèle ne sont pas beaucoup meilleurs que celles d’un modèle aléatoire. C’est surement dû à nos classes déséquilibrés.

3. Amélioration par bootstrap

Visualisation des résultats par test statistique

Voir le code
# On créer une nouvelle data avec les variables continu mais sans le score
d13=d1[,c(2,3,4,5,6)]
# Fonction de bootstrap pour estimer la moyenne d'une variable
bootstrap_mean <- function(data, column_name, B = 1000) {
  n <- nrow(data)
  means <- numeric(B)
  
  for (i in 1:B) {
    sample_indices <- sample(1:n, size = n, replace = TRUE) 
    means[i] <- mean(data[[column_name]][sample_indices])
  }
  
  return(means)
}
# Appliquer le bootstrap à chaque variable
B <- 1000
bootstrap_results <- list()
for (var in names(d13)) {
  bootstrap_results[[var]] <- bootstrap_mean(d13, var, B)
}
# Calculer les intervalles de confiance pour chaque variable
ci_results <- list()
for (var in names(d1)) {
  ci_lower <- quantile(bootstrap_results[[var]], 0.025)
  ci_upper <- quantile(bootstrap_results[[var]], 0.975)
  ci_results[[var]] <- c(lower = ci_lower, upper = ci_upper)
}

real_means <- sapply(d13, mean)
shapiro_results <- sapply(bootstrap_results, function(x) shapiro.test(x)$p.value)
shapiro_df <- data.frame(Variable = names(shapiro_results), p_value = shapiro_results)

Pour rappel, l’axe des abscisses est la valeurs des moyennes bootstrapées. Les intervalles (bins) ou chacun regroupe un nombre n de valeur. L’axe des ordonnées montre le nombre de fois que les valeurs de la variable tombent dans le bins (on parle de denstié de valeur. La symétrie montre la normalité des distributions avec des p-value confirmant le test de Shapiro. Les moyennes représentent en générale une tendance (fréquence élevé). L’équivalence entre la moyenne bootstrapé et la moyenne réelle montre une bonne représentation de la population.

Test de différence de moyenne

Voir le code
# Fonction pour calculer la différence de moyenne entre les groupes 'Oui' et 'Non' pour une variable donnée
bootstrap_diff_mean <- function(data, group_var, value_var, B = 1000) {
  # Séparer les groupes
  group_oui <- data[data[[group_var]] == "Oui", value_var]
  group_non <- data[data[[group_var]] == "Non", value_var]
  
  n_oui <- length(group_oui)
  n_non <- length(group_non)
  
  diff_means <- numeric(B)  # Stocker les différences de moyennes
  
  # Boucle pour le bootstrap
  for (i in 1:B) {
    # Bootstrap pour le groupe "Oui"
    sample_oui <- sample(group_oui, size = n_oui, replace = TRUE)
    
    # Bootstrap pour le groupe "Non"
    sample_non <- sample(group_non, size = n_non, replace = TRUE)
    
    # Calculer la différence de moyenne entre "Oui" et "Non"
    diff_means[i] <- mean(sample_oui) - mean(sample_non)
  }
  
  return(diff_means)
}

# Appliquer le bootstrap pour chaque variable d'intérêt
variables_continues <- c("Score.fertilité", "TempsAssis", "MarcheMET", "ModéréeMET", "IntensitéMET", "TotalMET")

bootstrap_diff_results <- list()
for (var in variables_continues) {
  bootstrap_diff_results[[var]] <- bootstrap_diff_mean(d9, "Fertile", var, B = 1000)
}

# Calcul des intervalles de confiance pour chaque variable
ci_diff_results <- list()
for (var in variables_continues) {
  ci_lower <- quantile(bootstrap_diff_results[[var]], 0.025)  # Limite inférieure (2.5%)
  ci_upper <- quantile(bootstrap_diff_results[[var]], 0.975)  # Limite supérieure (97.5%)
  ci_diff_results[[var]] <- c(lower = ci_lower, upper = ci_upper)
}

# Afficher les intervalles de confiance des différences de moyennes
ci_diff_df <- do.call(rbind, ci_diff_results)
colnames(ci_diff_df) <- c("CI Lower", "CI Upper")  # Renommer les colonnes pour plus de clarté
print(ci_diff_df)
                    CI Lower     CI Upper
Score.fertilité    0.1392376    0.2178435
TempsAssis      -126.0472069  -26.2456580
MarcheMET        -10.2559287  349.5022842
ModéréeMET      -829.1027397  407.2534247
IntensitéMET      23.0000000  756.7123288
TotalMET        -390.4482877 1253.3847603
# Chargement de ggplot2
library(ggplot2)

# Préparer le dataframe pour ggplot
data_ci <- data.frame(
  Variable = rownames(ci_diff_df),  # Les noms des variables
  CI_Lower = ci_diff_df[, "CI Lower"],  # Limite inférieure
  CI_Upper = ci_diff_df[, "CI Upper"],  # Limite supérieure
  MeanDiff = c(0.178107, -77.149443, 172.041137, -193.029315, 389.135890, 452.746384)  # Moyennes préalablement calculées
)

Ici, on observe une significativité dans les moyennes de temps assis, de score de fertilité et d’activité physique intense. Par rapport au valeur brute, on montre ici que le temps assis pourrait également jouer un rôle dans la fertilité. La marche se montre au seuil de la significativité. Un test de permutation à également été réalisé et à montrer la même significativité pour chacune des variables.

Régression linéaire et logistique

Régression logistique
Voir le code
d15=d1
d15 <- cbind(d15,APF$Fertile)
colnames(d15)[ncol(d15)] <- "Fertile"
d15$Fertile=as.factor(d15$Fertile)
# Fonction de bootstrap
bootstrap_lm <- function(data, indices) {
  d15 <- data[indices, ]
  model <- glm(Fertile ~IntensitéMET + ModéréeMET + MarcheMET + TempsAssis + Score.fertilité + TotalMET, data = d15,family = binomial)
  return(coef(model))
}
library(boot)
# Application du bootstrap avec 1000 répétitions
bootstrap_results <- boot(data = d15, statistic = bootstrap_lm, R = 1000)
# Extraire les coefficients pour chaque échantillon bootstrap
intercepts <- bootstrap_results$t[, 1]
coefficients_x1 <- bootstrap_results$t[, 2] 
coefficients_x2 <- bootstrap_results$t[, 3]  
coefficients_x3 <- bootstrap_results$t[, 4] 
coefficients_x4 <- bootstrap_results$t[, 5]
coefficients_x5 <- bootstrap_results$t[, 6]
coefficients_x6 <- bootstrap_results$t[, 7] 
coefficients_long <- data.frame(
  Coefficient = c(rep("Intercept", length(intercepts)), 
                  rep("IntensitéMET", length(coefficients_x1)), 
                  rep("ModéréeMET", length(coefficients_x2)), 
                  rep("MarcheMET", length(coefficients_x3)), 
                  rep("TempsAssis", length(coefficients_x4)),
                  rep("Score.fertilité",length(coefficients_x5)),
                  rep("TotalMET",length(coefficients_x6))),
  Value = c(intercepts, coefficients_x1, coefficients_x2, coefficients_x3, coefficients_x4,coefficients_x5,coefficients_x6)
)
# Calculer la moyenne +SD pour chaque coefficient
mean_values <- aggregate(Value ~ Coefficient, data = coefficients_long, FUN = mean)
sd_values <- aggregate(Value ~ Coefficient, data = coefficients_long, FUN = sd)
# Calculer les p-values
B <- 1000
p_values <- sapply(1:nrow(mean_values), function(i) {
  # t-statistic
  t_stat <- mean_values$Value[i] / (sd_values$Value[i] / sqrt(B))  # Diviser par sqrt(B)
  
  # Degrés de liberté pour bootstrap (B - 1)
  df <- B - 1
  
  # p-value bilatérale
  2 * (1 - pt(abs(t_stat), df = df))  # Utiliser df ajusté
})

# Ajouter les p-values aux moyennes dans une nouvelle data frame
results_df <- data.frame(
  Coefficient = mean_values$Coefficient,
  Mean = mean_values$Value,
  p_value = p_values
)
results_df$Odds_Ratio <- exp(results_df$Mean)

Attaching package: 'DT'
The following objects are masked from 'package:shiny':

    dataTableOutput, renderDataTable
Résultats des Coefficients de Régression linéaire
Coefficient Mean p_value Odds_Ratio
IntensitéMET 0.0001732 0.0000000 1.000173e+00
Intercept -5.6202711 0.0000000 3.623700e-03
MarcheMET 0.0005804 0.0000000 1.000581e+00
ModéréeMET 0.0000428 0.0313549 1.000043e+00
Score.fertilité 13.8049011 0.0000000 9.894466e+05
TempsAssis -0.0042497 0.0000000 9.957593e-01
TotalMET -0.0000570 0.0019529 9.999430e-01
Régression linéaire
Voir le code
# Fonction de bootstrap
bootstrap_lm2 <- function(data, indices) {
  d9 <- data[indices, ]
  model2 <- lm(Score.fertilité ~IntensitéMET + ModéréeMET + MarcheMET + TempsAssis + TotalMET, data = d9)
  return(coef(model2))
}
# Application du bootstrap avec 1000 répétitions
bootstrap_results2 <- boot(data = d9, statistic = bootstrap_lm2, R = 1000)
# Extraire les coefficients pour chaque échantillon bootstrap
intercepts2 <- bootstrap_results2$t[, 1]
coefficients_x11 <- bootstrap_results2$t[, 2] 
coefficients_x22 <- bootstrap_results2$t[, 3]  
coefficients_x33 <- bootstrap_results2$t[, 4] 
coefficients_x44 <- bootstrap_results2$t[, 5]
coefficients_x55 <- bootstrap_results2$t[, 6]
coefficients_long2 <- data.frame(
  Coefficient = c(rep("Intercept", length(intercepts2)), 
                  rep("IntensitéMET", length(coefficients_x11)), 
                  rep("ModéréeMET", length(coefficients_x22)), 
                  rep("MarcheMET", length(coefficients_x33)), 
                  rep("TempsAssis", length(coefficients_x44)),
                  rep("TotalMET",length(coefficients_x55))),
  Value = c(intercepts2, coefficients_x11, coefficients_x22, coefficients_x33, coefficients_x44,coefficients_x55)
)
# Calculer la moyenne +SD pour chaque coefficient
mean_values2 <- aggregate(Value ~ Coefficient, data = coefficients_long2, FUN = mean)
sd_values2 <- aggregate(Value ~ Coefficient, data = coefficients_long2, FUN = sd)
# Calculer les p-values
B <- 1000
p_values2 <- sapply(1:nrow(mean_values2), function(i) {
  # t-statistic
  t_stat2 <- mean_values2$Value[i] / (sd_values2$Value[i] / sqrt(B))  # Diviser par sqrt(B)
  
  # Degrés de liberté pour bootstrap (B - 1)
  df2 <- B - 1
  
  # p-value bilatérale
  2 * (1 - pt(abs(t_stat2), df = df2))  # Utiliser df ajusté
})

# Ajouter les p-values aux moyennes dans une nouvelle data frame
results_df2 <- data.frame(
  Coefficient = mean_values2$Coefficient,
  Mean = mean_values2$Value,
  p_value = p_values2
)
results_df2$Odds_Ratio <- exp(results_df2$Mean)
Résultats des Coefficients de Régression logistique
Coefficient Mean p_value Odds_Ratio
IntensitéMET 0.0000212 0.0000000 1.0000212
Intercept 0.4946889 0.0000000 1.6399880
MarcheMET 0.0000009 0.4907032 1.0000009
ModéréeMET -0.0000218 0.0000000 0.9999782
TempsAssis -0.0000833 0.0000000 0.9999167
TotalMET 0.0000120 0.0000000 1.0000120

Lorsqu’on observe les données issus de la régression logistique, on observe qu’une augmentation de la marche est significativement associé à une augmentation des chances de fertilité. Quant au temps, il est lui à l’inverse classé comme une variable négatif pour les chances de fertilité.

Sur les données de régression linéaire, l’activité physique intense et total est associé significativement à une augmentation du score de fertilité. Au contraire, le temps assis et l’activité modérée est associé à une diminution de ce même score.

4. Conclusion

Avec un score KMO moyen de 0.38, les variables sont difficilement interprétable dans le cadre d’une ACP, par conséquent les résultats, aussi interprétable qu’ils soient ne permettront de conclure efficacement sur la situation. Dans cette analyse, les deux premiers axes représentent 56,7% des observations. Il est même à noté que l’axe 3 ne représentent que quelque peu moins que l’axe 2. Sur la première dimension, les individus ayant une activité physique sont représenté à droite, là ou sur la deuxième dimension, ils semblent avoir une répartition homogène de ces individus. Pourtant, c’est bien cette deuxième dimension qui permet de caractérisé les individus selon leur score de fertilité et donc d’avoir la capacité de instigué au mieux un individus fertile ou infertile. En promettant cette fertilité, on s’aperçoit tout de même que les individus fertile sont disposés en haut de la représentation graphique. La PCA n’a pas apporté de nouvelle observation mais à confirmer le score comme un représentant de la fertilité. L’analyse en bootstrap permet d’observe une normalité améliorer pour la l’activité de marche (p = 0,106), l’activité total (p = 0,283) et le temps assis (p = 0,601). La comparaison de moyenne issus de se bootstrap montrent une différence de moyenne significatif entre le groupe fertile et infertile pour l’activité physique intense et le temps assis. La régression logistique confirme la l’activité de marche comme étant une variable significativement influente dans l’augmentation des chances de fertilité. Le score quant a lui est bien corrélé de manière significative avec l’activité physique intense et total.



Partie IV : Classification des données

Faisabilité de l’analyse de clustering

On vérifie la faisabilité de l’analyse en clustering en calculant la statistique de Hopkings.

get_clust_tendency(d1, graph = FALSE,n=50, seed = 123)
$hopkins_stat
[1] 0.8615869

$plot
NULL

Si l’indice de Hopkins est proche de 1, ça indique une tendance au regroupement et donc une argument possitifs à une analyse en cluster. Ici un score supérieur à 0,8 introduit bien une tendance au regroupement.

1. Détermination du nombre optimal de cluster

L’utilisation optimal de FactoMineR obligent à utiliser la partition ayant la plus grande perte relative d’inertie. On peut calculer cette indicateur via best.cutree. L’extension JLutils en propose une, la fonction regarde quelle serait la meilleure partition entre 3 et 20 classes

hc <- hclust(dist(d1), method="average")
src<- source(url("https://raw.githubusercontent.com/larmarange/JLutils/master/R/clustering.R"))
best<-best.cutree(hc)
best
[1] 3

Le nombre idéal de Cluster serait de 4.

Pour confirmer ce choix, nous pouvons utiliser une pour observer les pertes absolue.

cah_fm <- FactoMineR::HCPC(res.pca, graph = FALSE, min = 3)
cah_fm |> plot_inertia_from_tree()

On remarque que la perte absolue est quasiment équivalente entre un nombre de cluster de 3 ou 4 (si on exclus le fait d’avoir que 2 clusters).

2. Classification ascendante hiérarchique

cah_fm <- FactoMineR::HCPC(res.pca, graph = TRUE,nb.clust = 3)
d1$typo_cah_fm <- cah_fm$data.clust$clust

Visualisation intérractif

Faire l’interprêtation

3. Caractérisation de la typologie

d1 <- cbind(d1,APF$Fertile)
colnames(d1)[ncol(d1)] <- "Fertile"
Voir le code
# Supposons que vos données s'appellent 'data'
# Standardisation des variables d'activité physique
data_standardized <- d1 %>%
  mutate(
    TempsAssis_z = scale(TempsAssis),        # Standardisation du TempsAssis
    MarcheMET_z = scale(MarcheMET),          # Standardisation du MarcheMET
    ModereeMET_z = scale(ModéréeMET),        # Standardisation du ModéréeMET
    IntensiteMET_z = scale(IntensitéMET)     # Standardisation du IntensitéMET
  )

# Inversion de la variable TempsAssis_z car elle diminue le score
data_standardized <- data_standardized %>%
  mutate(TempsAssis_inv = -TempsAssis_z)

# Création du score de sportivité
data_standardized <- data_standardized %>%
  mutate(
    Score_Sportivite = MarcheMET_z + ModereeMET_z + IntensiteMET_z
  )

# Calcul de la moyenne des scores par groupe
score_par_groupe <- data_standardized %>%
  group_by(typo_cah_fm) %>%
  summarise(Moyenne_Score = mean(Score_Sportivite, na.rm = TRUE))

# Affichage du score par groupe
print(score_par_groupe)
# A tibble: 3 × 2
  typo_cah_fm Moyenne_Score
  <fct>               <dbl>
1 1                   -1.22
2 2                    1.23
3 3                    1.66
d1 <- d1 %>%
  mutate(
    TempsAssis_z = scale(TempsAssis),         # Standardisation du TempsAssis
    MarcheMET_z = scale(MarcheMET),           # Standardisation du MarcheMET
    ModereeMET_z = scale(ModéréeMET),         # Standardisation du ModéréeMET
    IntensiteMET_z = scale(IntensitéMET),     # Standardisation du IntensitéMET
    TempsAssis_inv = -TempsAssis_z,           # Inversion du TempsAssis standardisé
    Score_Sportivite = TempsAssis_inv + MarcheMET_z + ModereeMET_z + IntensiteMET_z # Calcul du score
  )

# Suppression des colonnes intermédiaires (si elles ne sont plus nécessaires)
d1 <- d1 %>%
  select(-TempsAssis_z, -MarcheMET_z, -ModereeMET_z, -IntensiteMET_z, -TempsAssis_inv)
Characteristic 1, N = 791 2, N = 341 3, N = 331
Score.fertilité 0.46 (0.36, 0.55) 0.57 (0.47, 0.66) 0.45 (0.36, 0.53)
TempsAssis 327 (240, 420) 300 (240, 420) 240 (180, 300)
MarcheMET 330 (171, 495) 336 (264, 495) 660 (330, 1,980)
ModéréeMET 400 (0, 1,200) 1,200 (525, 2,400) 4,800 (3,600, 7,200)
IntensitéMET 0 (0, 0) 2,400 (2,400, 2,700) 0 (0, 0)
TotalMET 1,200 (495, 1,980) 4,048 (3,233, 5,183) 5,295 (4,380, 7,980)
Fertile


    Non 48 (61%) 9 (26%) 16 (48%)
    Oui 31 (39%) 25 (74%) 17 (52%)
Score_Sportivite -1.45 (-2.28, -0.36) 0.98 (-0.02, 1.69) 2.14 (0.95, 2.82)
1 Median (IQR); n (%)

Tout comme chez l’homme, on retrouve un cluster qui montre un score de fertilité particulièrement élevé au 2 autres. Concernant les temps d’activité physique, ils sont en adéquation avec la sédentarité. On observe toute une fois une infertilité plus marqué pour le cluster 1 par rapport au cluster 3. Ce qui suppose une meilleurs classification que chez l’homme.

Test de l’indépendance des cluster

On créer des subset des cluster via les jeu de donnée d1

Cluster1=subset(d1,typo_cah_fm=="1")
Cluster2=subset(d1,typo_cah_fm=="2")
Cluster3=subset(d1,typo_cah_fm=="3")

Hypothèse H0 : les clusters selon le score de fertilité suivent une distribution de loi normal

Voir le code
#Test de Shapiro
shapiro_Cluster1=shapiro.test(Cluster1$Score.fertilité)
shapiro_Cluster2=shapiro.test(Cluster2$Score.fertilité)
shapiro_Cluster3=shapiro.test(Cluster3$Score.fertilité)
shapiro_Cluster1a=shapiro.test(Cluster1$TempsAssis)
shapiro_Cluster1b=shapiro.test(Cluster2$TempsAssis)
shapiro_Cluster1c=shapiro.test(Cluster3$TempsAssis)

#Réorganisation des data_frame
d3 <- data.frame(
  valeurs = c(Cluster1$Score.fertilité, Cluster2$Score.fertilité, Cluster3$Score.fertilité),
  groupe = factor(rep(c("Groupe 1", "Groupe 2", "Groupe 3"), 
                      times = c(length(Cluster1$Score.fertilité), length(Cluster2$Score.fertilité), length(Cluster3$Score.fertilité))))
)
d4 <- data.frame(
  valeurs = c(Cluster1$TempsAssis, Cluster2$TempsAssis, Cluster3$TempsAssis),
  groupe = factor(rep(c("Groupe 1", "Groupe 2", "Groupe 3"), 
                      times = c(length(Cluster1$TempsAssis), length(Cluster2$TempsAssis), length(Cluster3$TempsAssis))))
)
#Test ANOVA
anova_resultat <- aov(valeurs ~ groupe, data = d3)
anova_resultat2 <- aov(valeurs ~ groupe, data = d4)

#Graphique pour le score de fertilité
p4 <- ggplot(d3, aes(x = valeurs, fill = groupe)) +
  geom_density(alpha = 0.5) +
  stat_function(fun = dnorm, 
                args = list(mean = mean(d3$valeurs), sd = sd(d3$valeurs)), 
                color = "black", size = 1, linetype = "dashed") + # Courbe normale
  labs(title = "Courbes de densité des distributions avec courbe normale pour le score", 
       x = "Valeurs", 
       y = "Densité") +
  theme_minimal() +
  theme(legend.position = "top")

p4 <- p4 + 
  annotate("text", x = Inf, y = Inf, 
           label = paste("Shapiro-Wilk:\nCluster1: W =", round(shapiro_Cluster1$statistic, 4), 
                         ", p =", round(shapiro_Cluster1$p.value, 4), 
                         "\nCluster2: W =", round(shapiro_Cluster2$statistic, 4), 
                         ", p =", round(shapiro_Cluster2$p.value, 4),
                         "\nCluster2: W =", round(shapiro_Cluster3$statistic, 4),
                         ", p =", round(shapiro_Cluster3$p.value, 4)),
           hjust = 1.1, vjust = 1.5, size = 2.5, color = "black", 
           parse = FALSE)

#Graphique pour le temps assis
p5 <- ggplot(d4, aes(x = valeurs, fill = groupe)) +
  geom_density(alpha = 0.5) +
  stat_function(fun = dnorm, 
                args = list(mean = mean(d4$valeurs), sd = sd(d4$valeurs)), 
                color = "black", size = 1, linetype = "dashed") + # Courbe normale
  labs(title = "Courbes de densité des distributions avec courbe normale pour le temps assis", 
       x = "Valeurs", 
       y = "Densité") +
  theme_minimal() +
  theme(legend.position = "top")

p5 <- p5 + 
  annotate("text", x = Inf, y = Inf, 
           label = paste("Shapiro-Wilk:\nCluster1: W =", round(shapiro_Cluster1a$statistic, 4), 
                         ", p =", round(shapiro_Cluster1a$p.value, 4), 
                         "\nCluster2: W =", round(shapiro_Cluster1b$statistic, 4), 
                         ", p =", round(shapiro_Cluster1b$p.value, 4),
                         "\nCluster2: W =", round(shapiro_Cluster1c$statistic, 4),
                         ", p =", round(shapiro_Cluster1c$p.value, 4)),
           hjust = 1.1, vjust = 1.5, size = 2.5, color = "black", 
           parse = FALSE)

Faire l’interprêtation

Hypothèse H0 : Les moyennes des scores de fertilité et du temps assis des 3 groupes ne sont pas significativement différentes.

summary(anova_resultat)
             Df Sum Sq Mean Sq F value   Pr(>F)    
groupe        2  0.311 0.15552   7.552 0.000762 ***
Residuals   143  2.945 0.02059                     
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
summary(anova_resultat2)
             Df  Sum Sq Mean Sq F value Pr(>F)  
groupe        2  204456  102228   4.261 0.0159 *
Residuals   143 3430465   23989                 
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Résultat des ANOVA

On rejette l’hypothèse nul pour les 2 variables. Pour le score de fertilité et le temps assis, il y a une différence significative

Warning in wilcox.test.default(c(240, 780, 420, 360, 420, 480, 240, 480, :
cannot compute exact p-value with ties

interprêtation

Analyse des autres variables par test non paramétrique

Hormis le score de fertilité et le temps assis, toutes les autres variables ne suivent pas une loi normal. Pour pouvoir tout de même ajuster le discours, on utilise la variante non paramétrique du test d’ANOVA : le test de Kurskall Wallis, le test de post HOC est le test de dunn.

Voir le code
d5=d1[,c(3,4,5,6,7,9)]
names(d1)[names(d1) == "typo_cah_fm"] <- "Cluster"
d1_normalized <- d1 %>%
  mutate(across(where(is.numeric), ~ (.-mean(.)) / sd(.)))
d5_normalized <- d5 %>%
  mutate(across(where(is.numeric), ~ (.-mean(.)) / sd(.)))

names(d5_normalized)[names(d5_normalized) == "typo_cah_fm"] <- "Cluster"
# Convertir Cluster en facteur
d5_normalized$Cluster <- as.factor(d5_normalized$Cluster)

# Calculer les moyennes par cluster
mean_data <- d5_normalized %>%
  group_by(Cluster) %>%
  summarise(across(where(is.numeric), mean))

# Tester la significativité des moyennes pour chaque variable avec Kruskal-Wallis et le test de Dunn
anova_results <- lapply(names(mean_data)[-1], function(var) {
  formula <- as.formula(paste(var, "~ Cluster"))
  kw_result <- kruskal.test(formula, data = d5_normalized)
  tidy_result <- tidy(kw_result)
  
  # Si Kruskal-Wallis est significatif, faire un test de Dunn
  if (tidy_result$p.value[1] < 0.05) {
    dunn_result <- dunn.test(d5_normalized[[var]], d5_normalized$Cluster, method = "bonferroni")
    dunn_df <- data.frame(
      comparison = dunn_result$comparisons,
      p_value = dunn_result$P.adjusted,
      Variable = var
    )
    return(dunn_df)
  } else {
    return(NULL)
  }
})
  Kruskal-Wallis rank sum test

data: x and group
Kruskal-Wallis chi-squared = 12.2768, df = 2, p-value = 0

                           Comparison of x by group                            
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          1          2
---------+----------------------
       2 |  -0.653002
         |     0.7706
         |
       3 |  -3.480742  -2.404260
         |    0.0008*    0.0243*

alpha = 0.05
Reject Ho if p <= alpha/2
  Kruskal-Wallis rank sum test

data: x and group
Kruskal-Wallis chi-squared = 60.6326, df = 2, p-value = 0

                           Comparison of x by group                            
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          1          2
---------+----------------------
       2 |  -2.051847
         |     0.0603
         |
       3 |  -7.781740  -4.878233
         |    0.0000*    0.0000*

alpha = 0.05
Reject Ho if p <= alpha/2
  Kruskal-Wallis rank sum test

data: x and group
Kruskal-Wallis chi-squared = 114.1407, df = 2, p-value = 0

                           Comparison of x by group                            
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          1          2
---------+----------------------
       2 |  -10.03402
         |    0.0000*
         |
       3 |   0.514654   8.858631
         |     0.9102    0.0000*

alpha = 0.05
Reject Ho if p <= alpha/2
  Kruskal-Wallis rank sum test

data: x and group
Kruskal-Wallis chi-squared = 102.9078, df = 2, p-value = 0

                           Comparison of x by group                            
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          1          2
---------+----------------------
       2 |  -7.069079
         |    0.0000*
         |
       3 |  -9.050512  -1.743170
         |    0.0000*     0.1220

alpha = 0.05
Reject Ho if p <= alpha/2
  Kruskal-Wallis rank sum test

data: x and group
Kruskal-Wallis chi-squared = 79.2174, df = 2, p-value = 0

                           Comparison of x by group                            
                                 (Bonferroni)                                  
Col Mean-|
Row Mean |          1          2
---------+----------------------
       2 |  -6.356578
         |    0.0000*
         |
       3 |  -7.839968  -1.314429
         |    0.0000*     0.2831

alpha = 0.05
Reject Ho if p <= alpha/2
# Combiner les résultats de Dunn
dunn_results_df <- bind_rows(anova_results)

# Préparer les données pour le diagramme en boîte
d5_normalized_long <- d5_normalized %>%
  pivot_longer(cols = -Cluster, names_to = "Variable", values_to = "Valeur")
Warning in wilcox.test.default(c(1.4965995134689, 2.53791895254655,
1.4965995134689, : cannot compute exact p-value with ties
Warning in wilcox.test.default(c(-0.722429557975582, -1.02851443793905, :
cannot compute exact p-value with ties
Warning in wilcox.test.default(c(-0.257639395088843, -0.554290433598079, :
cannot compute exact p-value with ties
Warning in wilcox.test.default(c(0.254477974726414, 0.421506143728285,
0.841956362250236, : cannot compute exact p-value with ties

Faire l’interprêtation

4. Projection sur la fertilité

Pour finir l’analyse des clusters, on peut les projeters sur la fertilité pour comparer les groupes.

tabCont22 <- xtabs(~Fertile+d1$Cluster,data=d1)

Un test de Chi2 est réalisé

H0 : Il y a indépendance entre les variables qualitatives A et B.

X-squared 
 11.21794 

5. Conclusion

Le score de Hopkins confirme la faisabilité d’une analyse en clustering. Selon l’extension JLutils, le nombre de cluster est idéalement de 3. La classification ascendante hiérarchique montre bien 3 clusters distincts qui ne semblent pas se chevaucher. Dans une première vu, le 2ème cluster possèdent un score plus élevé que les 2 autres groupes, ainsi qu’une score de sportivité plus faible que le groupe 3. Au vu de la normalité de distribution du score et du temps assis, on réalise un ANOVA. Le score de fertilité est bien significativeement différent pour le groupe 2 par rapport au deux autres groupes qui ne possèdent entre eux par de différence dans leur score. Le score de sportivité est significativement différent entre les trois groupes avec le 3ème groupe en tête, on observe intrinsèquement qu’il dispose de valeur plus élevé pour les activités de marche et d’activité physique modérée. Le groupe 2 quant a lui à une meilleurs activité physique intense mais qui ne permet pas, sur une mesure de l’activité physique totale, de rattraper le groupe 3 qui en plus de sa, se distingue par des individus moins sédentaire. On remarque là peut être un effet plus important de la marche et de la sédentarité que de l’activité physique sur une analyse total d’un profil de sportivité. La projection sur la fertilité montre que le groupe 2 comporte une proportion d’individus fertile plus importante, là ou le groupe 3 est à quasi égalité dans sa proposition. Avec un score de fertilité et de sportivité diminué, le groupe 1 à une plus grande proportion d’individus infertile.

Partie V : Apprentissage automatique

Parmis les différents, nous avons testé différent modèle de prédiction. Le modèle qui a retenu notre attention était le modèle de forêt aléatoire qui semblait présenter des meilleurs paramètres. Seulement, on peut se rendre compte que l’accurency et le Kappa varie beaucoup lors de la validation croisée. Ce qui justifie que nos données acutelles ne permettent pas de créer un bon modèle de prédiction.

Une application Shiny montre la variation des paramètres selon l’actualisation du graphique