Note: Ce document est l’annexe technique d’un article avec le même titre et coécrit par François Claveau, Olivier Santerre, Andréanne Veillette et Sylvain Rocheleau. Au moment de produire cette version, l’article est en évaluation pour publication dans une revue universitaire.

1 Tâches pléliminaires

Chargement des paquets R nécessaires au traitement des données.

require(ggplot2)
require(dplyr)
require(mongolite)
require(data.table)
require(tidyr)
require(stringr)
require(ggrepel)
require(fuzzyjoin)
if ("anytime" %in% installed.packages()==FALSE){
  install.packages('anytime',dependencies = TRUE) }
library(anytime)
if ("xtable" %in% installed.packages()==FALSE){
  install.packages('xtable',dependencies = TRUE) }
library(xtable)
require(knitr)
require(kableExtra)
library(rvest) # for web scraping

Définition de variables globales:

path_stable_data <- "/data/Think_tank/"
subproject_path <-"Media/mass_media/"
budget_path <- "Finance/"
DB_connection <- mongolite::mongo(db = "projetThinkTank", collection = "articles")
# Seuil pour considéré qu'un think tank a une présence médiatique importante:
# il doit avoir au minimum 1% des mentions
important_TT_threshold <- 0.01

# Objet avec différentes versions des noms de think tanks
tt_names <- read.csv(paste0(path_stable_data,"Others/list_of_thinktanks/",
                           "2020-05-13_list_Canadian_TT.csv" )
                    ) %>% data.table()

#Olivier n'a pas les droits pour sauvegarder des fichiers dans le dossier /data
if(Sys.getenv("LOGNAME") =="francois"){
  is_Francois_running = TRUE
} else {  is_Francois_running = FALSE }


#Pour éviter qu'il y ait des exposants lorsqu'on affiche des nombres.
inline_hook <- function(x) {
  if (is.numeric(x)) {
    format(x, digits = 2)
  } else x
}
knitr::knit_hooks$set(inline = inline_hook)

#Traduction des catégories
label_francais = c("Économie et Finance", "Politique", "Travail", "Éducation", "Santé", "Sports", "Investissements", "Criminalité, droit et justice", "Société", "Environnement", "Désastres et accidents", "Arts, culture, divertissement et médias", "Conflit, guerre et paix", "Gens animaux insolite", "Science et technologie", "Météo", "Religion et croyance", "Vie quotidienne et loisirs", "Économie", "Energie et ressources", "Budget", "Finance", "Résultats financiers", "Élections")

label_anglais = c("economy, business and finance", "politics", "labour", "education", "health", "sport", "investment", "crime, law and justice", "social issue", "environmental issue", "disaster and accident", "arts, culture and entertainment", "unrest, conflicts and war", "human interest", "science and technology", "weather", "religion and belief", "lifestyle and leisure", "economy (general)", "energy and resource", "budgets and budgeting", "finance (general)", "earnings", "election")


traduction_label <- data.table(label_anglais, label_francais)

#Top 25 medias names

media_name <- c("The Globe and Mail", "CBC", "Castanet","CTV News", "Global News", "The Province", "Financial Post", "Calgary Herald", "The Star", "Toronto Sun", "National Post", "Vancouver Sun", "La Presse", "Edmonton Journal", "Journal de Montréal", "Montreal Gazette", "Edmonton Sun", "Journal de Québec", "Le Devoir", "Times Colonist", "Ottawa Citizen", "Lethbridge Herald", "Radio-Canada", "TVA Nouvelles", "Medicine Hat News")


root_url <- c("www.theglobeandmail.com","www.cbc.ca", "www.castanet.net", "www.ctvnews.ca", "globalnews.ca", "theprovince.com", "business.financialpost.com", "calgaryherald.com", "www.thestar.com", "torontosun.com", "nationalpost.com", "vancouversun.com", "www.lapresse.ca", "edmontonjournal.com", "www.journaldemontreal.com", "montrealgazette.com", "edmontonsun.com", "www.journaldequebec.com", "www.ledevoir.com", "www.timescolonist.com", "ottawacitizen.com", "lethbridgeherald.com", "ici.radio-canada.ca", "www.tvanouvelles.ca", "medicinehatnews.com")

media_names <- data.table(root_url, media_name)

1.1 Méthode d’extraction des mentions de think tanks

À partir de notre liste de 24 think tanks, nous avons construit des expressions régulières afin d’atteindre un haut niveau de sensibilité (extraire presque toutes les mentions; c.-à-d. minimiser les faux négatifs) et de précision (ne pas attribuer une mention lorsque la référence est à une autre organisation; c.-à-d. minimiser les faux positifs). Les expressions régulières ont été construites de façon itérative, avec échantillonage et inspection manuelle à chaque passage pour les corriger.

Les requêtes finales pour chaque think tank sont:

dt_tt_queries <- fread(paste0(path_stable_data,subproject_path,"thintank_queries.csv"))
dt_tt_queries <- merge(tt_names[,list(tt_ID,tt_short_to_use)],dt_tt_queries, by="tt_ID")
dt_tt_queries[,list(`Requête`=query,`Think tank`=tt_short_to_use)]

Ces requêtes sur la base de données de l’Observatoire de la circulation de l’information nous retournent une collection à partir de laquelle l’ensemble de l’analyse présentée ici est produite.

1.2 Prétraitement

En particulier, nous créons une table qui associe chaque think tank à un document si et seulement si ce document mentionne ce think tank. Nous chargeons cette table:

#We load the table containing the list of articles (doc_ID) that mention TT
dt_tt_in_mass_media <- read.csv(paste0(path_stable_data,subproject_path,"df_tt_in_mass_media.csv")) %>% data.table()
dt_tt_in_mass_media <- merge(dt_tt_in_mass_media, tt_names[,list(tt_ID, tt_short_to_use)], by = "tt_ID", all.x = TRUE)
 
# Quelques données sur notre extraction
nb_docs <-  dt_tt_in_mass_media$doc_ID %>% unique() %>% length()
min_date <- DB_connection$find(
  fields = '{"scraped_on" : true}',
  sort = '{"scraped_on":1}',
  limit = 1)$scraped_on
max_date <- DB_connection$find(
  fields = '{"scraped_on" : true}',
  sort = '{"scraped_on":-1}',
  limit = 1)$scraped_on
nb_days = (max_date - min_date)/86400

