Понимание динамики Twitter с помощью R и Gephi: анализ текста и центральность

Опубликовано: 2022-07-22

Эта статья расширяет и углубляет анализ, представленный в первой части нашей серии анализов социальных сетей. Мы используем тот же набор данных Twitter и сеть взаимодействия, которые были созданы в первой статье. Однако на этот раз идея состоит в том, чтобы лучше определить основных действующих лиц, определить их темы для обсуждения и понять, как эти темы распространяются.

Центральность социальных сетей

Для достижения наших целей сначала нам нужно ввести понятие центральности . В науке о сетях центральность относится к узлам, которые имеют сильное влияние на сеть. Влияние — неоднозначное понятие; это можно понять по-разному. Является ли узел с большим количеством ребер более влиятельным, чем узел с меньшим количеством ребер, но более «важными»? Что является важным преимуществом в социальной сети?

Чтобы устранить эти неясности, сетевые ученые разработали множество показателей центральности. Здесь мы обсудим четыре часто используемых меры, хотя доступно гораздо больше.

Степень

Наиболее распространенной и интуитивно понятной мерой является степень центральности. Идея центральности по степени проста: измеряйте влияние по степени узла. Может иметь варианты, если граф направленный; в этом случае вы можете измерить входящую и исходящую степень — первая известна как оценка центра, а вторая — как оценка авторитета.

В первой части этой серии мы использовали ненаправленный подход. На этот раз мы сосредоточимся на подходе в степени. Это позволяет проводить более точный анализ, выделяя пользователей, которых другие ретвитят, по сравнению с пользователями, которые просто часто ретвитят.

собственный вектор

Мера собственного вектора основана на степени центральности. Чем больше влиятельных узлов указывает на данный узел, тем выше его оценка. Мы начинаем с матрицы смежности , где строки и столбцы представляют узлы, и мы используем 1 или 0, чтобы указать, связаны ли соответствующие узлы данной строки и столбца. Основной расчет оценивает собственные векторы матрицы. Главный собственный вектор будет содержать нужные нам меры центральности, где позиция i будет содержать показатель центральности узла i .

PageRank

PageRank — это вариант меры собственного вектора, лежащий в основе Google. Точный метод, который использует Google, неизвестен, но общая идея заключается в том, что каждый узел начинает с оценки 1, а затем распределяет свою оценку равными частями по каждому из своих ребер. Например, если от узла отходят три ребра, он «отправляет» одну треть своей оценки через каждое ребро. В то же время узел становится более важным из-за ребер, указывающих на него. Это приводит к разрешимой системе N уравнений с N неизвестными.

Посредничество

Четвертая мера, промежуточность , использует совсем другой подход. Здесь узел считается влиятельным, если он включен во множество коротких путей между другими узлами. То есть он отвечает за связь со многими другими узлами, соединяя «разные миры».

Например, в анализе социальных сетей такие типы узлов можно понимать как типы людей, которые помогают другим найти новую работу или завязать новые связи — они являются дверьми в ранее неизвестные социальные круги.

Что я должен использовать?

Соответствующая мера центральности зависит от цели вашего анализа. Вы хотите знать, какие пользователи часто выделяются другими с точки зрения количества? Центральность по степени, вероятно, будет вашим лучшим вариантом. Или вы предпочитаете меру центральности, учитывающую качество? В этом случае собственный вектор или PageRank дадут лучшие результаты. Если вы хотите знать, какие пользователи наиболее эффективно функционируют в качестве мостов между различными сообществами, промежуточность — ваш лучший вариант.

При использовании нескольких одинаковых показателей, например, собственного вектора и PageRank, вы можете оценить их все и посмотреть, дают ли они эквивалентные рейтинги. Если нет, вы можете углубить свой анализ различий или создать новую меру, объединив их оценки.

Другой подход использует анализ основных компонентов, чтобы оценить, какая мера дает вам больше информации о реальном влиянии узлов на вашу сеть.

Практический расчет центральности

