Quand les étudiants rédigent des comptes-rendus : grande est la tentation pour eux (parfois) de pomper sur un travail rédigé par un copain d'un autre groupe ou par étudiant de l'année d'avant (un parrain).
Comment détecter cela ? Si tous les documents sont rangés dans des dossiers année par année, rien de plus simple. Une analyse textmining avec quanteda peut mesurer la parenté entre les devoirs grâce à l'indice de similarité.
install.packages("readtext")
install.packages("quanteda")
install.packages("quanteda.textmodels")
install.packages("quanteda.textstats")
install.packages("quanteda.textplots")
install.packages("ftrCOOL")
library("readtext") # Ouverture de plusieurs documents de tous les types
library(quanteda) # textmining
quanteda_options(language_stemmer = "french")
library(quanteda.textmodels) # A installer si nécessaire.
library(quanteda.textmodels)
library("quanteda.textstats")
library("quanteda.textplots")
library("ftrCOOL")
library(stringr)
library(textclean)
########################
Charger le dossier général qui contient toutes les copies dans des sous-dossiers :
setwd("C:/Rendus/Rendus") # Dossier qui contient tous les fichiers
Charger tous les pdf, mais aussi ceux dans des zips de tous les dossiers et sous dossiers :
liste_de_fichiers <- c(list.files(pattern = ".pdf",recursive = TRUE),
list.files(pattern = ".zip",recursive = TRUE))
Cela va m'afficher une liste contenant l'adresse de chaque copie étudiante, type :
"2022-2023/Gérard Bouchard_9068332_assignsubmission_file_/ADN 2.pdf"
Je vais extraire pour chaque adresse l'année correspondante et le nom de l'étudiant.e :
# Collecte des années
annees_de_fichiers <- as.numeric(substring(liste_de_fichiers,1,4))
# Supprimer les fichiers qui n'ont pas d'année (optionnel)
liste_de_fichiers <- liste_de_fichiers[which(!is.na(annees_de_fichiers))]
annees_de_fichiers <- annees_de_fichiers[which(!is.na(annees_de_fichiers))]
# Extraire les noms des rédacteurs
noms<- str_split_fixed(liste_de_fichiers, "_",2)[,1]
noms<- str_split_fixed(noms, "/",2)[,2]
# Charger le corpus de l'année en cours
P_now <- readtext(liste_de_fichiers[which(annees_de_fichiers==max(annees_de_fichiers))],encoding ="UTF-8")
P_now$doc_id<- noms # Nommer chaque fichier par le nom de l'étudiant
#Bidouillage pour remplacer les double espaces par de simples.
gsub(" "," ",P_now$text) -> P_now$text ; gsub(" "," ",P_now$text) -> P_now$text
gsub(" "," ",P_now$text) -> P_now$text
corpus <- corpus(P_now)
corpus<- replace_symbol(corpus)
corpus<- replace_non_ascii(corpus,replacement="")
corpus<- strip(corpus, char.keep = "~~", digit.remove = TRUE, apostrophe.remove = F)
gsub("percent","",corpus) -> corpus
corpus_now <- corpus(corpus)
docnames(corpus_now)<- P_now$doc_id
Etablir une matrice de similarité qui mesure la similarité entre les devoirs :
matrix_simil <-textstat_simil(mydfm, method = "cosine")
Tracer un dendrogramme qui illustre les liens/proximités entre les devoirs :
plot(hclust(as.dist(1/matrix_simil),method="single")) # La bonne méthode
Les devoirs appariés ont tendance à se ressembler entre eux et pas aux autres.
Plus des noms apparaissent bas sur l'axe Y plus les devoirs sont similaires.
Ainsi, Michel Cohan et Kakior de l'anclo ont peut-être quelque chose à se reprocher.
Extraire ces données pour collecter pour chaque étudiant, le nom du devoir le plus proche et le niveau de similarité.
diag(matrix_simil) <- NA
#max_proxy <- apply(matrix_proxy,1,max,na.rm=T)
max_simil <- apply(matrix_simil,1,max,na.rm=T)
names_simil <- apply(matrix_simil,1,function(x){names(x)[which(x==max(x,na.rm=T))]})
names_simil <- sapply(names_simil, paste, collapse=":")
synthese <- data.frame("Etudiant"=docnames(corpus_now),
"Année_en_cours_similiarité_nom"=names_simil,
"Année_en_cours_similiarité_score"=max_simil
)
View(synthese)
Afficher le tableau.
On voit clairement la bonne similarité entre Kakior et Michel (~34%) : reste à voir si cette similarité est abusive en fonction du sujet du devoir (afin d'extraire par exemple la similarité des consignes).