Pour ce projet, l’objectif était de mettre en pratique des différentes méthodes d’apprentissage statistique pour l’IA vue en cours. J’ai réutilisé les mêmes données que pour la SAE du semestre précédent. À savoir, un jeu de données sur les statistiques des joueurs de hockey sur glace de la NHL.
Le hockey sur glace est un sport de contact pratiqué sur une patinoire. Il est très populaire dans les pays nordiques tels que le Canada, les États-Unis, la Suède, la Finlande et la Russie, mais il est également joué dans de nombreux autres pays du monde. Ce sport implique deux équipes qui se disputent un palet avec des bâtons de hockey pour marquer des points en envoyant le palet dans le but adverse. Le hockey sur glace est connu pour sa vitesse, son intensité et sa brutalité, ce qui en fait l’un des sports les plus excitants et les plus regardés au monde.
La Ligue nationale de hockey, également connue sous le nom de NHL, est une ligue professionnelle de hockey sur glace en Amérique du Nord. C’est sur cette ligue que va porter notre classification.
La NHL se déroule en deux phases, la phase régulière et les playoffs seulement accessible pour les 16 meilleures équipes de la phase régulières. Lors de cette étude, je vais me concentrer sur la phase régulière de la NHL pour les saison entre 2004 et 2017.J’ai réparti mon jeu de données en deux catégories les défenseurs,D, et les attaquants où j’ai regroupé les centres, et les ailiers droits et gauches, A. L’objectif, va être de prédire si le poste du joueur. On va commencer par voir la méthode de K plus proches, voisins puis celles des arbres de décision et de random Forest, ensuite, on verra l’ADL et SVD et on finira par la régression logistique.
set.seed(2024)
library(DBI)
con =dbConnect(RPostgreSQL::PostgreSQL(),dbname="iut2202698")
query=' SELECT *
FROM "public"."nhl";'
Y <- dbGetQuery(con,query)
rownames(Y)=Y[,1]
Z=Y[,-1]
dim(Z)
## [1] 13186 31
head(Z)
## Rk Player Age Pos Tm GP G A PTS plusminus PIM PS EV PP SH GW
## 1 1 Connor McDavid 20 C EDM 82 30 70 100 27 26 12.8 26 3 1 6
## 2 2 Sidney Crosby 29 C PIT 75 44 45 89 17 24 12.3 30 14 0 5
## 3 3 Patrick Kane 28 RW CHI 82 34 55 89 11 32 10.8 27 7 0 5
## 4 4 Nicklas Backstrom 29 C WSH 82 23 63 86 17 38 9.9 15 8 0 5
## 5 5 Nikita Kucherov 23 RW TBL 74 40 45 85 13 38 12.0 23 17 0 7
## 6 6 Brad Marchand 28 LW BOS 80 39 46 85 18 81 12.6 27 9 3 8
## EV.1 PP.1 SH.1 S S_percent TOI ATOI BLK HIT FOW FOL FO_percent HART
## 1 45 24 1 251 12.0 1733 21.13333 29 34 348 458 43.2 1
## 2 34 11 0 255 17.3 1491 19.88333 27 80 842 906 48.2 0
## 3 39 16 0 292 11.6 1754 21.40000 15 28 7 44 13.7 0
## 4 36 27 0 162 14.2 1497 18.26667 33 45 685 648 51.4 0
## 5 30 15 0 246 16.3 1438 19.43333 20 30 0 0 0.0 0
## 6 29 15 2 226 17.3 1555 19.43333 35 51 13 23 36.1 0
## Votes Season
## 1 1604 2017
## 2 1104 2017
## 3 206 2017
## 4 60 2017
## 5 119 2017
## 6 184 2017
Z = Z[c(-2,-5,-31)]
Z=na.omit(Z)
Z$Pos = ifelse(Z$Pos %in% c('C', 'RW','LW'), "A", "D")
X=Z[c(2,4:26)]
Y=as.factor(Z[,3])
dim(X)
## [1] 12768 24
table(Y)
## Y
## A D
## 8552 4216
#Valeur Manquante
table(is.na(X))
##
## FALSE
## 306432
Je n’ai pas de valeur manquante, on va donc pouvoir poursuivre sans modifier le jeu de données.
La méthode K plus proches voisins (KNN) est une technique simple d’apprentissage automatique utilisée pour la classification et la régression.
En classification, KNN cherche les “K” voisins les plus proches d’un point de données inconnu en se basant sur une mesure de similarité, comme la distance euclidienne. Une fois les voisins identifiés, la classe du point inconnu est déterminée en fonction de la classe majoritaire parmi ces voisins.calcul=function(K=5){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
library(class)
Y_predit = knn(train=X_train, test=X_test, cl=Y_train) # pas de modèle dans les knn
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip()+
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 6%, ce qui signifie que le modele a une performance élevé dans la predictions des joueurs de hockey. Un F-score de 0,91 Pour les défenseurs indique une très bonne capacité du modèle à les identifier correctement. Pour les attaquants, un F-score de 0,95 indique une performance encore meilleure dans leur identification. En résumé, le modèle KNN semble être performant dans la classification des joueurs de hockey en attaquants et en défenseurs, avec un taux d’erreur bas et des F-scores élevés pour les deux classes.
Les arbres de décision sont une méthode d’analyse et de prise de décision utilisée en apprentissage automatique et en sciences de données. Ils sont basés sur une représentation arborescente des décisions et de leurs conséquences.
calcul=function(K=5){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
library(rpart)
model = rpart(Y_train~.,data=data.frame(X_train),method="class")
predictions=predict(model,data.frame(X_test),type="class")
Y_predit=predictions
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
RES_arbre = mean(RES[[1]])
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 8,5%, ce qui signifie que le modele est plutot précis dans ces prédictions. Un F-score de 0,87 Pour les défenseurs indique une bonne capacité du modèle à les identifier correctement. Pour les attaquants, un F-score de 0,93 indique une performance encore meilleure dans leur identification. En résumé, ces résultats suggèrent que le modèle d’arbre de décision est assez fiable pour prédire si un joueur de hockey est un attaquant ou un défenseur. Il est légèrement plus performant dans la prédiction des attaquants par rapport aux défenseurs, mais dans l’ensemble, il offre une bonne précision avec un faible taux d’erreur.
La méthode Random Forest est une technique d’apprentissage automatique utilisée pour résoudre des problèmes de classification et de régression. Elle fonctionne en combinant les prédictions de plusieurs arbres de décision individuels pour obtenir une prédiction plus robuste et précise.
calcul=function(K=4){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
library(randomForest)
model=randomForest(X_train, Y_train)
Y_predit=predict(model, X_test)
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 2,25%, ce qui signifie que le modele a une performance élevé dans la predictions des joueurs de hockey. Un F-score de 0,965 Pour les défenseurs et 0,98 pour les attaquants ce qui indique une très bonne performance du modèle. En conclusion, ces résultats suggèrent que le modèle Random Forest est capable de distinguer avec une grande précision les attaquants des défenseurs dans une équipe de hockey, avec une faible marge d’erreur.
La méthode ADL, ou Analyse Discriminante Linéaire, est une technique statistique utilisée pour trouver une combinaison linéaire des caractéristiques (ou variables) qui permet de mieux discriminer entre deux ou plusieurs groupes ou classes prédéfinis. L’objectif principal de l’ADL est de maximiser la séparation entre ces groupes.
calcul=function(K=5){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
library(MASS)
model=lda(X_train,Y_train)
predictions=predict(model,data.frame(X_test),type="class")
Y_predit=predictions$class
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip()+
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 5%, ce qui signifie que le modele arrive généralement à prédire le poste du joueur. Un F-score de 0,91 Pour les défenseurs indique une très bonne capacité du modèle à les identifier correctement. Pour les attaquants, un F-score de 0,965 indique une performance encore meilleure dans leur identification. En résumé, ces résultats suggèrent que le modèle ADL est efficace pour prédire si un joueur de hockey est un attaquant ou un défenseur. Il est légèrement plus performant dans la prédiction des attaquants par rapport aux défenseurs,cependant il offre une bonne précision avec un F-score superieur à 0,9 pour les attaquants et les defenseurs ainsi qu’un faible taux d’erreur.
La méthode de décomposition en valeurs singulières (SVD) est une technique mathématique utilisée pour analyser et représenter des données sous forme de combinaison de motifs significatifs. En gros, SVD prend une grande matrice de données et la décompose en matrices plus petites.
calcul=function(K=5){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
library(e1071)
model = svm(X_train, Y_train,probability = TRUE)
Y_predit = predict(model, X_test, probability = FALSE)
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip()+
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 3,5%, ce qui signifie que le modele a une performance élevé dans la predictions des joueurs de hockey. Un F-score de 0,945 Pour les défenseurs indique une très bonne capacité du modèle à les identifier correctement. Pour les attaquants, un F-score de 0,975 indique une performance encore meilleure dans leur identification. Cela suggère que votre modèle est généralement très bon pour distinguer les attaquants et les défenseurs, mais il est peut-être légèrement plus précis dans la prédiction des attaquants. Cela pourrait être dû à plusieurs facteurs, tels que des différences dans les caractéristiques des deux types de joueurs ou des déséquilibres dans les données d’entraînement.
La régression logistique est une méthode statistique utilisée pour prédire une variable binaire en fonction de variables indépendantes. Elle est souvent utilisée lorsque la variable à prédire ne peut prendre que deux valeurs possibles
calcul=function(K=5){
F_score=function(){
res=rep(0,nlevels(Y_train))
w=table(Y_predit,Y_test)
for (k in 1:nlevels(Y_train)){
TP=w[k,k]
FP=sum(w[k,-k])
FN=sum(w[-k,k])
res[k]=(2*TP) / (2*TP + FP +FN)
}
return(res)
}
RES_error=NULL
RES_F_score=NULL
ech=sample(1:K,nrow(X),replace = T)
for (iter in 1:K){
res_1_bloc=NULL
###
X_train=X[ech != iter,]
Y_train=Y[ech != iter]
X_test=X[ech == iter,]
Y_test=Y[ech == iter]
if (nlevels(Y_train)==2){
model = glm(Y_train~., family=binomial(link="logit"),data=as.data.frame(X_train))
p=predict.glm(model,X_test,type="response")
Y_predit=as.factor(p>0.5)
levels(Y_predit)=levels(Y_test)
w=table(Y_predit,Y_test)
TauxErreurGlobale = 1-sum(diag(w))/sum(w)
RES_error=c(RES_error,TauxErreurGlobale)
RES_F_score=rbind(RES_F_score,F_score())
}
}
return(list(RES_error,RES_F_score))
}
graph_erreur=function(){
library(ggplot2)
erreur=c(RES[[1]])
methode=rep("1.arbre",each=length(RES[[1]]))
df=data.frame(methode, erreur)
ggplot(df, aes(x=methode, y=erreur)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip()+
ggtitle("Taux d'erreur")
}
graph_F_score=function(){
library(ggplot2)
F_score=c(RES[[2]])
modalite=rep(levels(Y),each=nrow(RES[[2]]))
df=data.frame(modalite, F_score)
ggplot(df, aes(x=modalite, y=F_score)) +
stat_boxplot(geom = "errorbar",
width = 0.25) +
geom_boxplot() +
coord_flip() +
ggtitle("F-score par modalité")
}
RES=calcul(10)
graph_erreur()
graph_F_score()
Avec la méthode des arbres de décision, on a un taux d’erreur de seulement 2%, ce qui signifie que le modele a une performance élevé dans la predictions des joueurs de hockey. Un F-score de 0,97 Pour les défenseurs et 0,985 pour les attaquants ce qui indique une très bonne performance du modèle. En interprétant ces résultats, on peut conclure que le modèle de régression logistique est très efficace pour distinguer les attaquants des défenseurs dans le hockey. La faible erreur médiane et les F-scores élevés indiquent que le modèle est robuste et précis dans ses prédictions.
En conclusion, toutes les différentes méthodes d’apprentissage statistique pour l’IA ont donné de bons résultats, avec un taux d’erreur de 8,5 % et un F-score inferieur à 0,9, la méthode des arbres de décisions était la moins performante. Au contraire, avec 2 % de taux d’erreur et des F-scores superieur à 0,95 la méthode de régression logistique est la meilleure méthode tester dans le projet. Vu la qualité de mes résultats, je peux aussi conclure qu’il est facile de faire la différence entre le poste d’attaquant et celui de défenseur en NHL. En mettant en lumière les variables clés qui les sépare cela pourrait permettre de faciliter le recrutement des différents entraîneurs et des différentes franchises.