Давайте посмотрим, как мы можем рассчитать эти показатели с помощью R и RStudio. (Их также можно сделать с помощью Gephi.)

Во-первых, нам нужно загрузить все библиотеки, которые мы будем использовать в этой статье:

 library("plyr") library(igraph) library(tidyverse) library(NLP) library("tm") library(RColorBrewer) library(wordcloud) library(topicmodels) library(SnowballC) library("textmineR")

Далее мы удалим изолированные узлы из данных, которые мы использовали ранее, так как они бесполезны для этого анализа. Затем мы будем использовать функции igraph betweenness , centr_eigen , page_rank и degree для оценки показателей центральности. Наконец, мы будем хранить оценки в объекте igraph и во фрейме данных, чтобы увидеть, какие пользователи были наиболее важными.

 load("art1_tweets.RData") Isolated = which(degree(net)==0) net_clean = delete.vertices(net, Isolated) cent<-data.frame(bet=betweenness(net_clean),eig=centr_eigen(net_clean)$vector,prank=(page_rank(net_clean)$vector),degr=degree(net_clean, mode="in")) cent <- cbind(account = rownames(cent), cent)

Теперь мы можем проверить 10 самых центральных пользователей по каждому показателю:

Степень
 top_n(cent, 10 ,degr)%>% arrange(desc(degr))%>% select(degr)
собственный вектор
 top_n(cent, 10 ,eig)%>% arrange(desc(eig))%>% select(eig)
PageRank
 top_n(cent, 10 ,prank)%>% arrange(desc(prank))%>% select(prank)
Посредничество
 top_n(cent, 10 ,bet)%>% arrange(desc(bet))%>% select(bet)

Результаты, достижения:

Степень собственный вектор PageRank Посредничество
ЕСПНФК 5892 ПСЖ_внутри 1 мундодабола 0,037 взглядыдей 77704
Футбольный троль 5755 CrewsMat19 0,51 АлеЛипароти 0,026 ЭдмундОрис 76425
ПСЖ_внутри 5194 eh01195991 0,4 ПСЖ_внутри 0,017 бас***лла 63799
CrewsMat19 4344 Мохаммад135680 0,37 РойНемер 0,016 ФрансискоГайус 63081
брфутбол 4054 ActuFoot_ 0,34 Футбольный троль 0,013 Йемихазан 62534
PSG_espanol 3616 Мартвалл 0,34 ЕСПНФК 0,01 хэштег2weet 61123
ИбайАут 3258 ЕСПНФК 0,3 PSG_espanol 0,007 Анжела_FCB 60991
ActuFoot_ 3175 брфутбол 0,25 InstantFoot 0,007 Zyyon_ 57269
МутныйЮмор 2976 СейлорЛунаАрмия 0,22 ИбайАут 0,006 CrewsMat19 53758
мундодабола 2778 ДжонсвиллПэт 0,2 2010МистерЧип 0,006 МдинОлавале 49572

Мы видим, что первые три показателя имеют общее количество пользователей, таких как PSG_inside, ESPNFC, CrewsMat19 и TrollFootball. Можно предположить, что они оказали сильное влияние на дискуссию. Промежуточность имеет другой подход к измерению центральности и поэтому не показывает такого большого совпадения с другими методами.

Примечание. Мнения, выраженные учетными записями Twitter, упомянутыми в этой статье, не отражают точку зрения Toptal или автора.

На следующих изображениях вы можете увидеть наш исходный цветной сетевой график с двумя наложенными пользовательскими метками. В первом случае узлы выделены их показателями PageRank, а во втором — их показателями промежуточности:

Изображение, показывающее цветной график PageRank с выделенными 10 ведущими пользователями и их сетями. Тремя крупнейшими пользователями являются PSG_inside, TrollFootball и ESPNFC. ESPNFC расположен слева от графика и окрашен в фиолетовый цвет, а PSG_inside — справа от него и окрашен в красный цвет. TrollFootball расположен выше и правее от них, между зелеными, синими и оранжевыми пользователями.
Обсуждение Месси с 10 лучшими пользователями PageRank выделено

