Cet audit analytique supplémentaire documente les principales étapes de préparation des données, l’évaluation de la fidélité du codage, les transformations de variables, les procédures de diagnostic ainsi que les décisions de modélisation statistique qui sous-tendent les analyses présentées dans le manuscrit principal. Ce document est fourni afin de favoriser la transparence, la reproductibilité et l’interprétabilité des résultats.
Ce document complète, sans toutefois s’y substituer, la section « Méthodologie » du manuscrit principal. Toutes les informations méthodologiques essentielles sont rapportées dans l’article lui-même. Le présent fichier fournit le suivi analytique détaillé, incluant les vérifications intermédiaires, les tests de diagnostic et les sorties statistiques supplémentaires.
Note sur la transparence des données et la
reproductibilité
Le jeu de données
Clean_BD_TikTok_F.csv mis à disposition ici constitue la
base de travail ayant servi aux modélisations statistiques. Il regroupe
les indicateurs d’engagement et les scores issus du codage de la valence
pour les \(n=118\) vidéos de
l’échantillon.
Conformément aux pratiques de recherche en
sources ouvertes (OSINT), les données proviennent exclusivement de
l’espace public numérique. Pour les besoins de l’analyse statistique,
les données textuelles qualitatives (commentaires bruts) ont été
transformées en variables catégorielles et numériques. Les identifiants
originaux des vidéos sont conservés pour permettre la vérifiabilité des
sources, garantissant ainsi une transparence totale du processus de
recherche.
Objectif : Vérifier que le codage est suffisamment cohérent entre évaluateurs avant les analyses principales.
Procédure : La fidélité intercodeurs a été estimée séparément pour les vidéos et les commentaires à partir d’un codage en double aveugle.
Règle de décision : Les analyses subséquentes ont été poursuivies si la concordance observée était jugée élevée et substantiellement cohérente avec la structure des désaccords.
knitr::kable(
data.frame(
Base = c("Vidéos", "Commentaires"),
Type = c("Kappa simple", "Kappa pondéré quadratique"),
N = c(nrow(Kappa_Video), nrow(Kappa_Commentaire)),
Kappa = c(
round(kappa_video$value, 3),
round(kappa_commentaire$value, 3)
),
z = c(
round(kappa_video$statistic, 3),
round(kappa_commentaire$statistic, 3)
),
p = c(
ifelse(kappa_video$p.value < .001, "< .001", signif(kappa_video$p.value, 3)),
ifelse(kappa_commentaire$p.value < .001, "< .001", signif(kappa_commentaire$p.value, 3))
)
),
caption = "Fidélité intercodeurs pour le codage des vidéos et des commentaires."
)
| Base | Type | N | Kappa | z | p |
|---|---|---|---|---|---|
| Vidéos | Kappa simple | 118 | 0.838 | 16.423 | < .001 |
| Commentaires | Kappa pondéré quadratique | 1357 | 0.880 | 32.415 | < .001 |
Note : Le codage repose sur 118 vidéos et 1 357 commentaires de premier niveau, codés en double aveugle. Les désaccords ont été résolus par discussion entre les codeurs et, lorsque nécessaire, par l’intervention d’un troisième évaluateur.
knitr::kable(tab_video, caption = "Matrice de contingence du codage des vidéos.")
| 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|
| 44 | 0 | 2 | 0 | 0 |
| 0 | 15 | 1 | 0 | 0 |
| 3 | 4 | 23 | 0 | 0 |
| 1 | 0 | 0 | 7 | 1 |
| 1 | 0 | 1 | 0 | 15 |
knitr::kable(tab_commentaire, caption = "Matrice de contingence du codage des commentaires.")
| 1 | 2 | 3 | 4 |
|---|---|---|---|
| 290 | 30 | 1 | 0 |
| 29 | 679 | 37 | 2 |
| 1 | 28 | 144 | 24 |
| 0 | 4 | 30 | 58 |
Note : Les commentaires analysés en double aveugle représentent 10 % de l’échantillon total. La concentration des observations sur la diagonale suggère une forte concordance. Pour les commentaires, les désaccords se concentrent surtout entre catégories adjacentes, ce qui appuie l’usage d’un kappa pondéré quadratique.
Objectif : Vérifier que la base analytique finale est complète, cohérente et adéquatement structurée avant de procéder aux analyses descriptives et inférentielles.
Procédure : La base de données finale a été inspectée afin de confirmer le nombre d’observations et de variables, le type de chaque variable, ainsi que l’absence de valeurs manquantes pour les variables retenues dans les analyses. Une vérification de cohérence générale de la structure de la base a également été réalisée à partir d’une inspection tabulaire.
Règle de décision : Les analyses ont été poursuivies lorsque la base ne présentait pas de problème majeur d’intégrité, notamment en ce qui concerne les valeurs manquantes, la structure des variables et la cohérence générale du fichier analytique.
glimpse(BD_TikTok)
## Rows: 118
## Columns: 20
## $ id_video <dbl> 74627374, 74635192, 74653101, 74657027, 74683437, 747…
## $ date <date> 2025-01-22, 2025-01-24, 2025-01-29, 2025-01-30, 2025…
## $ Video_category_3 <dbl> 1, 1, 2, 2, 1, 2, 1, 2, 2, 1, 2, 1, 2, 3, 2, 1, 1, 1,…
## $ views <dbl> 388100, 1300000, 844600, 820000, 1100000, 557600, 140…
## $ like_rate <dbl> 0.05256377, 0.04761539, 0.03705896, 0.05621951, 0.062…
## $ likes <dbl> 20400, 61900, 31300, 46100, 68400, 18900, 61200, 2640…
## $ share_rate <dbl> 0.007851069, 0.005186154, 0.007209330, 0.002379268, 0…
## $ shares <dbl> 3047, 6742, 6089, 1951, 5635, 1014, 16600, 1576, 1024…
## $ comment_rate <dbl> 0.001378511, 0.001687692, 0.001075065, 0.001556098, 0…
## $ total_comments <dbl> 535, 2194, 908, 1276, 1417, 384, 1858, 647, 560, 805,…
## $ comments_lvl1 <dbl> 327, 484, 350, 417, 294, 245, 470, 158, 399, 140, 342…
## $ n_comments_lvl1 <dbl> 177, 215, 184, 201, 167, 150, 212, 113, 196, 103, 182…
## $ n_pos <dbl> 49, 69, 56, 24, 51, 38, 44, 83, 29, 35, 57, 24, 7, 34…
## $ n_neu <dbl> 85, 90, 104, 76, 106, 64, 119, 19, 115, 49, 89, 93, 1…
## $ n_neg <dbl> 27, 35, 20, 58, 10, 28, 40, 4, 43, 17, 33, 11, 2, 44,…
## $ n_host <dbl> 16, 21, 4, 43, 0, 20, 9, 7, 9, 2, 3, 7, 2, 38, 3, 2, …
## $ top_pos <dbl> 0, 0, 434, 0, 735, 190, 0, 2358, 1336, 1242, 0, 602, …
## $ top_neu <dbl> 1141, 2041, 2058, 927, 676, 183, 0, 0, 506, 0, 272, 0…
## $ top_neg <dbl> 3756, 7184, 0, 4345, 0, 0, 7448, 0, 0, 1001, 2691, 76…
## $ top_hos <dbl> 0, 0, 0, 0, 0, 482, 0, 0, 0, 0, 0, 0, 0, 674, 0, 0, 0…
Note : La base de données finale comprend 118 observations et 20 variables.
library(dplyr)
library(tidyr)
library(knitr)
na_table <- BD_TikTok %>%
summarise(across(everything(), ~ sum(is.na(.)))) %>%
pivot_longer(
cols = everything(),
names_to = "Variable",
values_to = "NA"
) %>%
filter(NA > 0)
if (nrow(na_table) == 0) {
na_table <- data.frame(
Vérification = "Valeurs manquantes",
Résultat = "Aucune valeur manquante détectée"
)
}
knitr::kable(
na_table,
caption = "Vérification des valeurs manquantes"
)
| Vérification | Résultat |
|---|---|
| Valeurs manquantes | Aucune valeur manquante détectée |
Note : Aucune valeur manquante (NA) n’a été observée dans la base de données pour les variables retenues dans les analyses.
check_duplicates <- sum(duplicated(BD_TikTok$id_video))
check_valence <- sum(abs((BD_TikTok$n_pos + BD_TikTok$n_neu + BD_TikTok$n_neg + BD_TikTok$n_host) - BD_TikTok$n_comments_lvl1), na.rm = TRUE)
resultats_integrite <- data.frame(
Indicateur = c("Nombre de doublons (id_video)", "Somme des écarts de valence (Cohérence totale)"),
Valeur = c(check_duplicates, check_valence)
)
knitr::kable(resultats_integrite,
caption = "Résultats des tests d'intégrité des données",
align = "lc")
| Indicateur | Valeur |
|---|---|
| Nombre de doublons (id_video) | 0 |
| Somme des écarts de valence (Cohérence totale) | 0 |
Note : Le premier indicateur vérifie l’absence de doublons dans l’identifiant unique des vidéos (id_video). Le second évalue la cohérence interne des variables de valence en comparant, pour chaque vidéo, la somme des commentaires positifs, neutres, négatifs et hostiles au nombre total de commentaires de premier niveau codés (n_comments_lvl1). Une valeur de 0 indique une cohérence parfaite sur l’ensemble de la base.
data_dict <- data.frame(
Variable = c(
"Video_category_3", "views", "like_rate", "share_rate", "comment_rate",
"n_pos", "n_neg", "n_host"
),
Description = c(
"Catégorie de la vidéo (3 niveaux)",
"Nombre total de vues",
"Ratio de mentions j'aime par vue",
"Ratio de partages par vue",
"Ratio de commentaires par vue",
"Nombre de commentaires positifs",
"Nombre de commentaires négatifs",
"Nombre de commentaires hostiles"
),
Type = c(
"Factor", "Numeric", "Numeric", "Numeric", "Numeric",
"Numeric", "Numeric", "Numeric"
),
Scale = c(
"Nominale", "Ratio", "Proportion", "Proportion", "Proportion",
"Ratio", "Ratio", "Ratio"
),
Used_in = c(
"VI (Tous les modèles)", "VD (Engagement)", "VD (Engagement)", "VD (Engagement)", "VD (Engagement)",
"VD (Valence)", "VD (Valence)", "VD (Valence)"
),
Transformation = c(
"Aucune", "ln(x)", "ln(x)", "ln(x)", "ln(x)",
"ln(x)", "ln(x+1)", "ln(x+1)"
)
)
knitr::kable(data_dict,
caption = "Dictionnaire des données et spécifications des variables",
col.names = c("Variable", "Description", "Type", "Échelle", "Utilisée dans", "Transformation"))
| Variable | Description | Type | Échelle | Utilisée dans | Transformation |
|---|---|---|---|---|---|
| Video_category_3 | Catégorie de la vidéo (3 niveaux) | Factor | Nominale | VI (Tous les modèles) | Aucune |
| views | Nombre total de vues | Numeric | Ratio | VD (Engagement) | ln(x) |
| like_rate | Ratio de mentions j’aime par vue | Numeric | Proportion | VD (Engagement) | ln(x) |
| share_rate | Ratio de partages par vue | Numeric | Proportion | VD (Engagement) | ln(x) |
| comment_rate | Ratio de commentaires par vue | Numeric | Proportion | VD (Engagement) | ln(x) |
| n_pos | Nombre de commentaires positifs | Numeric | Ratio | VD (Valence) | ln(x) |
| n_neg | Nombre de commentaires négatifs | Numeric | Ratio | VD (Valence) | ln(x+1) |
| n_host | Nombre de commentaires hostiles | Numeric | Ratio | VD (Valence) | ln(x+1) |
Note : Ce tableau présente les principales variables retenues dans les analyses inférentielles, leur définition, leur niveau de mesure, leur rôle analytique et, le cas échéant, la transformation appliquée avant modélisation. Les transformations logarithmiques ont été utilisées afin de réduire l’asymétrie de certaines distributions. Pour les variables pouvant prendre la valeur 0, une constante de 1 a été ajoutée avant transformation.
Objectif : Décrire les principales variables retenues dans les analyses et documenter leur distribution générale.
Procédure : Les variables numériques ont été résumées à l’aide de statistiques descriptives, puis représentées graphiquement afin de documenter leur amplitude et leur distribution. Une attention particulière a été portée aux indicateurs d’engagement, aux variables de valence et aux mesures d’approbation secondaire saillante.
Règle de décision : Les distributions observées ont servi à orienter les étapes ultérieures de transformation et de sélection des variables pour les analyses inférentielles.
library(dplyr)
library(janitor)
##
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
library(knitr)
repartition_categories <- BD_TikTok %>%
mutate(
categorie_video = factor(
Video_category_3,
levels = c(1, 2, 3),
labels = c("Information", "Prévention/sensibilisation", "Image work")
)
) %>%
tabyl(categorie_video) %>%
adorn_pct_formatting(digits = 1) %>%
adorn_totals("row")
knitr::kable(
repartition_categories,
caption = "Répartition des vidéos selon les trois catégories analytiques"
)
| categorie_video | n | percent |
|---|---|---|
| Information | 47 | 39.8% |
| Prévention/sensibilisation | 47 | 39.8% |
| Image work | 24 | 20.3% |
| Total | 118 | - |
Note : Ce tableau présente la répartition des 118 vidéos selon les trois catégories analytiques retenues pour les analyses comparatives, soit les contenus informationnels, les contenus de prévention/sensibilisation et les contenus d’image work. Les pourcentages sont calculés sur l’ensemble des vidéos codées.
Les variables de type rate (p. ex., like_rate,
share_rate, comment_rate) correspondent à des
ratios calculés à partir du nombre total de vues, afin de standardiser
les indicateurs d’engagement. Les variables top_* (p. ex.,
top_pos, top_neu, top_neg,
top_hos) représentent une mesure d’approbation secondaire
saillante, définie comme la somme des mentions « j’aime » des trois
commentaires les plus appréciés pour chaque vidéo, selon leur
valence.
library(dplyr)
library(tidyr)
library(knitr)
vars_desc <- c(
"views", "like_rate", "likes", "share_rate", "shares",
"comment_rate", "total_comments", "comments_lvl1",
"n_comments_lvl1", "n_pos", "n_neu", "n_neg", "n_host",
"top_pos", "top_neu", "top_neg", "top_hos"
)
desc_num <- BD_TikTok %>%
select(all_of(vars_desc)) %>%
summarise(
across(
everything(),
list(
moyenne = ~ mean(., na.rm = TRUE),
ecart_type = ~ sd(., na.rm = TRUE),
mediane = ~ median(., na.rm = TRUE),
min = ~ min(., na.rm = TRUE),
max = ~ max(., na.rm = TRUE)
),
.names = "{.col}___{.fn}"
)
) %>%
pivot_longer(
cols = everything(),
names_to = c("Variable", ".value"),
names_sep = "___"
) %>%
mutate(across(where(is.numeric), ~ format(round(., 4), scientific = FALSE, trim = TRUE)))
knitr::kable(
desc_num,
caption = "Statistiques descriptives des variables numériques."
)
| Variable | moyenne | ecart_type | mediane | min | max |
|---|---|---|---|---|---|
| views | 358755.0847 | 373204.0267 | 266350.0000 | 26800.0000 | 2300000.0000 |
| like_rate | 0.0494 | 0.0138 | 0.0482 | 0.0178 | 0.0817 |
| likes | 18187.0932 | 19236.8436 | 12900.0000 | 901.0000 | 114000.0000 |
| share_rate | 0.0031 | 0.0041 | 0.0017 | 0.0002 | 0.0296 |
| shares | 1593.2627 | 3969.3474 | 427.0000 | 12.0000 | 35500.0000 |
| comment_rate | 0.0013 | 0.0006 | 0.0012 | 0.0003 | 0.0042 |
| total_comments | 493.8898 | 561.4202 | 330.5000 | 20.0000 | 3617.0000 |
| comments_lvl1 | 208.4153 | 195.9603 | 153.0000 | 13.0000 | 1389.0000 |
| n_comments_lvl1 | 115.0593 | 69.6619 | 110.5000 | 13.0000 | 302.0000 |
| n_pos | 30.2034 | 25.4123 | 24.0000 | 2.0000 | 133.0000 |
| n_neu | 58.8305 | 37.6405 | 56.0000 | 0.0000 | 165.0000 |
| n_neg | 20.3644 | 21.3264 | 14.0000 | 0.0000 | 108.0000 |
| n_host | 5.6610 | 7.7175 | 3.0000 | 0.0000 | 43.0000 |
| top_pos | 296.6695 | 767.2979 | 0.0000 | 0.0000 | 5677.0000 |
| top_neu | 759.8136 | 2793.1756 | 138.0000 | 0.0000 | 28814.0000 |
| top_neg | 777.2203 | 2497.8889 | 6.0000 | 0.0000 | 22187.0000 |
| top_hos | 15.5000 | 79.7001 | 0.0000 | 0.0000 | 674.0000 |
library(dplyr)
data_num <- BD_TikTok %>%
select(where(is.numeric)) %>%
select(-id_video)
library(tidyr)
data_long <- data_num %>%
pivot_longer(cols = everything(),
names_to = "variable",
values_to = "value")
library(ggplot2)
ggplot(data_long, aes(x = value)) +
geom_histogram(bins = 30) +
facet_wrap(~variable, scales = "free")
Note : Les histogrammes présentent la distribution des variables numériques retenues pour les analyses. Les échelles de l’axe des x sont libres afin de respecter l’amplitude propre à chaque variable.
library(dplyr)
library(ggplot2)
library(scales)
##
## Attaching package: 'scales'
## The following object is masked from 'package:readr':
##
## col_factor
library(tibble)
comment_counts <- c(
Positif = sum(BD_TikTok$n_pos, na.rm = TRUE),
Neutre = sum(BD_TikTok$n_neu, na.rm = TRUE),
Négatif = sum(BD_TikTok$n_neg, na.rm = TRUE),
Hostile = sum(BD_TikTok$n_host, na.rm = TRUE)
)
approval_counts <- c(
Positif = sum(BD_TikTok$top_pos, na.rm = TRUE),
Neutre = sum(BD_TikTok$top_neu, na.rm = TRUE),
Négatif = sum(BD_TikTok$top_neg, na.rm = TRUE),
Hostile = sum(BD_TikTok$top_hos, na.rm = TRUE)
)
plot_data <- bind_rows(
tibble(
valence = names(comment_counts),
mesure = "Commentaires",
n = as.numeric(comment_counts)
),
tibble(
valence = names(approval_counts),
mesure = "Approbation secondaire saillante",
n = as.numeric(approval_counts)
)
) %>%
group_by(mesure) %>%
mutate(pct = n / sum(n)) %>%
ungroup() %>%
mutate(
valence = factor(valence, levels = c("Positif", "Neutre", "Négatif", "Hostile")),
mesure = factor(
mesure,
levels = c("Commentaires", "Approbation secondaire saillante")
),
label = paste0(
percent(pct, accuracy = 0.1),
"\n(n = ", format(n, big.mark = " ", scientific = FALSE), ")"
)
)
p <- ggplot(plot_data, aes(x = valence, y = pct, fill = mesure)) +
geom_col(
position = position_dodge(width = 0.72),
width = 0.65
) +
geom_text(
aes(label = label),
position = position_dodge(width = 0.72),
vjust = -0.3,
size = 4.0,
lineheight = 0.9
) +
scale_y_continuous(
labels = percent_format(accuracy = 1),
limits = c(0, 0.62),
expand = expansion(mult = c(0, 0.05))
) +
scale_fill_manual(
values = c(
"Commentaires" = "grey30",
"Approbation secondaire saillante" = "grey70"
)
) +
labs(
x = "Valence",
y = "Proportion",
fill = NULL
) +
theme_minimal(base_size = 14) +
theme(
legend.position = "top",
legend.justification = "left",
panel.grid.minor = element_blank(),
panel.grid.major.x = element_blank(),
axis.title.x = element_text(size = 14, margin = margin(t = 10)),
axis.title.y = element_text(size = 14, margin = margin(r = 10)),
axis.text = element_text(size = 12),
legend.text = element_text(size = 12),
legend.title = element_text(size = 13)
)
print(p)
Note : Cette figure présente une comparaison agrégée à l’échelle de l’ensemble des vidéos publiées par la Sûreté du Québec en 2025. Les proportions de la série « Commentaires » sont calculées à partir de l’ensemble des commentaires de premier niveau codés, tous vidéos confondues. Les proportions de la série « Approbation secondaire saillante » sont calculées à partir de la somme des mentions « j’aime » associées aux trois commentaires les plus appréciés pour chaque vidéo, agrégées selon la valence de ces commentaires. Il s’agit donc d’une comparaison globale de la structure des réactions exprimées et de la structure des réactions les plus valorisées dans l’espace interactionnel.
Objectif : Préparer les variables pour des analyses comparatives plus stables sur le plan distributionnel.
Procédure : Des transformations logarithmiques ont été appliquées aux variables les plus asymétriques, avec ajout d’une constante de 1 lorsque des valeurs nulles étaient possibles.
Règle de décision : Les variables ont été conservées pour l’inférence lorsqu’elles demeuraient interprétables après transformation et que leur structure restait compatible avec une modélisation prudente.
library(dplyr)
BD_TikTok <- BD_TikTok %>%
mutate(
log_views = log(views),
log_like = log(likes),
log_like_rate = log(like_rate),
log_comment = log(total_comments),
log_share = log(shares),
log_share_rate = log(share_rate),
log_comment_rate = log(comment_rate),
log_n_pos = log(n_pos),
log_n_neg = log(n_neg + 1),
log_n_host = log(n_host + 1),
log_top_pos = log(top_pos + 1),
log_top_neg = log(top_neg + 1),
log_top_hos = log(top_hos + 1)
)
Les distributions transformées des variables d’engagement ont été examinées visuellement afin d’évaluer la persistance éventuelle d’asymétries ou de valeurs extrêmes.
library(tidyr)
library(ggplot2)
library(scales)
engagement_vars <- BD_TikTok %>%
select(log_views, log_like, log_like_rate, log_share, log_share_rate, log_comment, log_comment_rate) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value") %>%
mutate(
variable = case_when(
variable == "log_views" ~ "Vues",
variable == "log_like" ~ "Mentions « j’aime »",
variable == "log_like_rate" ~ "Taux de mentions « j’aime »",
variable == "log_share" ~ "Partages",
variable == "log_share_rate" ~ "Taux de partage",
variable == "log_comment" ~ "Commentaires totaux",
variable == "log_comment_rate" ~ "Taux de commentaires",
TRUE ~ variable
)
)
ggplot(engagement_vars, aes(x = value)) +
geom_histogram(bins = 30, fill = "grey40", color = "white") +
facet_wrap(~variable, scales = "free") +
scale_x_continuous(labels = comma) +
labs(
x = "Valeur",
y = "Fréquence"
) +
theme_minimal(base_size = 14) +
theme(
strip.text = element_text(size = 12),
panel.grid.minor = element_blank()
)
Note : Histogrammes des variables d’engagement après transformation logarithmique.
log_vars <- BD_TikTok %>%
select(log_views, log_like, log_like_rate, log_share, log_share_rate, log_comment, log_comment_rate) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value")
ggplot(log_vars, aes(y = value)) +
geom_boxplot() +
facet_wrap(~variable, scales = "free") +
theme_minimal()
Note : Malgré l’application de transformations logarithmiques, certaines valeurs extrêmes persistent dans les distributions. Ces observations ne sont pas considérées comme des erreurs, mais reflètent la nature fortement asymétrique des données issues des plateformes sociales (effets de viralité). Elles ont été conservées dans les analyses afin de préserver la validité écologique des résultats.
Les distributions des variables de valence ont été examinées séparément afin de vérifier si leur forme demeurait compatible avec les analyses comparatives envisagées.
valence_vars <- BD_TikTok %>%
select(log_n_pos, log_n_neg, log_n_host) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value") %>%
mutate(
variable = case_when(
variable == "log_n_pos" ~ "Commentaires positifs",
variable == "log_n_neg" ~ "Commentaires négatifs",
variable == "log_n_host" ~ "Commentaires hostiles",
TRUE ~ variable
)
)
ggplot(valence_vars, aes(x = value)) +
geom_histogram(bins = 30, fill = "grey40", color = "white") +
facet_wrap(~variable, scales = "free") +
scale_x_continuous(labels = comma) +
labs(
x = "Valeur",
y = "Fréquence"
) +
theme_minimal(base_size = 14) +
theme(
strip.text = element_text(size = 12),
panel.grid.minor = element_blank()
)
Note : Les variables de valence représentent le nombre de commentaires de premier niveau positifs, négatifs ou hostiles observés pour chaque vidéo.
log_vars <- BD_TikTok %>%
select(log_n_pos, log_n_neg, log_n_host) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value")
ggplot(log_vars, aes(y = value)) +
geom_boxplot() +
facet_wrap(~variable, scales = "free") +
theme_minimal()
Les variables d’approbation secondaire saillante ont été examinées séparément afin d’évaluer si leur structure permettait leur inclusion dans les modèles inférentiels.
valence_vars <- BD_TikTok %>%
select(log_top_pos, log_top_neg, log_top_hos) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value") %>%
mutate(
variable = case_when(
variable == "log_top_pos" ~ "Approbation secondaire positifs",
variable == "log_top_neg" ~ "Approbation secondaire négatifs",
variable == "log_top_hos" ~ "Approbation secondaire hostiles",
TRUE ~ variable
)
)
ggplot(valence_vars, aes(x = value)) +
geom_histogram(bins = 30, fill = "grey40", color = "white") +
facet_wrap(~variable, scales = "free") +
scale_x_continuous(labels = comma) +
labs(
x = "Valeur",
y = "Fréquence"
) +
theme_minimal(base_size = 14) +
theme(
strip.text = element_text(size = 12),
panel.grid.minor = element_blank()
)
log_vars <- BD_TikTok %>%
select(log_top_pos, log_top_neg, log_top_hos) %>%
pivot_longer(cols = everything(), names_to = "variable", values_to = "value")
ggplot(log_vars, aes(y = value)) +
geom_boxplot() +
facet_wrap(~variable, scales = "free") +
theme_minimal()
Note : Les variables top_*, représentant une mesure d’approbation secondaire saillante, présentent une distribution fortement asymétrique avec une inflation de zéros, persistant après transformation logarithmique. Compte tenu de cette structure, leur inclusion dans des modèles linéaires aurait compromis la robustesse des estimations et la validité des comparaisons. Ces variables ont donc été exclues des analyses inférentielles.
Objectif : Examiner si les indicateurs d’engagement et de valence diffèrent selon les catégories de vidéos.
Procédure : Des modèles de régression linéaire distincts ont été estimés pour chaque variable dépendante retenue, avec Video_category_3 traitée comme facteur catégoriel.
Règle de décision : Les modèles ont été interprétés comme des outils de comparaison entre groupes, sans inférence causale ni finalité prédictive.
BD_TikTok <- BD_TikTok %>%
mutate(Video_category_3 = factor(Video_category_3))
mod_views <- lm(log_views ~ Video_category_3, data = BD_TikTok)
mod_like <- lm(log_like ~ Video_category_3, data = BD_TikTok)
mod_like_rate <- lm(log_like_rate ~ Video_category_3, data = BD_TikTok)
mod_comment <- lm(log_comment ~ Video_category_3, data = BD_TikTok)
mod_comment_rate <- lm(log_comment_rate ~ Video_category_3, data = BD_TikTok)
mod_share <- lm(log_share ~ Video_category_3, data = BD_TikTok)
mod_share_rate <- lm(log_share_rate ~ Video_category_3, data = BD_TikTok)
mod_n_pos <- lm(log_n_pos ~ Video_category_3, data = BD_TikTok)
mod_n_neg <- lm(log_n_neg ~ Video_category_3, data = BD_TikTok)
mod_n_host <- lm(log_n_host ~ Video_category_3, data = BD_TikTok)
models <- list(
views = mod_views,
like = mod_like,
like_rate = mod_like_rate,
comment = mod_comment,
comment_rate = mod_comment_rate,
share = mod_share,
share_rate = mod_share_rate,
pos_comm = mod_n_pos,
neg_comm = mod_n_neg,
host_comm = mod_n_host
)
Objectif :
Vérifier si les modèles retenus satisfont suffisamment les hypothèses
nécessaires à une interprétation prudente.
Procédure : Des tests formels d’hétéroscédasticité et de normalité ont été combinés à une inspection visuelle des graphiques diagnostiques et à un examen des observations influentes.
Règle de décision : En présence d’hétéroscédasticité, des erreurs-types robustes ont été privilégiées. Les observations influentes ont été conservées lorsqu’elles semblaient refléter la variabilité réelle des données plutôt qu’une erreur manifeste.
library(lmtest)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
diagnostic_results <- lapply(names(models), function(name) {
m <- models[[name]]
bp_test <- bptest(m)
sw_test <- shapiro.test(residuals(m))
data.frame(
Variable = name,
BP_p_value = round(bp_test$p.value, 4),
SW_p_value = round(sw_test$p.value, 4),
stringsAsFactors = FALSE
)
})
diagnostic_table <- bind_rows(diagnostic_results)
knitr::kable(diagnostic_table, caption = "Tests de diagnostic des modèles")
| Variable | BP_p_value | SW_p_value | |
|---|---|---|---|
| BP…1 | views | 0.0180 | 0.5593 |
| BP…2 | like | 0.0068 | 0.7692 |
| BP…3 | like_rate | 0.0420 | 0.2762 |
| BP…4 | comment | 0.0002 | 0.1835 |
| BP…5 | comment_rate | 0.0012 | 0.5716 |
| BP…6 | share | 0.1155 | 0.2638 |
| BP…7 | share_rate | 0.4655 | 0.0581 |
| BP…8 | pos_comm | 0.0032 | 0.0246 |
| BP…9 | neg_comm | 0.0033 | 0.5015 |
| BP…10 | host_comm | 0.5028 | 0.0027 |
Note : Les tests de Breusch-Pagan et de Shapiro-Wilk sont rapportés à titre diagnostique. Les résultats ont été interprétés conjointement avec l’inspection visuelle des résidus.
for (name in names(models)) {
m <- models[[name]]
par(mfrow = c(2,2))
plot(m)
mtext(paste("Modèle :", name), outer = TRUE, line = -2, cex = 1.2)
}
library(dplyr)
library(purrr)
##
## Attaching package: 'purrr'
## The following object is masked from 'package:scales':
##
## discard
cooks_table <- map_dfr(names(models), function(name) {
m <- models[[name]]
cooks_d <- cooks.distance(m)
threshold <- 4 / nobs(m)
tibble(
Variable = name,
Max_Cook_D = max(cooks_d, na.rm = TRUE),
Mean_Cook_D = mean(cooks_d, na.rm = TRUE),
Threshold = threshold,
Nb_Outliers = sum(cooks_d > threshold)
)
}) %>%
mutate(
across(where(is.numeric), ~ round(., 4))
)
knitr::kable(
cooks_table,
caption = "Diagnostic des observations influentes (distance de Cook)"
)
| Variable | Max_Cook_D | Mean_Cook_D | Threshold | Nb_Outliers |
|---|---|---|---|---|
| views | 0.1193 | 0.0091 | 0.0339 | 5 |
| like | 0.1048 | 0.0093 | 0.0339 | 6 |
| like_rate | 0.0721 | 0.0093 | 0.0339 | 9 |
| comment | 0.1071 | 0.0096 | 0.0339 | 6 |
| comment_rate | 0.1116 | 0.0098 | 0.0339 | 7 |
| share | 0.1512 | 0.0091 | 0.0339 | 6 |
| share_rate | 0.1536 | 0.0091 | 0.0339 | 7 |
| pos_comm | 0.0607 | 0.0089 | 0.0339 | 3 |
| neg_comm | 0.0942 | 0.0094 | 0.0339 | 7 |
| host_comm | 0.0978 | 0.0090 | 0.0339 | 5 |
Note : Les observations dépassant le seuil conventionnel de 4/n ont été recensées mais conservées, car elles reflètent vraisemblablement la variabilité réelle des données issues des plateformes sociales.
Objectif : Identifier quelles catégories de vidéos diffèrent entre elles pour les variables analysées.
Procédure : Des comparaisons pairwise ont été réalisées à partir des modèles linéaires estimés au moyen de emmeans, avec une matrice de variance-covariance robuste HC3 et un ajustement de Tukey.
Règle de décision : Les contrastes ont été interprétés à partir des p-values ajustées et de leur ampleur relative, exprimée en ratios exponentiés et en pourcentages de variation.
library(emmeans)
## Welcome to emmeans.
## Caution: You lose important information if you filter this package's results.
## See '? untidy'
library(sandwich)
library(dplyr)
library(purrr)
library(knitr)
pairwise_results <- imap(models, function(mod, nom_modele) {
emm <- emmeans(
mod,
specs = ~ Video_category_3,
vcov. = vcovHC(mod, type = "HC3")
)
pairs_emm <- pairs(emm, adjust = "tukey")
as.data.frame(summary(pairs_emm)) %>%
mutate(
modele = nom_modele,
ratio = exp(estimate),
pct_change = (exp(estimate) - 1) * 100,
.before = 1
)
})
pairwise_table <- bind_rows(pairwise_results)
pairwise_formatted <- pairwise_table %>%
mutate(
across(c(estimate, SE, df, t.ratio, ratio, pct_change), ~ round(., 4)),
p.value = ifelse(p.value < .001, "< .001", as.character(round(p.value, 4)))
) %>%
select(modele, contrast, estimate, SE, df, t.ratio, p.value, ratio, pct_change)
knitr::kable(
pairwise_formatted,
caption = "Comparaisons post-hoc (Tukey) avec erreurs-types robustes (HC3)"
)
| modele | contrast | estimate | SE | df | t.ratio | p.value | ratio | pct_change |
|---|---|---|---|---|---|---|---|---|
| views | Video_category_31 - Video_category_32 | 0.5935 | 0.1809 | 115 | 3.2800 | 0.0039 | 1.8102 | 81.0230 |
| views | Video_category_31 - Video_category_33 | 0.7647 | 0.2299 | 115 | 3.3268 | 0.0034 | 2.1483 | 114.8299 |
| views | Video_category_32 - Video_category_33 | 0.1712 | 0.2583 | 115 | 0.6630 | 0.7854 | 1.1868 | 18.6755 |
| like | Video_category_31 - Video_category_32 | 0.7524 | 0.1992 | 115 | 3.7767 | < .001 | 2.1221 | 112.2064 |
| like | Video_category_31 - Video_category_33 | 0.7621 | 0.2646 | 115 | 2.8802 | 0.0131 | 2.1428 | 114.2830 |
| like | Video_category_32 - Video_category_33 | 0.0097 | 0.2958 | 115 | 0.0329 | 0.9994 | 1.0098 | 0.9786 |
| like_rate | Video_category_31 - Video_category_32 | 0.1589 | 0.0561 | 115 | 2.8347 | 0.0149 | 1.1723 | 17.2262 |
| like_rate | Video_category_31 - Video_category_33 | -0.0025 | 0.0767 | 115 | -0.0332 | 0.9994 | 0.9975 | -0.2546 |
| like_rate | Video_category_32 - Video_category_33 | -0.1615 | 0.0833 | 115 | -1.9387 | 0.1325 | 0.8509 | -14.9120 |
| comment | Video_category_31 - Video_category_32 | 0.7546 | 0.2161 | 115 | 3.4914 | 0.002 | 2.1267 | 112.6716 |
| comment | Video_category_31 - Video_category_33 | 0.8895 | 0.3190 | 115 | 2.7886 | 0.0169 | 2.4340 | 143.3985 |
| comment | Video_category_32 - Video_category_33 | 0.1350 | 0.3488 | 115 | 0.3869 | 0.9209 | 1.1445 | 14.4480 |
| comment_rate | Video_category_31 - Video_category_32 | 0.1611 | 0.0922 | 115 | 1.7467 | 0.1924 | 1.1748 | 17.4832 |
| comment_rate | Video_category_31 - Video_category_33 | 0.1249 | 0.1437 | 115 | 0.8688 | 0.661 | 1.1330 | 13.2982 |
| comment_rate | Video_category_32 - Video_category_33 | -0.0363 | 0.1539 | 115 | -0.2357 | 0.9699 | 0.9644 | -3.5622 |
| share | Video_category_31 - Video_category_32 | 0.3326 | 0.3055 | 115 | 1.0887 | 0.523 | 1.3946 | 39.4562 |
| share | Video_category_31 - Video_category_33 | 0.7463 | 0.4014 | 115 | 1.8591 | 0.1554 | 2.1092 | 110.9250 |
| share | Video_category_32 - Video_category_33 | 0.4138 | 0.4359 | 115 | 0.9493 | 0.6103 | 1.5125 | 51.2481 |
| share_rate | Video_category_31 - Video_category_32 | -0.2609 | 0.1780 | 115 | -1.4659 | 0.3111 | 0.7704 | -22.9621 |
| share_rate | Video_category_31 - Video_category_33 | -0.0183 | 0.2328 | 115 | -0.0788 | 0.9966 | 0.9818 | -1.8177 |
| share_rate | Video_category_32 - Video_category_33 | 0.2425 | 0.2453 | 115 | 0.9886 | 0.5856 | 1.2745 | 27.4468 |
| pos_comm | Video_category_31 - Video_category_32 | 0.6568 | 0.2017 | 115 | 3.2567 | 0.0042 | 1.9287 | 92.8673 |
| pos_comm | Video_category_31 - Video_category_33 | 0.4031 | 0.2439 | 115 | 1.6524 | 0.2281 | 1.4965 | 49.6454 |
| pos_comm | Video_category_32 - Video_category_33 | -0.2537 | 0.2733 | 115 | -0.9285 | 0.6235 | 0.7759 | -22.4102 |
| neg_comm | Video_category_31 - Video_category_32 | 0.5815 | 0.2092 | 115 | 2.7803 | 0.0173 | 1.7887 | 78.8713 |
| neg_comm | Video_category_31 - Video_category_33 | 0.9229 | 0.2897 | 115 | 3.1858 | 0.0052 | 2.5166 | 151.6607 |
| neg_comm | Video_category_32 - Video_category_33 | 0.3414 | 0.3188 | 115 | 1.0710 | 0.5339 | 1.4069 | 40.6937 |
| host_comm | Video_category_31 - Video_category_32 | 0.5532 | 0.2066 | 115 | 2.6774 | 0.023 | 1.7388 | 73.8751 |
| host_comm | Video_category_31 - Video_category_33 | 0.6146 | 0.2652 | 115 | 2.3174 | 0.0574 | 1.8490 | 84.8972 |
| host_comm | Video_category_32 - Video_category_33 | 0.0615 | 0.2755 | 115 | 0.2231 | 0.9729 | 1.0634 | 6.3391 |