Nous étudions des données issues de pages Facebook de ventes d’articles de modes et de cosmétiques. Le tableau de données contient une ligne par post qui peuvent être de différents types (vidéos, photos, status et liens). Les données sont téléchargeables sur le site UCI Machine Learning repository. Les variables que nous allons étudier sont :
status_type
: le type du post, variable qualitative ayant 4 valeurs possibles (link
,video
,status
,photo
),num_reactions
: nombre de réactions (J’aime, J’adore, Wouah, Haha, Triste, Grrr),num_comments
: nombre de commentaires,num_shares
: nombre de partages,num_likes
: nombre de J’aime,num_loves
: nombre J’adore,num_wows
: nombre de Wouah,num_hahas
: nombre de Haha,num_sads
: nombre de Triste,num_angrys
: nombre de Grrr.library("readr")
Live <- read_csv("Live.csv")
##
## ── Column specification ────────────────────────────────────────────────────────
## cols(
## status_id = col_character(),
## status_type = col_character(),
## status_published = col_character(),
## num_reactions = col_double(),
## num_comments = col_double(),
## num_shares = col_double(),
## num_likes = col_double(),
## num_loves = col_double(),
## num_wows = col_double(),
## num_hahas = col_double(),
## num_sads = col_double(),
## num_angrys = col_double(),
## Column1 = col_logical(),
## Column2 = col_logical(),
## Column3 = col_logical(),
## Column4 = col_logical()
## )
Live <- Live[,c(2,4:12)]
Live[,1] <- factor(Live$status_type)
summary(Live)
## status_type num_reactions num_comments num_shares
## link : 63 Min. : 0.0 Min. : 0.0 Min. : 0.00
## photo :4288 1st Qu.: 17.0 1st Qu.: 0.0 1st Qu.: 0.00
## status: 365 Median : 59.5 Median : 4.0 Median : 0.00
## video :2334 Mean : 230.1 Mean : 224.4 Mean : 40.02
## 3rd Qu.: 219.0 3rd Qu.: 23.0 3rd Qu.: 4.00
## Max. :4710.0 Max. :20990.0 Max. :3424.00
## num_likes num_loves num_wows num_hahas
## Min. : 0.0 Min. : 0.00 Min. : 0.000 Min. : 0.0000
## 1st Qu.: 17.0 1st Qu.: 0.00 1st Qu.: 0.000 1st Qu.: 0.0000
## Median : 58.0 Median : 0.00 Median : 0.000 Median : 0.0000
## Mean : 215.0 Mean : 12.73 Mean : 1.289 Mean : 0.6965
## 3rd Qu.: 184.8 3rd Qu.: 3.00 3rd Qu.: 0.000 3rd Qu.: 0.0000
## Max. :4710.0 Max. :657.00 Max. :278.000 Max. :157.0000
## num_sads num_angrys
## Min. : 0.0000 Min. : 0.0000
## 1st Qu.: 0.0000 1st Qu.: 0.0000
## Median : 0.0000 Median : 0.0000
## Mean : 0.2437 Mean : 0.1132
## 3rd Qu.: 0.0000 3rd Qu.: 0.0000
## Max. :51.0000 Max. :31.0000
Nous observons que le jeu de données ne contient pas de valeurs manquantes. Le minimum, ainsi que, pour certaines variables le 1er quartile voire la médiane et le 3ème quartile, est à 0 pour toutes les variables suggérant que certains posts ne suscitent aucune réaction ou aucun commentaire ou aucun partage. Les données ne peuvent pas être gaussiennes.
library("FactoMineR")
res.ACP <- PCA(Live,quali.sup=1,quanti.sup=2,ncp=10)
Nous représentons tout d’abord les valeurs propres
res.ACP$eig
## eigenvalue percentage of variance cumulative percentage of variance
## comp 1 3.2219706 40.274632 40.27463
## comp 2 1.0424926 13.031157 53.30579
## comp 3 0.9091640 11.364550 64.67034
## comp 4 0.8337559 10.421948 75.09229
## comp 5 0.7734797 9.668497 84.76078
## comp 6 0.6897911 8.622389 93.38317
## comp 7 0.3802242 4.752802 98.13598
## comp 8 0.1491220 1.864025 100.00000
barplot(res.ACP$eig[,1])
Nous observons que la plus grande part d’inertie est portée par le premier axe. Les axes 2 à 6 portent chacun entre 9% et 13% de l’inertie totale donc peuvent être intéressants à garder dans l’analyse si nous pouvons les interpréter.
plot(res.ACP,choix="var")
Nous observons que toutes les variables sont corrélées positivement à l’axe 1. L’axe 2 semble opposer des individus qui ont suscité plus de J’aime et de réactions et moins de Tristes que la moyenne à des individus.
plot(res.ACP,choix="ind",habillage=1,select="contrib 10")
Nous observons que les individus ayant les coordonnées les plus élevées et les plus contributifs sur l’axe 1 sont des posts de type vidéo. Les individus ayant les coordonnées les plus élevées sur l’axe 2 sont plutôt de type photo.
L’axe 1 semble opposer les posts ayant suscité le plus de réactions à ceux n’ayant pas ou peu suscité de réaction. Pour confirmer cela nous pouvons comparer les observations des individus les plus remarquables sur l’axe 1 et comparer aux données statistique des variables (moyenne, médiane et quartiles) de tous les individus calculés par la fonction summary()
.
tri1 = sort.int(res.ACP$ind$coord[,1],index.return = T,decreasing = T)
data.frame(Live[tri1$ix[1:5],])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 video 2639 1625 675 1753 657
## 2 video 1970 2903 3424 1330 482
## 3 video 2399 2458 1430 1643 529
## 4 video 1758 1890 718 1181 385
## 5 video 2237 2571 815 1591 376
## num_wows num_hahas num_sads num_angrys
## 1 68 157 0 4
## 2 138 13 5 2
## 3 206 15 3 3
## 4 89 100 2 1
## 5 252 15 1 2
L’observation du nuage des individus nous indique également que le type ‘video’ semble susciter plus de réactions que la moyenne.
print('type video')
## [1] "type video"
colMeans(Live[which(Live$status_type=="video"),2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 283.4095973 642.4781491 115.6799486 243.0154242 35.5402742
## num_wows num_hahas num_sads num_angrys
## 2.4481577 1.7352185 0.4138817 0.2540703
print('moyenne globale')
## [1] "moyenne globale"
colMeans(Live[,2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 230.1171631 224.3560284 40.0225532 215.0431206 12.7286525
## num_wows num_hahas num_sads num_angrys
## 1.2893617 0.6964539 0.2436879 0.1131915
A première vue l’axe 2 semble plus difficile à interpréter que l’axe 1. Nous pouvons observer la description automatique des axes à l’aide de la fonction dimdesc()
.
desc.axes = dimdesc(res.ACP,axes=1:6)
desc.axes$Dim.2
## $quanti
## correlation p.value
## num_likes 0.64595013 0.000000e+00
## num_reactions 0.63913572 0.000000e+00
## num_wows 0.46553776 0.000000e+00
## num_loves 0.05178638 1.359180e-05
## num_hahas 0.03174047 7.692773e-03
## num_shares -0.06937720 5.503022e-09
## num_angrys -0.11539402 2.484129e-22
## num_comments -0.34253982 2.691800e-193
## num_sads -0.51900269 0.000000e+00
##
## $quali
## R2 p.value
## status_type 0.01361524 8.369041e-21
##
## $category
## Estimate p.value
## status_type=status 0.1983384 3.543176e-11
## status_type=link 0.1893489 8.862610e-03
## status_type=photo -0.1061315 4.767902e-05
## status_type=video -0.2815558 3.563068e-15
##
## attr(,"class")
## [1] "condes" "list"
Les posts ayant des coordonnées positives sur l’axe 2 sont ceux ayant tendance à avoir plus de réactions que la moyenne, en particulier de type J’aime, Wouah, J’adore, et Haha et moins de réaction de type triste ou Grr, de commentaires et de partage (même si la corrélation avec le nombre de partages et le nombre de J’adore et de Haha est très faible). L’axe 2 semble donc opposer des posts ayant généré des réactions positives (ayant des coordonnées positives sur cet axe) à ceux ayant des coordonnées négatives. Il semblerait que les posts de type status ou lien aient tendance à avoir des coordonnées positives sur cet axe et que les photos et les vidéos plutôt des coordonnées négatives (ce n’est pas très visible sur le nuage des individus). Ceci dit cette tendance n’est pas confirmée par l’analyse des moyennes des variables ci-dessous et nous ne la retiendrons pas.
print('video')
## [1] "video"
colMeans(Live[which(Live$status_type=="video"),2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 283.4095973 642.4781491 115.6799486 243.0154242 35.5402742
## num_wows num_hahas num_sads num_angrys
## 2.4481577 1.7352185 0.4138817 0.2540703
print('photo')
## [1] "photo"
colMeans(Live[which(Live$status_type=="photo"),2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 181.29034515 15.99347015 2.55387127 178.77845149 1.44519590
## num_wows num_hahas num_sads num_angrys
## 0.68470149 0.19076493 0.14249067 0.04570896
print('link')
## [1] "link"
colMeans(Live[which(Live$status_type=="link"),2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 370.14285714 5.69841270 4.39682540 369.61904762 0.30158730
## num_wows num_hahas num_sads num_angrys
## 0.19047619 0.03174603 0.00000000 0.00000000
print('status')
## [1] "status"
colMeans(Live[which(Live$status_type=="status"),2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 438.78356164 36.23835616 2.55890411 435.52876712 1.56164384
## num_wows num_hahas num_sads num_angrys
## 1.17260274 0.10958904 0.38630137 0.02465753
print("Moyenne")
## [1] "Moyenne"
colMeans(Live[,2:10])
## num_reactions num_comments num_shares num_likes num_loves
## 230.1171631 224.3560284 40.0225532 215.0431206 12.7286525
## num_wows num_hahas num_sads num_angrys
## 1.2893617 0.6964539 0.2436879 0.1131915
Nous observons un groupe d’individu ayant des coordonnées plus importantes que les autres sur l’axe 1 et sur l’axe 2. L’analyse de ces individus remarquables peut aider par exemple à déterminer des caractéristiques communes aux posts les plus partagés et remarqués (dans l’objectif de faire de la plublicité sur un produit par exemple).
# Individu ayant la coordonnée la plus élevée sur l'axe 1
data.frame(Live[which.max(res.ACP$ind$coord[,1]),])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 video 2639 1625 675 1753 657
## num_wows num_hahas num_sads num_angrys
## 1 68 157 0 4
# Il s'agit d'un post ayant suscité un nombre important de réactions, de commentaires et de partages. Il a notamment suscité le plus de réaction de type *Haha* et *J'adore* et aucune réaction *Triste*.
# Individu ayant la coordonnée la plus élevée sur l'axe 2
data.frame(Live[which.max(res.ACP$ind$coord[,2]),])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 video 1678 1499 685 1227 165
## num_wows num_hahas num_sads num_angrys
## 1 278 8 0 0
# Il s'agit d'un post ayant suscité un nombre important de réactions, de commentaires et de partages. Il a notamment suscité le plus de réaction de type *Wouah* aucune réaction *Triste* ou *Grr*.
# Individu ayant la coordonnée la moins élevée sur l'axe 2
data.frame(Live[which.min(res.ACP$ind$coord[,2]),])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 photo 295 3 10 243 1
## num_wows num_hahas num_sads num_angrys
## 1 0 0 51 0
# Il s'agit d'un post ayant suscité un nombre relativement important de réactions, peu de commentaires et de partages. C'est le post qui a suscité le plus de réaction de type *Triste*.
plot(res.ACP,choix="var",axes=c(3,4))
Au vu du cercle des corrélations, l’axe 3 semble corrélé positivement en particulier avec les variables num_likes
, num_sads
et num_reactions
. L’axe 4 avec la variable num_angrys
.
plot(res.ACP,axes=c(3,4),select="contrib 10",habillage = 1)
Les individus les plus contributifs sur ces deux axes sont plutôt des photos. La plupart des individus sont assez centraux. Nous allons analyser plus particulièrement les individus ayant les coordonnées les plus élevées.
desc.axes$Dim.3
## $quanti
## correlation p.value
## num_sads 0.69631467 0.000000e+00
## num_likes 0.59199713 0.000000e+00
## num_reactions 0.56360026 0.000000e+00
## num_comments -0.04957078 3.127246e-05
## num_wows -0.07133358 2.021752e-09
## num_loves -0.12964520 8.304035e-28
## num_shares -0.14154732 7.064047e-33
## num_hahas -0.17028366 5.137158e-47
##
## $quali
## R2 p.value
## status_type 0.01985001 2.00204e-30
##
## $category
## Estimate p.value
## status_type=status 0.3312680 1.131077e-23
## status_type=photo -0.1321370 1.409001e-02
## status_type=video -0.2778798 1.900577e-14
##
## attr(,"class")
## [1] "condes" "list"
desc.axes$Dim.4
## $quanti
## correlation p.value
## num_angrys 0.84348023 0.000000e+00
## num_wows 0.05334512 7.412678e-06
## num_loves -0.02788457 1.921426e-02
## num_sads -0.03193281 7.330961e-03
## num_reactions -0.07476002 3.281620e-10
## num_likes -0.07601445 1.652208e-10
## num_hahas -0.08390696 1.708919e-12
## num_shares -0.14588532 7.719046e-35
## num_comments -0.28905518 9.610029e-136
##
## $quali
## R2 p.value
## status_type 0.006907891 1.407183e-10
##
## $category
## Estimate p.value
## status_type=photo 0.08320988 1.179854e-11
## status_type=video -0.08018494 1.420627e-11
##
## attr(,"class")
## [1] "condes" "list"
Trois individus se dégagent en particulier.
tri3 = sort.int(res.ACP$ind$coord[,3],decreasing = T,index.return = T)
data.frame(Live[tri3$ix[1:3],])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 photo 295 3 10 243 1
## 2 photo 336 42 2 285 5
## 3 photo 336 42 2 285 5
## num_wows num_hahas num_sads num_angrys
## 1 0 0 51 0
## 2 0 0 46 0
## 3 0 0 46 0
Il s’agit d’individus qui ont suscité un nombre relativement élevé de réactions (un peu plus élevé que la moyenne), relativement peu de commentaires mais un nombre élevé (proche ou égal au maximum de réactions tristes).
Cinq individus se dégagent en particulier.
tri4 = sort.int(res.ACP$ind$coord[,4],decreasing = T,index.return = T)
data.frame(Live[tri4$ix[1:4],])
## status_type num_reactions num_comments num_shares num_likes num_loves
## 1 photo 215 44 0 176 1
## 2 photo 251 29 5 228 0
## 3 photo 251 29 5 228 0
## 4 photo 287 38 2 260 0
## num_wows num_hahas num_sads num_angrys
## 1 3 4 0 31
## 2 3 0 1 19
## 3 3 0 1 19
## 4 12 2 1 12
On repère bien ici les individus qui ont suscité des réactions tristes.
res.ACP <- PCA(Live,quali.sup=1,quanti.sup=2,graph=FALSE,ncp=10)
plot(res.ACP,choix="var",axes=c(5,6))
plot(res.ACP,axes=c(5,6),select="contrib 10",habillage = 1)
desc.axes$Dim.5
## $quanti
## correlation p.value
## num_wows 0.51259605 0.000000e+00
## num_sads 0.35893141 2.198026e-213
## num_hahas 0.24020731 4.362536e-93
## num_loves 0.02441876 4.034046e-02
## num_shares -0.14901787 2.711434e-36
## num_angrys -0.18279282 5.045841e-54
## num_reactions -0.32246522 2.691196e-170
## num_likes -0.34711291 8.832132e-199
## num_comments -0.38404494 1.503855e-246
##
## $quali
## R2 p.value
## status_type 0.01795084 1.744607e-27
##
## $category
## Estimate p.value
## status_type=photo 0.15617955 1.813664e-28
## status_type=video -0.09548691 8.032696e-27
##
## attr(,"class")
## [1] "condes" "list"
desc.axes$Dim.6
## $quanti
## correlation p.value
## num_hahas 0.71438615 0.000000e+00
## num_likes 0.12738854 6.751855e-27
## num_reactions 0.11679685 7.668540e-23
## num_angrys 0.03728601 1.740777e-03
## num_sads -0.02922030 1.414536e-02
## num_loves -0.07885634 3.350788e-11
## num_comments -0.08271722 3.501139e-12
## num_shares -0.19708066 1.128469e-62
## num_wows -0.33025804 5.089573e-179
##
## $quali
## R2 p.value
## status_type 0.001927471 0.00351157
##
## $category
## Estimate p.value
## status_type=photo -0.005364373 0.0080623204
## status_type=video -0.076369191 0.0003778104
##
## attr(,"class")
## [1] "condes" "list"
Il semblerait que l’axe 5 soit plutôt corrélé aux réactions de type Wouah et l’axe 6 aux réactions de type Haha.
L’analyse du jeu de données à montré que les données sont très hétérogènes : la plus grande partie des posts suscite assez peu de réactions, commentaires et partages. L’analyse des résultats de l’ACP nous permet de repérer les individus les plus marquants et certaines caractéristiques qui se dégagent. Nous pouvons par exemple remarquer que les posts qui générent globalement plus de réactions, commentaires et partages sont des vidéos. L’analyse de l’axe 2 nous permet de différencier les posts qui génèrent plutôt des réactions positives (J’aime, Wouah, J’adore, et Haha) et ceux qui génèrent plutôt des réactions négatives. Les autres axes semblent plutôt liés au nombre de réactions de tristesse (axe 3), de colère (axe 4), d’étonnement (axe 5) ou de rire (axe 6). Les individus les plus marquants sur les axes 3 et 4 sont plutôt des photos.
Investigate
)library("FactoInvestigate")
Investigate(res.ACP)
## -- création du fichier .Rmd (temps écoulé : 0s) --
##
## -- détection d'individus singuliers (temps écoulé : 0.09s) --
## 0 anomalie(s) éliminée(s)
##
## -- analyse de l'inertie (temps écoulé : 0.59s) --
## 2 composante(s) porteuse(s) d'information : inertie totale de 53.3%
##
## -- description des composantes (temps écoulé : 12.36s) --
## plan 1:2
##
## -- classification (temps écoulé : 17.64s) --
## 3 classes
##
## -- rédaction des annexes (temps écoulé : 35.32s) --
##
## -- sauvegarde des données (temps écoulé : 37.74s) --
##
## -- compilation des documents (temps écoulé : 37.74s) --
## -- tâche terminée (temps écoulé : 65.34s) --
## Cette interprétation des résultats a été réalisée de façon automatique,
## elle ne peut en aucun cas égaler la qualité d'une interprétation personnalisée