Изображение, показывающее цветной график промежуточности, на котором отмечены и выделены первые 10 пользователей и их сети. Все первые 10 пользователей, которые больше похожи по размеру, чем на предыдущем изображении, расположены в левом нижнем углу изображения, окрашенного в фиолетовый цвет. Они плотно сгруппированы.
Выделено обсуждение Месси с 10 лучшими пользователями посредничества

Gephi можно использовать для воспроизведения этих изображений. Вы можете оценить промежуточность или баллы PageRank, используя кнопку Network Diameter на панели статистики. Затем вы можете отображать имена узлов, используя атрибуты, как показано в первой части этой серии.

Анализ текста: R и LDA

Мы также можем анализировать обсуждения в социальных сетях, чтобы определить, о чем говорили пользователи. Есть несколько подходов к этому. Мы будем проводить тематическое моделирование с помощью скрытого распределения Дирихле (LDA), метода машинного обучения без учителя, который позволяет нам оценить, какой набор слов обычно появляется вместе. Затем с помощью этого набора слов мы можем вывести обсуждаемую тему.

Первый шаг — очистка текста. Для этого определим следующую функцию:

 # This function normalizes text by removing Twitter-related terms and noisy characters sanitize_text <- function(text) { # Convert to ASCII to remove accented characters: text <- iconv(text, to = "ASCII", sub = " ") # Move to lower case and delete RT word (this is added by Twitter) text <- gsub("rt", " ", tolower(text)) # Delete links and user names: text <- gsub("@\\w+", " ", gsub("http.+ |http.+$", " ", text)) # Delete tabs and punctuation: text <- gsub("[ |\t]{2,}", " ", gsub("[[:punct:]]", " ", text)) text <- gsub("amp", " ", text) # Remove HTML special character # Delete leading and lagging blanks: text <- gsub("^ ", "", gsub(" $", "", text)) text <- gsub(" +", " ", text) # Delete extra spaces return(text) }

Нам также необходимо удалить стоп-слова, дубликаты и пустые записи. Затем мы должны преобразовать наш текст в матрицу терминов документа для обработки LDA.

В этом наборе данных у нас есть пользователи, говорящие на многих языках (английский, испанский, французский и т. д.). LDA работает лучше всего, если мы сосредоточимся на одном языке. Мы собираемся применить его к пользователям самого большого сообщества, обнаруженного в первой части этой серии, которое состоит в основном из учетных записей с англоязычными пользователями.

 # Detect communities: my.com.fast <-cluster_louvain(as.undirected(simplify(net))) largestCommunities <- order(sizes(my.com.fast), decreasing=TRUE)[1:3] # Save the usernames of the biggest community: community1 <- names(which(membership(my.com.fast) == largestCommunities[1])) # Sanitize the text of the users of the biggest community: text <- unique(sanitize_text(tweets.df[which(tweets.df$screen_name %in% community1),]$text)) text = text[text!=''] # Delete empty entries stopwords_regex = paste(stopwords('es'), collapse = '\\b|\\b') stopwords_regex = paste0('\\b', stopwords_regex, '\\b') # Remove English stopwords: text = stringr::str_replace_all(text, stopwords_regex, '') # Create the document term matrix: dtm <- CreateDtm(text, doc_names = seq(1:length(text)), ngram_window = c(1, 2))

Подсчет тем и оценка согласованности