Cette extraction nous donne 49401 documents médiatiques du 2017-01-07 au 2020-05-12, ce qui équivaut à 1221 jours de contenu médiatique ( 3.4 années).

Certains think tanks ne sont mentionnés que très peu souvent par les médias canadiens. Nous créons donc une liste réduite des think tanks qui ont au minimum 1% des mentions médiatiques dans notre corpus.

#In some section, we only take think tanks that get more than one percent of all mentions
imp_TT <- dt_tt_in_mass_media[,.N, by = "tt_ID"]
imp_TT[,Proportion := N / sum(N)]
imp_TT <- imp_TT[Proportion > important_TT_threshold, list(tt_ID)]

Pour la section sur la description des données, nous créons un tableau descriptif des think tanks:

descript_tt <- tt_names[,list(tt_ID,tt_short_to_use, Name_fr,Name_en)]

descript_tt[is.na(Name_fr),Name_fr := Name_en][,Name_en:=NULL]
setnames(descript_tt,c("tt_short_to_use","Name_fr"),c("Acronyme","Nom complet"))

descript_tt <- rbind(
  descript_tt[tt_ID %in% imp_TT$tt_ID][order(`Nom complet`),list(un_perc = "Oui", Acronyme,`Nom complet`)],
  descript_tt[!tt_ID %in% imp_TT$tt_ID][order(`Nom complet`),list(un_perc = "Non", Acronyme,`Nom complet`)]
  )
setnames(descript_tt,"un_perc","Plus que 1% des citations")


