Analyse automatique du plagiat avec R

Mesure de la similarité entre des documents rédigés par des étudiants

L'essentiel de cette page

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é.

1- Exécuter (et installer toutes les librairies nécessaires)

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)

########################

2- Charger tous les fichiers et extraire les années et les noms

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]

3- Transformer l'ensemble en corpus et nettoyer celui-ci

# 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

4- Mesurer la similarité entre tous les devoirs

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.

5- Générer un tableau de similarité pour seuiller automatiquement les fraudes

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).