forked from EricMarcon/Bibliometrie
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Bibliometrie.Rmd
435 lines (347 loc) · 14.5 KB
/
Bibliometrie.Rmd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
---
title: "Bibliométrie"
author:
- name: Eric Marcon
abstract: >
Utilisation de Google Scholar et de Scopus avec R pour analyser les publications d'une structure ou d'un auteur.
date: "`r format(Sys.time(), '%d %B %Y')`"
pdftoc: yes
preamble: >
\hyphenation{bio-di-ver-si-ty sap-lings}
bibliography: references.bib
lang: fr-FR # en-US
babel: french # english
always_allow_html: yes
output:
bookdown::html_document2:
theme: sandstone
toc: yes
toc_float: yes
bookdown::pdf_book:
base_format: EcoFoG::memo
latex_engine: xelatex
keep_tex: TRUE
---
```{r Options, include=FALSE}
knitr::opts_chunk$set(cache=TRUE, echo = TRUE, tidy=FALSE, tidy.opts=list(blank=FALSE, width.cutoff=50), out.width='\\maxwidth')
options(width=50)
# Installation des packages si nécessaire et chargement
Library <- function(Packages) {
InstallAndLoad <- function(Package) {
if (!Package %in% installed.packages()[, 1]) {install.packages(Package, repos="https://cran.rstudio.com/")}
require(Package, character.only = TRUE)
}
invisible(sapply(Packages, InstallAndLoad))
}
# Ajouter les packages nécessaires ici
Library(c("kableExtra", "scholar", "tidyverse", "ggraph", "bibliometrix", "tm", "wordcloud", "entropart"))
```
# Google Scholar
Le package _scholar_ permet d'accéder à l'API de Google Scholar.
L'objectif est d'analyser la production d'un auteur (ou d'une structure) disposant d'un identifiant, donc d'une page, Google Scholar.
Le paramètre de base est l'identifiant de l'auteur :
```{r}
# AuthorID <- "4iLBmbUAAAAJ" # Eric Marcon
AuthorID <- "8XqZyDUAAAAJ" # UMR EcoFoG
```
La vignette du package fournit la majorité du code utile.
```{r, eval=FALSE}
vignette(topic = "scholar", package = "scholar")
```
## Information sur l'auteur
La fonction `get_profile` retourne une liste avec les informations sur l'auteur.
```{r}
library("scholar")
get_profile(AuthorID)
```
## Liste des publications
La fonction `get_publications` retourne un dataframe contenant toutes les publications.
Les colonnes contiennent le titre, la liste des auteurs (séparés par des virgules), le nom du journal, la pagination (sous la forme _Volume (numéro), pages_), le nombre de citations et les années correspondantes (sous la forme de vecteurs), et deux identifiants internes de la publication (`cid` et `pubid`).
```{r, tidy=TRUE}
Publications <- get_publications(AuthorID)
colnames(Publications)
```
## Citations par année
Evolution du nombre de citations d'un auteur :
```{r}
library("ggplot2")
get_citation_history(AuthorID) %>%
ggplot(aes(x = year, y = cites)) +
geom_line() +
geom_point() +
labs(caption= format(Sys.time(), "%Y-%m-%d %H:%M (GMT %Z)"))
```
Suivi d'un article en particulier (le plus cité: les articles sont classés par ordre décroissant du nombre de citations) :
```{r}
NumArticle <- 1
Reference <- with(Publications[NumArticle, ],
paste(author, " (", year, ") ", journal, ". ", number, sep=""))
get_article_cite_history(AuthorID, Publications$pubid[NumArticle]) %>%
ggplot(aes(year, cites)) +
geom_segment(aes(xend = year, yend = 0), size=1, color='darkgrey') +
geom_point(size=3, color='firebrick') +
labs(caption = Reference)
```
## Réseau d'auteurs
`get_coauthors` retourne un dataframe contenant les coauteurs déclarés par l'auteur sur sa page et leurs coauteurs.
La profondeur `n_deep` du graphe permet d'augmenter le nombre de niveaux de coauteurs mais ne peut pas être mise à 0 pour obtenir seulement les coauteurs directs.
Les valeurs par défaut sont 5 coauteurs et une profondeur de 1.
```{r}
get_coauthors(AuthorID, n_coauthors = 5, n_deep=1) %>%
# Bug in get_coauthors
filter(substr(coauthors, start = 1, stop = 8) != "Sort By ") %>%
plot_coauthors
```
Les coauteurs réels, définis par le nombre de publications écrites en commun, sont à rechercher dans le tableau des publications.
```{r coauthors, message=FALSE, warning=FALSE}
### Paramètres
# Augmenter pour limiter le nombre de coauteurs affichés
MinCopublications <- 25
# Eliminer les documents non cités (mémoires, artefacts)
MinCitations <- 2
# Eliminer les coauteurs les moins productifs
MaxCoauteurs <- 100
library("magrittr")
# Vecteur des coauteurs de publications, sans accents
get_publications(AuthorID) %>%
dplyr::filter(cites >= MinCitations) %>%
mutate(AuthorsASCII=iconv(author, from="UTF-8", to="ASCII//TRANSLIT")) %$%
AuthorsASCII %>%
# Suppression des accents transformés en ' sur MacOS
str_replace("'", "") ->
AuthorsASCII
# Auteurs uniques
AuthorsASCII %>%
paste(collapse=", ") %>%
str_split(pattern=", ") %>%
unlist %>%
# Uniformisation de la casse
str_to_upper() %>%
unique ->
UniqueAuthors
# Elimination de ... (= et al.)
UniqueAuthors <- UniqueAuthors[UniqueAuthors != "..."]
# Matrice d'autorat: une ligne par article, auteurs en colonnes, valeurs logiques
PaperAuthoredBy <- sapply(UniqueAuthors, function(Author) str_detect(str_to_upper(AuthorsASCII), Author))
# Filtrage des auteurs
tibble(Author=UniqueAuthors, NbPapers=colSums(PaperAuthoredBy)) %>%
filter(NbPapers >= MinCopublications) %>%
arrange(desc(NbPapers)) %>%
slice(1:MaxCoauteurs) ->
NbPapersPerAuthor
# Recalcul de la matrice d'autorat réduite
PaperAuthoredBy <- sapply(NbPapersPerAuthor$Author,
function(Author) str_detect(str_to_upper(AuthorsASCII), Author))
# Matrice d'adjacence
adjacencyMatrix <- t(PaperAuthoredBy) %*% PaperAuthoredBy
# Graphe d'adjacence
# (https://paulvanderlaken.com/2017/10/31/network-visualization-with-igraph-and-ggraph/)
library("igraph")
g <- graph.adjacency(adjacencyMatrix, mode = "undirected", diag = FALSE)
V(g)$Degree <- degree(g, mode = 'in') # Nombre de liens
V(g)$Name <- NbPapersPerAuthor$Author # Etiquettes des noeuds
# Figure
library("ggraph")
ggraph(g, layout = "auto") +
geom_edge_diagonal(alpha = 1, label_colour = "blue") +
geom_node_label(aes(label = Name, size = log(Degree), fill = Degree)) +
scale_fill_gradient(high = "blue", low = "lightblue") +
theme(
plot.background = element_rect(fill = "beige"),
panel.border = element_blank(),
panel.grid = element_blank(),
legend.position = "none",
axis.text = element_blank(),
axis.title = element_blank(),
axis.ticks = element_blank()) +
labs(title = paste("Coauthorship Network of", get_profile(AuthorID)$name),
subtitle = paste("Publications with at least", MinCitations, "Google Scholar citations included"),
caption = paste("Coauthors with at least", MinCopublications, "copublications"))
```
Nombres de publications :
```{r}
knitr::kable(NbPapersPerAuthor, caption="Nombre de documents par auteur",
longtable = FALSE, booktabs = TRUE) %>%
kableExtra::kable_styling(bootstrap_options = "striped")
```
# Scopus et Web of Science
Le package _bibliometrix_ permet d'exploiter les données des bases de données commerciales majeures.
La vignette du package décrit l'ensemble de ses possibilités.
```{r, eval=FALSE}
vignette(topic = "bibliometrix-vignette", package = "bibliometrix")
```
## Lecture des données
Voir la première partie de la vignette.
Sur le site de Scopus (utilisé en exemple), sélectionner les références utiles et les exporter dans un fichier Bibtex.
L'export doit contenir tous les champs, y compris le résumé et les documents cités.
Le fichier est ensuite lu et converti:
```{r, message=FALSE}
library(bibliometrix)
# Fichier de données au format bibtex, exporté de Scopus
M <- convert2df("scopus.bib", dbsource="scopus", format="bibtex")
```
## Analyses basiques
Les analyses de base sont retournées par la fonction `biblioAnalysis`.
Le résultat est un objet de type `bibliometrix`.
Les méthodes `summary` et `plot` renvoient tous les résultats à l'écran.
```{r}
k <- 5 # Nombre d'auteurs à afficher
BA <- biblioAnalysis(M)
summary(BA, k)
```
Pour les afficher séparément, il faut stocker le résultat dans une variable (qui est une liste) et appeler ensuite chacun de ses membres.
```{r, fig.show='hide'}
# plot(BA) renvoie tous les graphiques à la suite. Stocker.
BAP <- plot(BA)
```
```{r, warning=FALSE}
# Graphiques disponibles
BAP$MostProdAuthors
BAP$MostProdCountries
BAP$AnnualScientProd
BAP$AverArtCitperYear
BAP$AverTotCitperYear
```
## h index
L'indice h peut être calculé par auteur ou source, et depuis un nombre d'années choisi.
Pour tous les auteurs :
```{r}
Hindex(M, elements = dominance(BA)$Author, years=50)$H %>%
arrange(desc(h_index))
```
Pour l'indice de toute la base bibliographique :
```{r}
(h <- Hindex(M, elements="*", years=50)$H)
```
Le graphique rang-citations peut être tracé par le package entropart.
```{r}
library("entropart")
# Courbe rang-abondance, ajustée à une distribution log-normale
autoplot(as.AbdVector(M$TC), ylab = "Nombre de citations", xlab = "Rang", Distribution = "lnorm") +
# Ajout de l'indice h
geom_hline(yintercept = h$h_index) +
geom_vline(xintercept = h$h_index)
```
## Documents et auteurs cités
Les documents les plus cités par la base bibliographique sont retournés par la commande `citations`, par article ou par auteur.
```{r}
CAR <- citations(M, field = "article")
CAR$Cited[1:5] %>%
as_tibble %>%
rename(Article = CR, Citations=n) %>%
knitr::kable(caption =
"Citations les plus fréquentes par les documents de la base de données bibliographique",
longtable = TRUE, booktabs = TRUE) %>%
kableExtra::kable_styling(full_width=TRUE, bootstrap_options = "striped")
```
Les auteurs les plus cités :
```{r}
CAU <- citations(M, field = "author")
CAU$Cited[1:5] %>%
as_tibble %>%
rename(Auteur=CR, Citations=n) %>%
knitr::kable(
caption="Auteurs les plus cités par les documents de la base de données bibliographique",
longtable = TRUE, booktabs = TRUE) %>%
kableExtra::kable_styling(bootstrap_options = "striped")
```
## Collaborations
Un réseau de collaboration entre les pays des auteurs est retourné par la fonction `biblioNetwork`.
```{r, tidy=TRUE}
NbCountries <- 15
# Create a country collaboration network
mAU_CO <- metaTagExtraction(M, Field = "AU_CO", sep = ";")
NetMatrix <- biblioNetwork(mAU_CO, analysis = "collaboration", network = "countries", sep = ";")
# Plot the network
netC <- networkPlot(NetMatrix, n = NbCountries, Title = "Country Collaboration", type = "circle", size=TRUE, remove.multiple=FALSE)
```
Le réseau des auteurs est obtenu de la même façon.
```{r, tidy=TRUE}
NbAuthors <- 15
# Réseau d'auteurs
AuthorNet <- biblioNetwork(M, analysis="collaboration", network="authors", sep = ";")
netA <- networkPlot(AuthorNet, n = NbAuthors, Title = "Author Collaboration", type = "circle", size=TRUE, remove.multiple=FALSE)
```
# Analyse des résumés
Les résumés des publications se trouvent dans la colonne `AB` de la base importée par _bibliometrix_.
Ils sont en Anglais.
## Corpus
Le package `tm` permet de constituer un corpus.
```{r}
library("tm")
M$AB %>%
VectorSource %>%
VCorpus %>%
tm_map(PlainTextDocument) %>%
tm_map(content_transformer(tolower)) ->
MonCorpus
```
La fonction `tm_map` permet d'appliquer une fonction quelconque à chaque élément du corpus, c'est-à-dire à chaque résumé.
Les fonctions standard, n'appartenant pas au package `tm`, doivent être appliquées par l'intermédiaire de la fonction `content_transformer` pour ne pas dégrader la structure du corpus : dans le code précédent, la fonction `tolower` est appliquée à chaque résumé pour le passer en minuscules, alors que la création de corpus est en majuscules.
## Nettoyage du corpus
Des mots sémantiquement identiques ont plusieurs formes.
Le traitement le plus rigoureux consiste à les réduire à leur radical mais le résultat n'est pas très lisible.
La fonction `stemDocument` permet de le faire : il suffit de l'utiliser à la place de `PlainTextDocument` dans le code ci-dessus.
Un bon compromis consiste à supprimer les formes plurielles, par une fonction ad-hoc : ce sera fait plus tard.
Les déterminants, conjonctions, etc. sont les mots les plus fréquents mais n'ont pas d'intérêt pour l'analyse.
La fonction `removeWords` permet de retirer une liste de mots.
`stopwords` fournit la liste de ces mots dans une langue au choix.
`removeNumbers` retire les nombres comme _one_, _two_, etc. et la fonction `removePunctuation` retire la ponctuation.
```{r}
MonCorpus %<>% tm_map(removePunctuation) %>%
tm_map(removeNumbers) %>%
tm_map(removeWords, stopwords("english"))
```
Une liste de mots complémentaire est nécessaire pour supprimer des mots inutiles mais fréquents.
Elle peut être complétée de façon itérative pour retirer des mots parasites du résultat final.
```{r, tidy=TRUE}
ExtraWords <- c("use", "used", "using", "results", "may", "across", "high", "higher", "low", "show", "showed", "study", "studies", "studied", "however", "can", "our", "based", "including", "within", "total", "among", "found", "due", "also", "well", "strong", "large", "important", "first", "known", "one", "two", "three")
MonCorpus %<>% tm_map(removeWords, ExtraWords)
```
## Mots du corpus
L'objectif est de transformer le corpus en un vecteur d'abondance des mots utilisés.
`TermDocumentMatrix` crée un objet spécifique au package _tm_ qui pose des problèmes de traitement.
Cet objet est transformé en un vecteur d'abondances.
```{r, tidy=TRUE}
TDM <- TermDocumentMatrix(MonCorpus, control = list(minWordLength = 3))
AbdMots <- sort(rowSums(as.matrix(TDM)), decreasing=TRUE)
```
Le vecteur de mots contient des formes singulières et plurielles.
Elles peuvent être regroupées selon un modèle simple : si un mot existe avec et sans _s_ ou _es_ final, la forme singulière est sans _s_ ou _es_.
Des pluriels particuliers peuvent être ajoutés selon les besoins.
```{r}
# Adapté de https://github.com/mkfs/misc-text-mining/blob/master/R/wordcloud.R
aggregate_plurals <- function (v) {
aggr_fn <- function(v, singular, plural) {
if (! is.na(v[plural])) {
v[singular] <- v[singular] + v[plural]
v <- v[-which(names(v) == plural)]
}
return(v)
}
for (n in names(v)) {
n_pl <- paste(n, 's', sep='')
v <- aggr_fn(v, n, n_pl)
n_pl <- paste(n, 'es', sep='')
v <- aggr_fn(v, n, n_pl)
# cas particuliers
if (endsWith(n, "y")) {
n <- substr(n, 1, nchar(n)-1)
n_pl <- paste(n, 'ies', sep='')
}
if (n == "genus") {
n_pl <- "genera"
v <- aggr_fn(v, n, n_pl)
}
}
return(v)
}
AbdMots %<>% aggregate_plurals
```
## Nuage de mots
Le résultat final est un nuage de mots.
```{r, tidy=TRUE, warning=FALSE}
library("wordcloud")
df <- data.frame(word=names(AbdMots), freq=AbdMots)
wordcloud(df$word, df$freq, max.words=100, random.order=FALSE, rot.per=0.35, use.r.layout=FALSE, colors=brewer.pal(8, "Dark2"))
```