Основной гиперпараметр, который нам нужно определить в LDA, — это количество (k) тем, которые мы хотим оценить. Однако как мы можем знать это заранее? Один из распространенных подходов заключается в обучении моделей LDA для разных значений k и измерении когерентности каждого из них. Мы сделаем это для значений k от 3 до 20, поскольку, по моему опыту, значения за пределами этого диапазона проверять не стоит:

 tf <- TermDocFreq(dtm = dtm) # Remove infrequent words: tf_trimmed = tf$term[ tf$term_freq > 1 & tf$doc_freq < nrow(dtm) / 2 ] # Create a folder to store trained models: model_dir <- paste0("models_", digest::digest(tf_trimmed, algo = "sha1")) if (!dir.exists(model_dir)) dir.create(model_dir) # Define a function to infer LDA topics: train_lda_model <- function(number_of_topics){ filename = file.path(model_dir, paste0(number_of_topics, "_topics.rda")) # Check if the model already exists: if (!file.exists(filename)) { # To get exactly the same output on each run, use a constant seed: set.seed(12345) lda_model = FitLdaModel(dtm = dtm, k = number_of_topics, iterations = 500) lda_model$k = number_of_topics lda_model$coherence = CalcProbCoherence(phi = lda_model$phi, dtm = dtm, M = 5) save(lda_model, file = filename) } else { load(filename) } lda_model } # The number of topics that we are going to infer in each LDA training run: topic_count = seq(3, 20, by = 1) # Train through the TmParallelApply function models = TmParallelApply(X = topic_count, FUN = train_lda_model, export = c("dtm", "model_dir"))

Далее мы наносим на график значение когерентности каждого:

 coherence_by_topics_quantity = data.frame( topic_number = sapply(models, function(model_instance) nrow(model_instance$phi)), score_coherence = sapply(models, function(model_instance) mean(model_instance$coherence)), stringsAsFactors = FALSE) ggplot(coherence_by_topics_quantity, aes(x = topic_number, y = score_coherence)) + geom_point() + geom_line(group = 1) + ggtitle("Coherence by Topic") + theme_minimal() + scale_x_continuous(breaks = seq(1,20,1)) + ylab("Coherence Score") + xlab("Number of topics")

Высокое значение когерентности показывает лучшую сегментацию текста на темы:

График, показывающий оценку согласованности для разных тем. Показатель согласованности варьируется от чуть более 0,05 по шести-семи темам, при этом по всем темам от трех до двенадцати оценка ниже 0,065. Оценка внезапно достигает пика около 0,105 по 13 темам. Затем он опускается ниже 0,06 для 17 тем, почти до 0,09 для 19 тем и заканчивается чуть выше 0,07 для 20 тем.

Мы достигаем пика согласованности при k = 13, поэтому будем использовать модель LDA, обученную по 13 темам. С помощью функции GetTopTerms мы можем увидеть 10 основных слов для каждой темы и через них оценить семантику темы:

 best_model <- models[which.max(coherence_by_topics_quantity$score_coherence)][[ 1 ]] # Most important terms by topic: best_model$top_terms <- GetTopTerms(phi = best_model$phi, M = 20) top10 <- as.data.frame(best_model$top_terms) top10

В следующей таблице подробно описаны пять наиболее важных обнаруженных тем и 10 основных слов, которые их иллюстрируют:

t_1 т_2 т_3 т_4 т_5
1 Месси Месси Месси Месси Месси
2 Лайонел инстаграм лига стандартное восточное время псж
3 Лионель Месси почта победить иль Лео
4 псж миллион цели ау leo_messi
5 Мадрид нравится ч налить ахора
6 настоящий спо ионы па компа
7 барселона козел ch_ions авек ва
8 Париж псж УКЛ дю сер
9 Реал Мадрид бар баллон куй югадор
10 mbapp больше Мир Дже старший

Хотя большинство пользователей в этом сообществе говорят по-английски, все еще есть несколько носителей французского и испанского языков (t_4 и t_5 в таблице). Мы можем сделать вывод, что первая тема связана с предыдущей командой Месси (ФК «Барселона»), вторая тема касается поста Месси в Instagram, а третья тема посвящена достижениям Месси.

Теперь, когда у нас есть темы, мы можем предсказать, какая из них была наиболее обсуждаемой. Для этого мы сначала объединим твиты пользователей (опять же, из самого большого сообщества):

 tweets.df.com1 = tweets.df[which(tweets.df$screen_name %in% community1),] users_text <- ddply(tweets.df.com1, ~screen_name, summarise, text = paste(text, collapse = " "))