if (is_Francois_running){
  write.csv(descript_tt,paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_tt_general_info.csv"),row.names = F)
}

if(is_Francois_running ==TRUE){
  print(xtable(descript_tt[,list(Acronyme,`Nom complet`)]), type="latex",#include.rownames = FALSE,
      file = paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_tt_general_info.tex"))
}

descript_tt %>% kable(caption = "") %>%
  kable_styling(fixed_thead = T) %>%
  scroll_box(width = "800px", height = "360px")
Plus que 1% des citations Acronyme Nom complet
Oui CCPA Centre canadien de politiques alternatives
Oui CEFRIO Centre facilitant la recherche et l’innovation dans les organisations
Oui CIGI Centre pour l’innovation dans la gouvernance internationale
Oui Conf Board Conference Board du Canada
Oui CCA Conseil des académies canadiennes
Oui APF Fondation Asie Pacifique du Canada
Oui PPForum Forum des politiques publiques
Oui Broadbent Institut Broadbent
Oui CDHowe Institut C.D. Howe
Oui Cardus Institut Cardus
Oui IRIS Institut de recherche et d’informations socio-économiques
Oui IEDM Institut économique de Montréal
Oui Fraser Institut Fraser
Oui IISD Institut international du développement durable
Oui Pembina Institut Pembina
Oui CWF Canada West Foundation
Non CRIM Centre de recherche informatique de Montréal
Non CIRANO Centre interuniversitaire de recherche en analyse des organisations
Non CTF Fondation canadienne de fiscalité
Non CIFAR Institut canadien de recherches avancées
Non IRPP Institut de recherche en politiques publiques
Non IHE Institute of Health Economics
Non Maytree Maytree
Non Mowat Mowat Center

2 Relation entre mentions et budget

Notre première grande question a trait à la relation entre le nombre de mentions et les ressources financières des think tanks.

Pour les budgets annuels, nous utilisons les données récoltées par l’équipe de Stéphanie Yates. Nous chargeons ces données et les associons aux nombres de mentions médiatiques rapportées sur une base annuelle.

budgets <- read.csv(paste0(path_stable_data,
                           budget_path,"2020-05-27_budget_Canadian_TT.csv" )
                    ) %>% data.table()
dt_number_art_per_TT <- dt_tt_in_mass_media[,.N, by = "tt_ID"]
budgets <- merge(budgets, dt_number_art_per_TT, by = "tt_ID")
budgets <- budgets[,list(tt_ID, Budget, N = round(N/nb_days*365))]
#budgets <- budgets[tt_ID != "Broadbent_TT"]
budgets$Budget <-  as.numeric(gsub(",","",budgets$Budget))
 
budgets <- merge(tt_names[,list(tt_ID,tt_short_to_use)],budgets, by="tt_ID")

On peut représenter dans un plan la relation entre budget et présence médiatique. La Figure ici ne représente que les 15 think tanks avec au moins 1% des mentions et dont nous avons les données budgétaires (ce qui exclut l’Institut Broadbent).

ggplot(budgets[tt_ID %in% imp_TT$tt_ID],aes(x=Budget/10^6,y=N, label =tt_short_to_use)) +
  geom_label_repel() + ylab("Nombre de documents médiatiques") +
  xlab("Budget annuel (en millions de CAD)")

Si on se concentre sur les mentions, les quatre think tanks les plus cités rafflent 60% de celles-ci.

On voit que la relation entre le budget et la présence médiatique n’est pas très forte, la corrélation dans le sous-ensemble ici étant de 0.41 (et tombant à 0.35 si on inclut les think tanks dont les mentions correspondent à moins de 1% du total).

Et si on exclut trois cas atypiques: CIGI, IISD et le Conference Board? La corrélation pour l’échantillon des autres think tanks saute à 0.71. Et si on exclut trois cas atypiques: CIGI, IISD et Fraser? La corrélation pour l’échantillon des autres think tanks saute à 0.74.

Une autre perspective sur ces données est de regarder combien ‘coûte’ une citation dans les médias pour chaque think tank. Nous divisons le budget annuel de l’organisation par le nombre annuel de citations. L’Institut Broadbent doit être écarté à nouveau de l’analyse puisque nous n’avons pas ses données budgétaires. Nous restreignons aussi les résultats aux think tanks avec des mentions équivalant à au moins 1% du total.

budgets[,dollar_per_article := Budget /N]

cost_by_mention <- budgets[tt_ID %in% imp_TT$tt_ID &  tt_ID != "Broadbent_TT"][order(dollar_per_article),
                                 list(`Think tank`= tt_short_to_use,
                                      `Coût par citation` = paste0(round(dollar_per_article)," $"), 
                                      `Budget` =paste0(round(Budget/10^6,1)," M$"),
                                      `Citations annuelles` = N)]

if (is_Francois_running)
{
  write.csv(cost_by_mention,paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_cost_by_mention.csv"),row.names = F)
   print(xtable(cost_by_mention), type="latex",#include.rownames = FALSE,
      file = paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_cost_by_mention.tex"))
}


cost_by_mention

2.1 Autres représentations pour le décompte des citations

Cette sous-section inclut des représentations alternatives des mentions globales.

2.1.1 Quels sont les think tanks les plus cités?

#Most cited TT
dt_tt_in_mass_media <- dt_tt_in_mass_media[,N := .N, by = "tt_ID"]
ggplot(dt_tt_in_mass_media, aes(x = reorder(tt_short_to_use, N))) + geom_bar() + coord_flip() + ylab("Nombre d'articles") + xlab("Think tank")

dt_tt_w_cit_count <- unique(dt_tt_in_mass_media[order(-N),list(tt_ID,N)]) 

Les 4 think tanks les plus mentionnés représentent 60% des mentions.

2.1.2 Quels médias citent le plus de think tanks?

#Getting every articles that are in french or english with more that 500 characters.
query <- paste0('{"_id" : {"$in" :  [{"$oid": "', paste(unique(dt_tt_in_mass_media$doc_ID), collapse = '"}
                ,{"$oid":"'),"\"}]}", ',
                "text_length": {"$gt": 500.0}, 
                "language": {"$in":["fr","en"]}}')
#We are only taking the article's title, published_date and ful text.
fields <- '{"media_url" : true}'

#Fetching the data.
dt_media <- DB_connection$find(query = query, fields = fields) %>% data.table()

#cbc has 30 different urls
dt_media[grepl("cbc", media_url), media_url := "https://www.cbc.ca/"]


dt_media <- dt_media[media_url != "https://www.cdhowe.org/"]
#Searching for 25 most citing media
dt_media <- dt_media[,N := .N, by = "media_url"]

#Creating the root_url column in order to merge names from the first_25
dt_media[,root_url:= str_split(str_split(media_url,"://")[[1]][2],pattern = "/")[[1]][1],by=media_url]
dt_media[grepl("ctvnews.ca",root_url), root_url:= "www.ctvnews.ca"]
dt_media[grepl("yahoo.com",root_url), root_url:= "ca.yahoo.com"]
dt_media[grepl("vancouversun",root_url), root_url:= "vancouversun.com"]
dt_media[, nb_TT_refs := .N, by = root_url]

#ordering in order to plot the top 25 citing medias
setorder(dt_media, -nb_TT_refs)
dt_plot <- dt_media[,list(root_url, nb_TT_refs)] %>% unique() %>% head(25)
#ploting
ggplot(dt_plot , aes(x = reorder(root_url, nb_TT_refs), y=nb_TT_refs)) + geom_bar(stat = "identity") + coord_flip() + ylab("Nombre d'articles") + xlab("Médias")

3 Thèmes abordés dans les articles citant des think tanks

Dans cette section, nous voulons savoir quels thèmes sont le plus souvent abordés dans les articles qui font intervenir les think tanks. Nous voulons aussi voir dans quelle mesure les think tanks se différencient les uns des autres sur ce plan.

Dans notre base de donnée, à chaque article est associé une dizaine de catégories, qui sont au fond des thèmes, avec un score entre 0 et 1. Plus le score est près de 1, plus l’article a de probabilité de porter sur la catégorie (ou le thème) en question. Ce classement se fait automatiquement sur la base des catégories de l’IPTC.

Les catégories sont organisées en arborescence. En haut de l’arbre se situent les catégories les plus générales. Par exemple, au premier niveau, on trouve “politics” et “economy business and finance”. Les catégories des niveaux inférieurs sont de plus en plus spécifiques. Par exemple au deuxième niveau, on peut trouver “economy, business and finance>economy (general)” et au troisième niveau “economy, business and finance>macro economics>investments”. Le “>” représente une arète dans l’arbre des catégories. L’arbre en question a 3 niveaux.

Pour notre analyse nous prenons seulement la catégorie ayant obtenu le meilleur score pour chaque article.

3.1 Chi carré

Dans un premier temps, nous avons voulu savoir si les articles de notre corpus se distinguent de l’ensemble des articles des médias canadiens. Ici, nous prenons en compte uniquement les catégories du plus haut niveau de généralité. Par exemple, si la catégorie est “economy, business and finance>economy (general)”, nous conservons uniquement “economy, business and finance”. Pour répondre à la question de savoir si notre corpus se distingue de l’ensemble des articles, nous avons généré un échantillon aléatoire à partir de la base de données de Sylvain Rocheleau. Nous avons ensuite calculé selon quelles proportions étaient réparties les catégories dans cet échantillon. Grâce à un test du chi carré, nous avons voulu répondre à la question de savoir si notre corpus d’articles mentionnant des think tanks se distinguait de l’échantillon sur le plan des catégories. L’hypothèse nulle ici est donc qu’il n’y aurait aucune différence entre notre corpus et l’échantillon sur ce plan.

DB_sample_categories <- mongolite::mongo(db = "projetThinkTank", collection = "random_categories")
dt_sample_categories <- DB_sample_categories$aggregate('[{"$unwind": "$categories"},
                                          {"$sort":{"categories.score": -1}},
                                          {"$group":{"_id":"$_id",
                                           "score": {"$first" : "$categories.score"},
                                           "label": {"$first" :"$categories.label"}}}]') %>% data.table()

#We only get categories that have a score higer than 0.55, to get rid of weird cases.
dt_sample_categories <- dt_sample_categories[score > 0.55, c("_id", "score", "label")]
dt_sample_categories <- separate(dt_sample_categories,label,c("label1", "label2", "label3"), sep = ">")
dt_sample_categories <- dt_sample_categories[,list(label = label1)]
dt_sample_categories <- dt_sample_categories[, list(sample_count = .N), by = label]

dt_categories <- DB_connection$aggregate('[{"$unwind": "$categories"},
                                          {"$sort":{"categories.score": -1}},
                                          {"$group":{"_id":"$_id",
                                           "score": {"$first" : "$categories.score"},
                                           "label": {"$first" :"$categories.label"}}}]') %>% data.table()

#We only get categories that have a score higer than 0.55, to get rid of weird cases.
dt_categories <- dt_categories[score > 0.55, c("_id", "score", "label")]
dt_categories <- separate(dt_categories,label,c("label1", "label2", "label3"), sep = ">")
dt_categories <- dt_categories[,list(label = label1)]
dt_categories <- dt_categories[, list(TT_count = .N), by = label]

dt_chi_square <- merge(dt_sample_categories, dt_categories, by = "label", all.x = TRUE, all.y = TRUE)
dt_chi_square[is.na(sample_count), sample_count := 0]
dt_chi_square[is.na(TT_count), TT_count := 0]
# This table gives a n-categories by 2 contingency table. 
# We can compute the chi-square statistics for this table under the assumption that there is no relationship between rows and columns
res_chi <- chisq.test(dt_chi_square[,list(sample_count,TT_count)])
  # OLD
  # dt_chi_square[, proportion := sample_count / sum(sample_count)]
  # dt_chi_square[, expected_count := proportion * sum(TT_count)]
  # dt_chi_square[, contribution_to_chi := (TT_count - expected_count)^2 / expected_count]
# We save the standardized residuals for TT sample
dt_chi_square[, residual := res_chi$stdres[,2]]

Afin d’obtenir une valeur-p sous 0.05, un test chi-2 avec 17 degrés de liberté, comme c’est le cas ici, a besoin de produire une valeur d’au moins 28. On atteint une valeur-p d’environ 0.01 aux alentours d’une statistique du chi carré de 33. La valeur chi-2 obtenue dans notre cas est d’environ 19336. On peut donc, sans crainte, rejeter l’hypothèse nulle selon laquelle il n’y a pas de différence entre l’échantillon et notre corpus.

Dans le graphique ci-bas, on présente les catégories qui sont le plus surreprésentées et sous-représentées dans notre corpus en comparaison avec notre échantillon. L’unité de mesure est le résidu qu’on obtient grâce à la formule suivante :

\(résidu =\frac{valeur\, observée - valeur\, attendue}{\sqrt(valeur \, attendue)}\)

Plus la valeur du résidu est élévée plus cette catégorie est surreprésentée dans notre corpus, et vice versa.

if(any(!dt_chi_square$label %in% traduction_label$label_anglais)){stop("Some category labels are not in the translation table.")}
#On regarde si certaines traduction de label sont manquant
a <- 2
dt_chi_square <- merge(dt_chi_square,traduction_label, by.x = "label", by.y = "label_anglais")

ggplot(dt_chi_square, aes(x = reorder(label_francais,residual), y = residual)) + geom_bar(stat = "identity") + coord_flip() + ylab("Résidu du chi-carré") + xlab("Catégories")

3.2 Catégories les plus fréquentes par think tank

Pour savoir comment les think tanks se distinguent entre eux, nous avons opté pour les catégories du plus bas niveau disponible. Par exemple, si la catégorie associée à un article est “economy, business and finance>macro economics>investments”, nous conservons uniquement “investments”. Nous avons opté pour cette méthode puisque les catégories du plus haut niveau sont trop générales pour montrer les spécificités de chaque think tank.

dt_categories <- DB_connection$aggregate('[{"$unwind": "$categories"},
                                          {"$sort":{"categories.score": -1}},
                                          {"$group":{"_id":"$_id",
                                           "score": {"$first" : "$categories.score"},
                                           "label": {"$first" :"$categories.label"}}}]') %>% data.table()
 
#Separating level so each one gets its column
dt_categories <- separate(dt_categories,label,c("label1", "label2", "label3"), sep = ">")
#If no level 3 is available, we take level 2
dt_categories[is.na(label3), label3 := label2]
#If no level 2 is available (and hence neither is level 3) we take level 1
dt_categories[is.na(label3), label3 := label1]
#We only get categories that have a score higer than 0.55, to get rid of weird cases.
dt_categories <- dt_categories[score > 0.55, c("_id", "score", "label3")] %>% setnames("label3", "label1")

#On prend les catégories les plus importantes, et on facet wrap par categorie
nb_categories_to_plot <- 10
dt_most_imp_cat <- merge(dt_tt_in_mass_media, dt_categories, by.x = "doc_ID", by.y = "_id", all.x = TRUE)
dt_most_imp_cat <- dt_most_imp_cat[!is.na(label1) & tt_ID %in% imp_TT$tt_ID, list(tt_short_to_use, label = label1)]
dt_most_imp_cat <- dt_most_imp_cat[,N := .N, by = .(tt_short_to_use, label)] %>% unique()
setorder(dt_most_imp_cat, tt_short_to_use, -N)
most_imp_cat <- dt_most_imp_cat[, sum(N), by=label]
setorder(most_imp_cat, -V1)
most_imp_cat <- head(most_imp_cat$label, nb_categories_to_plot)
dt_most_imp_cat[,total := sum(N), by = tt_short_to_use][,proportion := N/total]
dt_most_imp_cat <- dt_most_imp_cat[label %in% most_imp_cat]

#We check if we miss some translations as the data evolve
if(any(!dt_most_imp_cat$label %in% traduction_label$label_anglais)){stop("Some category labels are not in the translation table.")}

dt_most_imp_cat <- merge(dt_most_imp_cat, traduction_label, by.x = "label", by.y = "label_anglais")

ggplot(dt_most_imp_cat, aes(x=label_francais, y=proportion)) + geom_bar(stat = "identity") + facet_wrap(~ tt_short_to_use)  + coord_flip() + xlab("Catégories") + ylab("Proportion des articles dans lesquels le think tank est cité")

4 Co-citations

Nous voulons savoir dans quelle proportion les think tanks (TT) tendent à être cités seuls dans les articles des médias canadiens. Nous voulons aussi savoir au côté de quel autre TT, chaque TT a le plus tendance à être cité. Les calculs sont faits en prenant la liste des 24 think tanks, mais seulement les résultats pour les think tanks ayant au moins 1% des mentions sont affichés.

Nous débutons par la création des objets importants pour l’analyse.

## First creating a matrix of co-cication
dt_cocitation <- dt_tt_in_mass_media[,list(doc_ID)] %>% unique()
dt_tt_in_mass_media[,N := .N, by = "doc_ID"]
for (i in 1:max(dt_tt_in_mass_media$N))
{
  new_col <- dt_tt_in_mass_media[,.SD[i], by = doc_ID]$tt_ID
  dt_cocitation <- cbind(dt_cocitation, new_col)
  setnames(dt_cocitation, "new_col", paste0("TT_",i))
}

#First we want to know what TT are, proportionnaly, the most often cited alone.
#Counting how many times every TT are cited alone
TT_cited_alone <- dt_cocitation[is.na(TT_2), .N, by=TT_1][order(-N)]
setnames(TT_cited_alone, "TT_1", "tt_ID")
#Counting how many times every TT is cited with another one
TT_cited_with_another <- dt_tt_in_mass_media[N > 1]
TT_cited_with_another <- TT_cited_with_another[,.N, by = "tt_ID"]

#Merging the two table
TT_cited_alone <- merge(TT_cited_alone, TT_cited_with_another, by = "tt_ID", all.x = TRUE)
setnames(TT_cited_alone, c("N.x", "N.y"), c("nb_alone", "nb_with_another"))
TT_cited_alone[is.na(nb_with_another), nb_with_another := 0]#one case (IHE_TT)

#Calculating the proportion
TT_cited_alone[,proportion_alone := nb_alone /(nb_with_another + nb_alone)]

Suit maintenant la création d’un graphique avec la proportion de mentions accompagnant un autre think tank.

TT_cited_alone <- merge(tt_names[,list(tt_ID,tt_short_to_use)],TT_cited_alone, by="tt_ID")

#Ploting
ggplot(TT_cited_alone[tt_ID %in% imp_TT$tt_ID], aes(x = reorder(tt_short_to_use, 1-proportion_alone), y = 1-proportion_alone)) + geom_bar(stat = "identity") + coord_flip() + ylim(c(0,1)) + xlab("Think tanks") + ylab("Proportion de mentions non isolées")

TT_cited_alone[tt_ID %in% imp_TT$tt_ID][order(proportion_alone),list(Acronyme=tt_short_to_use,
            `Nombre seul`=nb_alone, 
            `Nombre pas seul`=nb_with_another,
            `Proportion seul`=proportion_alone)]

Cette proportion est suprenamment base. Pour l’ensemble des think tanks, elle n’est que de 8.1%.

Il s’agit maintenant de regarder les couples les plus co-cités. Nous utilisons deux mesures: le nombre de co-citations par publication, mais aussi par article (c.-à-d. qu’un même article publié plusieurs fois dans différents médias ne compte qu’une fois).

#The next question we ask ourselves is who is the most cited with whom?
#We use another method to answer that question, since the previous table format made it to difficult to answer that question.


freq_cocitation <- function(dt,just_top=FALSE)
{
  #This function returns a table of the frequency of cocitations.
  #This function takes a table with two columns : doc_ID which an identifier of the article, and tt_ID which is a identifier of a TT.
  #Each line represent a time an given article mentions a given TT. If one article mentions 5 different TTs, there will be 5 lines with
  #the same doc_ID.
  dt[,N := .N, by = "doc_ID"]
  
  #Creating all combinations of TT cited in the same article
  dt_all_combination <- dt[N > 1, list(TT_1=rep(tt_ID[1:(length(tt_ID)-1)],
                                                        (length(tt_ID)-1):1),
                                                 TT_2 = rev(tt_ID)[sequence((length(tt_ID)-1):1)]),
                                                 by= doc_ID]
  dt_cocitation <- data.table()
  #In this loop we count how many times every TT is cited with every other.
  for (think_tank in unique(dt_tt_in_mass_media$tt_ID))
  {
    dt_tt1 <- dt_all_combination[TT_1 == think_tank]
    dt_tt1 <- dt_tt1[, .N, by = "TT_2" ][,.(tt2 = TT_2, TT_2 = NULL, N)]
    dt_tt2 <- dt_all_combination[TT_2 == think_tank]
    dt_tt2 <- dt_tt2[, .N, by = "TT_1"][,.(tt2 = TT_1, TT_1 = NULL, N)]
    dt_tt <- rbind(dt_tt1, dt_tt2)
    dt_tt[,N := sum(N), by = "tt2"]
    dt_tt$tt1 <- think_tank
    dt_cocitation <- rbind(dt_cocitation, dt_tt, fill=TRUE)
    
    
  }
  # reordering tt1 and tt2 to remove duplicate lines
  dt_cocitation[,tt2 := as.character(tt2)]
  dt_cocitation[,i:=1:.N]
  dt_cocitation <- dt_cocitation[,   list(TT1 = sort(c(tt1,tt2))[1],
                                          TT2 = sort(c(tt1,tt2))[2],
                                          N), by = i][,i:=NULL] %>% unique()
  
  
  # Renommons les identifiants de think tanks:
  dt_cocitation <- merge(tt_names[,list(tt_ID,tt_short_to_use)],dt_cocitation, 
                         by.x="tt_ID",by.y="TT1")
  setnames(dt_cocitation,"tt_short_to_use","Think tank 1")
  dt_cocitation$tt_ID <- NULL
  dt_cocitation <- merge(tt_names[,list(tt_ID,tt_short_to_use)],dt_cocitation, 
                         by.x="tt_ID",by.y="TT2")
  setnames(dt_cocitation,"tt_short_to_use","Think tank 2")
  dt_cocitation$tt_ID <- NULL
  
  setnames(dt_cocitation,"N","Cocitations")
  # reordering columns
  setcolorder(dt_cocitation, c("Think tank 1","Think tank 2","Cocitations"))
  
  # reordering rows for max to min
  setorder(dt_cocitation, -Cocitations, "Think tank 1","Think tank 2")
  
  if (is_Francois_running)
  {
    write.csv(dt_cocitation,paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_cocits_tt.csv"),row.names = T)
  }
  
  if(just_top == TRUE){
  # Focusing on the 20 most common cocitations
    dt_cocitation %>% head(20)
  } else {
    dt_cocitation
  }
}

Nous avons décidé d’ordonner les couples par le nombre de co-citations sur la base de l’article, mais nous mettons le rang des couples entre parenthèses pour le nombre de co-publications.

fuzzy_join_article_duplicates <- function(i)
{
  #This function finds duplicates in a list or articles with the same title. 
  #The parameter 'i' is the index of the list of titles that appear more than once.
  
  #To know where we're at
  print(paste0("article ", i))
  #Getting the title
  title_ <- article_titles[i]
  #getting all publications with that title
  dt_article <- dt_articles_duplicates[title == title_]
  #Over about 20000 charaters, the fuzzy join function overload our memory
  memory_limit_nb_character <- 20000
  dt_article[text_length > memory_limit_nb_character,  `:=` 
             (full_article_text = substr(full_article_text, 1, memory_limit_nb_character), text_length = memory_limit_nb_character)]
  #We did tests and concluded if the levenshtein distance made edits under 0.05 * (nb_character_text1 + nb_character_text2) / 2. It must be
  #the same article
  distance_proportion <- 0.05
  #We need a max distance in the stringdist_inner_join function so it don't take forever.
  max_distance <- max(dt_article$text_length) * distance_proportion
  fuzzy_join_distances <- stringdist_inner_join(dt_article, dt_article, by="full_article_text",
                                distance_col = "distance",
                                method = "osa",
                                max_dist = max_distance) %>% data.table()
  
  #renaming
  setnames(fuzzy_join_distances,c("doc_ID.x", "doc_ID.y"), c("ID1", "ID2"))
  #Getting rid of distances between the same article
  fuzzy_join_distances <- fuzzy_join_distances[ID1 != ID2, list(ID1, ID2, distance, text_length.x, text_length.y)]
  #This will make sure we can have two or more different articles in a set of publications with the same title
  fuzzy_join_distances <- fuzzy_join_distances[, `:=`(ID1 = c(ID1,ID2) %>% sort() %>%  first(), ID2 = c(ID1,ID2) %>% sort() %>% last())
     , by = .(ID1,ID2)] %>% unique()
  
  #Returning the table with the score
  fuzzy_join_distances[,score := distance / (text_length.x + text_length.y / 2)]
}

#Fetching article titles, full_text and length
query <- paste0('{"_id" : {"$in" :  [{"$oid": "', paste(unique(dt_tt_in_mass_media$doc_ID), collapse = '"}
                ,{"$oid":"'),"\"}]}", ',
                "text_length": {"$gt": 500.0}, 
                "language": {"$in":["fr","en"]}}')
fields <- '{"title" : true, "full_article_text" : true, "text_length" : true}'
dt_publications <- DB_connection$find(query = query, fields = fields) %>% data.table()

#renaming
setnames(dt_publications, "_id", "doc_ID")

#Taking publication that have the same title
dt_publications[,N := .N, by = title]
dt_articles_duplicates <- dt_publications[N > 1]
setorder(dt_articles_duplicates, -text_length)

#list of article, we need this for the fuzzy_join_article_duplicates() function to work
article_titles <- dt_articles_duplicates$title %>% unique()

#creating the table we will save the results in
articles_list <- data.table(doc_ID = character(), publication_rank = numeric())
#looping over all titles
articles_list <- foreach(i = 1:length(article_titles), .packages=c('tidyr', 'dplyr', 'fuzzyjoin', 'data.table'), .combine = rbind) %do% fuzzy_join_article_duplicates(i)

#0.05 is our threshold, as explained in the fuzzy_join_duplicates() function
articles_list <- articles_list[score < 0.05]
#The way articles_list is ordered ensure that if we don't take ID2, we will have only one article per 'cluster' of publications that are the same article. This line keeps articles that don't have dupplicates too.
unique_articles <- dt_publications[!doc_ID %in% unique(articles_list$ID2), list(doc_ID)] %>% unique()
#saving unique articles
save(unique_articles, file = "/data/Think_tank/Media/mass_media/unique_articles.RData")
#Nombre de cocitation en terme de publications
dt_cocit <- freq_cocitation(dt_tt_in_mass_media)
# Ajout du rang
dt_cocit[order(-Cocitations), cocit_pub:=paste0(Cocitations," (",.I,")")][,Cocitations:=NULL]
setkey(dt_cocit, "Think tank 1", "Think tank 2")


#Nombre de cocitation en terme d'articles.
load("/data/Think_tank/Media/mass_media/unique_articles.RData")
dt_articles <- dt_tt_in_mass_media[doc_ID %in% unique_articles$doc_ID]

temp_cocit <- freq_cocitation(dt_articles)
temp_cocit[order(-Cocitations), cocit_art:=paste0(Cocitations," (",.I,")")]
setkey(temp_cocit, "Think tank 1", "Think tank 2")

# Combinaison des deux mesures

dt_cocit <- dt_cocit[temp_cocit]

dt_cocit <-  dt_cocit[order(-Cocitations), list(`Think tank 1`,`Think tank 2`,
                                   `Articles avec co-citation` = cocit_art, 
                                   `Publications avec co-citation` = cocit_pub)] 

dt_cocit <- head(dt_cocit,20)

# Production de la table en différents formats

if(is_Francois_running ==TRUE){
  write.csv(dt_cocit,paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_most_cocited.csv"),row.names = F)
  print(xtable(dt_cocit), type="latex",include.rownames = FALSE,
      file = paste0(path_stable_data,subproject_path,
                                   Sys.Date(),"_most_cocited.tex"))
}

dt_cocit

Une forte proportion des mentions de Maytree vont avec le CCPA puisque Maytree ne parait que dans 211 publications.

5 Relation préférentielle entre think tanks et médias

Nous produisons ici une carte thermique (heatmap) des références aux think tanks dans les plus grands médias canadiens. L’algorithme derrière la carte thermique regroupe ensemble les colonnes et les lignes similaires de la matrice qu’on lui passe en argument. Dans notre cas, les colonnes représentent les think tanks et les lignes les médias. La valeur d’une cellule est le résidu, qu’on obtient grâce à la formule suivante :

\(residu =\frac{valeurObservée - valeurAttendue}{\sqrt(valeurAttendue)}\)

L’idée est la suivante. La valeur attendue est le nombre de fois que chaque think tank serait cité par chaque média si les deux variables étaient indépendantes. Par exemple, si la CBC publiait 10% des articles, on pourrait s’attendre à ce qu’un think tank cité par 50 articles soit cité par 5 articles de la CBC. Le résidu mesure la distance par rapport à cette valeur attendue. Un résidu avec une forte valeur positive signifie que le média en question cite atypiquement plus un think tank que ce à quoi on pourrait s’attendre.

Dans la carte thermique, plus la valeur s’approche du rouge foncé, plus cela indique que ce media cite atypiquement plus un certain think. Plus la valeur s’approche du blanc, plus cela indique que le media cite atypiquement moins un certain think tank. Les medias sont regroupés ensemble s’ils citent atypiquement plus ou atypiquement moins les mêmes think tanks, les think tanks sont regroupés ensemble de manière similaire.

#Fetching the data.

DB_con_for_source <- mongolite::mongo(db = "projetThinkTank", collection = "websites")
query <- '{"stats.domain_authority" : {"$ne" : null}}'
fields <- '{"redirected_website_url" : 1.0, "stats.domain_authority" : 1.0}'
  #fields <- '{"original_website_url" : 1.0,  "redirected_website_url" : 1.0,  "db_website" : 1.0, "stats.domain_authority" : 1.0}'
sort_proc <- '{"stats.domain_authority" : -1}'
dt_on_source <- DB_con_for_source$find(query = query, fields = fields,sort = sort_proc) %>% data.table()


# Cleaning objects
dt_on_source <- dt_on_source[,list(media_url= redirected_website_url, domain_authority=stats)]
media_w_n_tt_refs <- dt_media[,list(media_url,nb_TT_refs = N)] %>% unique()
# join with number of referencs to think tank
setkey(media_w_n_tt_refs,media_url); setkey(dt_on_source,media_url)
dt_on_source <- dt_on_source[media_w_n_tt_refs]

## Agregating sources by root url####

# Renaming in batch
dt_on_source[,root_url:= str_split(str_split(media_url,"://")[[1]][2],pattern = "/")[[1]][1],by=media_url]
# renaming manually:
dt_on_source[grepl("ctvnews.ca",root_url), root_url:= "www.ctvnews.ca"]
dt_on_source[grepl("yahoo.com",root_url), root_url:= "ca.yahoo.com"]
dt_on_source[grepl("vancouversun",root_url), root_url:= "vancouversun.com"]

# The aggregation iself
setkey(dt_on_source, domain_authority)
dt_on_source <- dt_on_source[,list(domain_authority = last(domain_authority),nb_TT_refs = sum(nb_TT_refs)),by= root_url]

top_25 <- dt_on_source[, score := domain_authority^2/10000 * nb_TT_refs][order(-score)] %>% head(25)

#Merging media names so we don't have to use their url
top_25 <- merge(top_25, media_names, by = "root_url")
#Extracting names of TT for plotting purposes
name_TT <- c()
for (i in c(1:nrow(imp_TT)))
{
   name_TT <- c(name_TT, str_split(imp_TT[i]$tt_ID, pattern = "_")[[1]][1])
}
imp_TT <- cbind(imp_TT,name_TT)
imp_TT[name_TT == "ConferenceBoard", name_TT := "ConfBoard"]#this name is too long



#To do a heatmap the data needs to be arranged as a matrix.
#In our case, every row is a media, every column is a TT, a cell will contain the residual.

#First we merge the media table with the TT table
dt_matrix <- merge(dt_media[root_url %in% top_25$root_url], dt_tt_in_mass_media[tt_ID %in% imp_TT$tt_ID], by.x = "_id", by.y = "doc_ID", all.x = TRUE)
dt_matrix <- dt_matrix[!is.na(tt_ID)]

#Then we merge the names
dt_matrix <- merge(dt_matrix, imp_TT, by="tt_ID")
dt_matrix <- merge(dt_matrix, media_names, by = "root_url")
#Then we count how many citations every TT gets from every media
dt_matrix <- dt_matrix[,.N,by = c("media_name", "name_TT")]

#Keeping the total number of citation before spreading
total <- sum(dt_matrix$N)

#To calculate the residual, we need a Expected Value table. The expected value is the number of citation every TT would get from every media if the citation count was uniformely distributed

#We need to know how many TT and media we have in our table to produce the Expected value table
nb_TT <- uniqueN(dt_matrix$name_TT)
nb_media <- uniqueN(dt_matrix$media_name)



#Total number of citation per media
total_media <- dt_matrix[,sum(N), by = media_name]
#Calculating the proportion of citation every media produces in our sample
total_media$proportion <- total_media$V1 / total
#duplicating every row so we can produce the expected value table
total_media <- total_media[rep(seq_len(nrow(total_media)), nb_TT),]

#Same thing with the TT
total_TT <- dt_matrix[,sum(N), by = name_TT]
total_TT <- total_TT[rep(seq_len(nrow(total_TT)), nb_media),]

#Creating the expexted value table
setkey(total_TT, "name_TT")
setnames(total_TT, "V1", "total_pub_TT")
expected_value <- cbind(total_TT, total_media[,list(media_name, proportion)])
#Calculating the expected value
expected_value[,expect_val := proportion * total_pub_TT]
expected_value <- expected_value[,list(name_TT, media_name, expect_val)] %>% unique() %>% data.table()
#Creating the matrix format
expected_value <- spread(expected_value, name_TT, expect_val)
matrix_EV <- data.matrix(expected_value)
#Renaming rows
matrix_EV <- matrix_EV[,2:ncol(matrix_EV)]
rownames(matrix_EV) <- expected_value$media_name


#spreading the data so it has a matrix form
dt_matrix <- spread(dt_matrix, name_TT, N)
#NA must be 0 so we can do the maths
dt_matrix[is.na(dt_matrix)] <- 0
#Changing the format the heatmap function ask for a matrix, not a data frame
matrix <- data.matrix(dt_matrix)
#getting rid of the first col with are the names on the medias
matrix <- matrix[,2:ncol(matrix)]
#putting it back as row names
rownames(matrix) <- dt_matrix$media_name

## Calculating the residual
matrix <- (matrix - matrix_EV) / sqrt(matrix_EV)

#Plotting the heatmap with manhantta distance
heatmap(matrix,scale="column", distfun = function(x) dist(x,method = 'manhattan'))

Un cas intéressant est le Journal de Montréal qui fait une grande place à l’IRIS et à l’IEDM, à un point tel qu’il leur donne un espace de blogue réservé: le Blogue de l’IRIS et le Blogue de l’IEDM. Est-ce que ces articles de blogues contribuent à une grande partie des mentions des deux think tanks dans ce média?

# Focus on JdM
id_JdM <-  dt_media[grepl("journaldemontreal",media_url), "_id"] %>% unlist
# Focus more specifically on IEDM and IRIS
dt_mention_level_JdM <- dt_tt_in_mass_media[doc_ID %in% id_JdM & tt_ID %in% c("IEDM_TT","IRIS_TT")]

# Fetch the urls from MongoDB
DB_connection <- mongolite::mongo(db = "projetThinkTank", collection = "articles")
query <- paste0('{"_id" : {"$in" :  [{"$oid": "', paste(unique(dt_mention_level_JdM$doc_ID), collapse = '"}
                ,{"$oid":"'),"\"}]}}")
fields <- '{"redirected_article_url" : true}'
dt_JdM <- DB_connection$find(query = query, fields = fields) %>% data.table()

# Now, we want to do some extra scraping because there is no clear indication 
# in the database that a source is from the blog although the full html has section metadata flagging that.
for(i in 1:nrow(dt_JdM)){
  the_url <-  dt_JdM[i,redirected_article_url]
  the_href <- tryCatch( {
              webpage <- read_html(the_url)
              html_nodes(webpage, '.header-groupe-blog>a:nth-child(1)') %>% html_attr("href") 
    },
        error=function(cond) {
            message(paste("URL does not seem to exist:", the_url))
            message("Here's the original error message:")
            message(cond)
            return(NULL)
        },
        warning=function(cond) {
            message(paste("URL caused a warning:", the_url))
            message("Here's the original warning message:")
            message(cond)
            return(NULL)
        },
        finally=  message(paste("Processed URL number", i, "out of",nrow(dt_JdM)))
        )
  
  if(length(the_href)==0){
   the_href <- "Autre source" 
  }
  dt_JdM[i,Source:= the_href]
}

# Counting the different sources
dt_JdM[grepl("blogues/iris",Source),Source := "Blogue de l'IRIS"]
dt_JdM[grepl("blogues/iedm",Source),Source := "Blogue de l'IEDM"]
dt_JdM[grepl("blogues",Source),Source := "Autre source"] # autre entrée de blogue non reliée aux TT

dt_JdM_final <- merge(dt_mention_level_JdM[,list(doc_ID, cited_TT = tt_short_to_use)], dt_JdM[,list(doc_ID = get("_id"), Source)], by= "doc_ID", all.x= TRUE)
setkey(dt_JdM_final,cited_TT,Source)
dt_JdM_final <-  dt_JdM_final[,list(nombre_cit = .N),.(cited_TT,Source)]
dt_JdM_final <- dt_JdM_final[,list(Source,nombre_cit, prop_de_TT = round(nombre_cit/sum(nombre_cit),2)),cited_TT]

save(dt_JdM_final, file = "/data/Think_tank/Media/mass_media/source_cit_IRIS_IEDM_dans_JdeM.RData")
load("/data/Think_tank/Media/mass_media/source_cit_IRIS_IEDM_dans_JdeM.RData") 
dt_JdM_final  %>% kable(caption = "") %>%
  kable_styling(fixed_thead = T)# %>%
cited_TT Source nombre_cit prop_de_TT
IEDM Autre source 115 0.80
IEDM Blogue de l’IEDM 23 0.16
IEDM Blogue de l’IRIS 5 0.03
IRIS Autre source 108 0.79
IRIS Blogue de l’IEDM 1 0.01
IRIS Blogue de l’IRIS 28 0.20
  #scroll_box(width = "800px", height = "360px")

Les mentions dans les deux blogues comptent pour 20% des mentions de ces deux think tanks dans le Journal de Montréal.

5.1 Autres représentations de la relation préférentielle entre think tanks et médias

5.1.1 Quels sont les think tanks les plus cités par les médias québécois?

most_cited_TT_in_media <- function(name, dt_media, dt_think_tanks, col_id_media, col_id_think_tank)
{
  #This function plot the most cited think tanks by a given media.
  #Arguments : 
  #   name - the name of the media as it appears it its url.
  #   dt_media - a data.table with two columns. One with ids of articles, and the other one with the url of the media it is                   published in
  #   dt_think_tanks - a data.tble with two columns. On with ids of articles, and the other one with the names of a                                 think tank the article mentions
  #   col_id_media : how the column of ids is named in dt_media
  #   col_id_think_tank : how the column of ids is named in dt_think_tanks.
  
  dt_tt <- merge(dt_think_tanks, dt_media, by.x = col_id_think_tank, by.y = col_id_media, all.x = TRUE)
  dt_tt <- dt_tt[grepl(name, root_url)]
  dt_tt <- dt_tt[, .N, by = "tt_ID"]
  dt_tt <- merge(dt_tt, tt_names, by = "tt_ID")
  ggplot(dt_tt, aes(x = reorder(tt_short_to_use, N), y = N)) + geom_bar(stat = "identity") + coord_flip() + ggtitle(paste0("Think tanks les plus cités par ", name)) + ylab("Nombre d'articles") + xlab("Think tanks")
  
}
most_cited_TT_in_media("lapresse", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("journaldemontreal", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("ledevoir", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("radio-canada", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("montrealgazette", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

5.1.2 Quels sont les tinks tanks les plus cités dans le ROC?

most_cited_TT_in_media("cbc", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("globeandmail", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("theprovince", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("calgaryherald", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_cited_TT_in_media("nationalpost", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

5.1.3 Qui citent les think tanks?

Quels médias citent certains des thinks tanks les plus infuents?

most_citing_media_for_TT <- function(think_tank_id, dt_media, dt_think_tanks, col_id_media, col_id_think_tank)
{
  #This function plot what medias cites a given think tank the most.
  #Arguments : 
  #   think_tank_id - the identifier of the think tank, for example "Fraser_TT".
  #   dt_media - a data.table with two columns. One with ids of articles, and the other one with the url of the media it is                   published in
  #   dt_think_tanks - a data.tble with two columns. On with ids of articles, and the other one with the names of a                                 think tank the article mentions
  #   col_id_media : how the column of ids is named in dt_media
  #   col_id_think_tank : how the column of ids is named in dt_think_tanks.
  
  dt_med <- merge(dt_think_tanks, dt_media, by.x = col_id_think_tank, by.y = col_id_media, all.x = TRUE)
  dt_med <- dt_med[tt_ID == think_tank_id]
  dt_med <- dt_med[, .N, by = "root_url"]
  first_10 <- dt_med[!is.na(root_url),list(root_url, N)][order(-N)] %>% unique() %>% head(10)
  ggplot(dt_med[root_url %in% first_10$root_url], aes(x = reorder(root_url, N), y = N)) + geom_bar(stat = "identity") + coord_flip() + ggtitle(paste0("Média citant le plus : ", think_tank_id))
  
}
most_citing_media_for_TT("ConferenceBoard_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("Fraser_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("Pembina_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("CDHowe_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("CCPA_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("IEDM_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")

most_citing_media_for_TT("IRIS_TT", dt_media, dt_tt_in_mass_media, "_id", "doc_ID")