Затем мы очищаем текст, как и раньше, и создаем DTM. После этого мы вызываем функцию predict , используя нашу модель LDA и DTM в качестве аргументов. Кроме того, мы установили метод Гиббса, чтобы сократить время вычислений, потому что нам нужно проанализировать много текста:

 users_text$text <- sanitize_text(users_text$text) # Get rid of duplicates stopwords_regex = paste(stopwords('en'), collapse = '\\b|\\b') stopwords_regex = paste0('\\b', stopwords_regex, '\\b') users_text$text = stringr::str_replace_all(users_text$text, stopwords_regex, '') dtm.users.com1 <- CreateDtm(users_text$text, doc_names = users_text$screen_name, ngram_window = c(1, 2)) com1.users.topics = predict(best_model, dtm.users.com1, method="gibbs", iterations=100)

Теперь во фрейме данных com1.users.topics мы видим, сколько каждый пользователь говорил по каждой теме:

Счет t_1 т_2 т_3 т_4 т_5 […]
___99-й 0,02716049 0,86666666 0,00246913 0,00246913 0,00246913
Босс__ 0,05185185 0,84197530 0,00246913 0,00246913 0,00246913
Мемфис 0,00327868 0,00327868 0,03606557 0,00327868 0,00327868
___Алекс1 0,00952380 0,00952380 0,00952380 0,00952380 0,00952380
[…]

Наконец, с помощью этой информации мы можем создать новый атрибут на диаграмме узлов, чтобы определить, какая тема больше всего обсуждалась каким пользователем. Затем мы можем создать новый файл GML, чтобы визуализировать его в Gephi:

 # Get the subgraph of the first community: net.com1 = induced_subgraph(net,community1) # Estimate the topic with the max score for each user: com1.users.maxtopic = cbind(users_text$screen_name, colnames(com1.users.topics)[apply(com1.users.topics, 1, which.max)]) # Order the users topic data frame by the users' order in the graph: com1.users.maxtopic = com1.users.maxtopic[match(V(net.com1)$name, com1.users.maxtopic[,1]),] # Create a new attr of the graph by the topic most discussed by each user: V(net.com1)$topic = com1.users.maxtopic[,2] # Create a new graph: write_graph(simplify(net.com1), "messi_graph_topics.gml", format = "gml") 

Цветной граф узлов, сгенерированный с помощью Gephi, показывает ESPNFC как пользователя с самым высоким рейтингом по централизации PageRank. ESPNFC расположен в нижней части изображения, под ним сгруппировано множество фиолетовых узлов.
Крупнейшее сообщество обсуждения Месси, окрашенное по темам и с пользователями, отмеченными центральным положением PageRank.

Изображение, показывающее процент пользователей, выделенных каждым цветом, используемым на графике, причем фиолетовый «t 6» является наиболее часто используемым цветом (40,53% всех пользователей на графике), за которым следует зеленый «t 13» с 11,02. %, а синий/голубой «t 10» — 9,68 %. Серый «NA», занимающий предпоследнюю позицию в этом списке из 11, составляет 2,25%.
Метки тем и процент пользователей для каждого цвета, используемого на диаграмме

Определение важных тем и применение центральности в социальных сетях

В первой части этой серии мы узнали, как получать данные из Twitter, создавать граф взаимодействия, отображать его с помощью Gephi и обнаруживать сообщества и важных пользователей. В этой части мы расширили этот анализ, продемонстрировав использование дополнительных критериев для выявления влиятельных пользователей. Мы также продемонстрировали, как обнаруживать и делать выводы о том, о чем говорили пользователи, и отображать это в сети.

В нашей следующей статье мы продолжим углублять этот анализ, показав, как пользователи могут обнаружить бич социальных сетей: спам-ботов и троллей.

Дальнейшее чтение в блоге Toptal Engineering:

  • Анализ социальных сетей с помощью Power BI и R: Руководство по пользовательским визуальным элементам