Zrozumienie dynamiki Twittera za pomocą R i Gephi: analiza i centralność tekstu

Opublikowany: 2022-07-22

Ten artykuł rozwija i pogłębia analizę przedstawioną w pierwszej części naszej serii analiz sieci społecznościowych. Korzystamy z tego samego zestawu danych i sieci interakcji Twittera, które zostały skonstruowane w pierwszym artykule. Jednak tym razem chodzi o lepsze wywnioskowanie głównych aktorów, zidentyfikowanie ich tematów do dyskusji i zrozumienie, w jaki sposób te tematy się rozprzestrzeniają.

Centralna sieć społecznościowa

Aby osiągnąć nasze cele, najpierw musimy wprowadzić pojęcie centralności . W nauce o sieciach centralność odnosi się do węzłów, które mają silny wpływ na sieć. Wpływ jest pojęciem niejednoznacznym; można to rozumieć na wiele sposobów. Czy węzeł z wieloma krawędziami ma większy wpływ niż węzeł z mniejszą liczbą, ale bardziej „ważnych” krawędzi? Co stanowi ważną przewagę w sieci społecznościowej?

Aby rozwiązać te niejasności, naukowcy sieci opracowali wiele miar centralności. W tym miejscu omówimy cztery powszechnie stosowane miary, choć dostępnych jest znacznie więcej.

Stopień

Najbardziej powszechną i intuicyjną miarą jest centralność stopni. Idea centralności stopni jest prosta: zmierz wpływ stopniem węzła. Może mieć warianty, jeśli wykres jest skierowany; w takim przypadku możesz zmierzyć stopień wejściowy i stopień wyjściowy — pierwszy jest znany jako wynik centralny, a drugi jako wynik autorytetu.

W pierwszej odsłonie tej serii zastosowaliśmy podejście nieukierunkowane. Tym razem skupiamy się na podejściu stopniowym. Pozwala to na dokładniejszą analizę, kładąc nacisk na użytkowników, którzy są retweetowani przez innych, na użytkowników, którzy po prostu retweetują często.

Wektor własny

Miara wektora własnego opiera się na centralności stopnia. Im więcej wpływowych węzłów wskazuje na dany węzeł, tym wyższy jest jego wynik. Zaczynamy od macierzy sąsiedztwa , w której wiersze i kolumny reprezentują węzły i używamy 1 lub 0, aby wskazać, czy odpowiednie węzły danego wiersza i kolumny są połączone. Główne obliczenie szacuje wektory własne macierzy. Główny wektor własny będzie zawierał miary centralności, które chcemy, gdzie pozycja i będzie zawierała wynik centralności węzła i .

PageRank

PageRank to odmiana miary wektora własnego w rdzeniu Google. Dokładna metoda stosowana przez Google jest nieznana, ale ogólna idea polega na tym, że każdy węzeł zaczyna się z wynikiem 1, a następnie rozdziela swój wynik w równych częściach na każdą ze swoich krawędzi. Na przykład, jeśli węzeł ma trzy wystające z niego krawędzie, „przesyła” jedną trzecią swojego wyniku przez każdą krawędź. Jednocześnie węzeł jest ważniejszy przez krawędzie, które na niego wskazują. Daje to rozwiązywalny układ N równań z N niewiadomymi.

Pomiędzy

Czwarta miara, pośredniość , wykorzystuje zupełnie inne podejście. Tutaj mówi się, że węzeł ma wpływ, jeśli znajduje się na wielu krótkich ścieżkach między innymi węzłami. Oznacza to, że odpowiada za komunikację z wieloma innymi węzłami, łącząc „różne światy”.

Na przykład w analizie sieci społecznościowych tego rodzaju węzły można rozumieć jako typy ludzi, którzy pomagają innym znaleźć nową pracę lub nawiązać nowe kontakty — są to drzwi do nieznanych wcześniej kręgów społecznych.

Którego powinienem użyć?

Odpowiednia miara centralności zależy od celu analizy. Chcesz wiedzieć, którzy użytkownicy są często wyróżniani przez innych pod względem ilości? Centralność stopnia prawdopodobnie byłaby najlepszą opcją. A może wolisz centralną miarę uwzględniającą jakość? W takim przypadku wektor własny lub PageRank dadzą lepsze wyniki. Jeśli chcesz wiedzieć, którzy użytkownicy działają najskuteczniej jako pomosty między różnymi społecznościami, najlepszą opcją jest pośrednictwo.

Używając wielu podobnych miar, np. wektora własnego i PageRank, możesz oszacować je wszystkie i sprawdzić, czy dają równoważne rankingi. Jeśli nie, możesz pogłębić analizę różnic lub wygenerować nową miarę, łącząc ich wyniki.

Inne podejście wykorzystuje analizę głównych komponentów do oszacowania, która miara daje więcej informacji o rzeczywistym wpływie węzłów na twoją sieć.

Praktyczne obliczanie centralności

Zobaczmy, jak możemy obliczyć te miary za pomocą R i RStudio. (Można to również zrobić za pomocą Gephi.)

Najpierw musimy załadować wszystkie biblioteki, których będziemy używać w tym artykule:

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

Następnie usuniemy izolowane węzły z danych, których używaliśmy wcześniej, ponieważ nie są one przydatne do tej analizy. Następnie użyjemy funkcji igraph betweenness , centr_eigen , page_rank , i degree do oszacowania miar centralności. Na koniec przechowamy wyniki w obiekcie igraph i w ramce danych, aby zobaczyć, którzy użytkownicy byli najbardziej centralni.

 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)

Teraz możemy sprawdzić 10 najbardziej centralnych użytkowników według każdej miary:

Stopień
 top_n(cent, 10 ,degr)%>% arrange(desc(degr))%>% select(degr)
Wektor własny
 top_n(cent, 10 ,eig)%>% arrange(desc(eig))%>% select(eig)
PageRank
 top_n(cent, 10 ,prank)%>% arrange(desc(prank))%>% select(prank)
Pomiędzy
 top_n(cent, 10 ,bet)%>% arrange(desc(bet))%>% select(bet)

Wyniki:

Stopień Wektor własny PageRank Pomiędzy
ESPNFC 5892 PSG_wewnątrz 1 mundodabola 0,037 widokidey 77704
TrollPiłka Nożna 5755 ZałogiMat19 0,51 AleLiparoti 0,026 Edmund Oris 76425
PSG_wewnątrz 5194 eh01195991 0,4 PSG_wewnątrz 0,017 ba*****lla 63799
ZałogiMat19 4344 mohammad135680 0,37 RoyNemer 0,016 Francisco Gaius 63081
brfutbol 4054 AktuStopa_ 0,34 TrollPiłka Nożna 0,013 Jemihazan 62534
PSG_espanol 3616 marttvall 0,34 ESPNFC 0,01 hashtag2weet 61123
IbaiOut 3258 ESPNFC 0,3 PSG_espanol 0,007 Angela_FCB 60991
AktuStopa_ 3175 brfutbol 0,25 Natychmiastowa stopa 0,007 Zjon_ 57269
FootyHumour 2976 SaylorMoonArmy 0,22 IbaiOut 0,006 ZałogiMat19 53758
mundodabola 2778 JohnsvillPat 0,2 2010MisterChip 0,006 MdeenOlawale 49572

Widzimy, że pierwsze trzy miary mają wspólną liczbę użytkowników, takich jak PSG_inside, ESPNFC, CrewsMat19 i TrollFootball. Można przypuszczać, że mieli duży wpływ na dyskusję. Pomiędzy ma inne podejście do mierzenia centralności i dlatego nie wykazuje tak dużego pokrywania się z innymi technikami.

Uwaga: Poglądy wyrażane przez konta na Twitterze wymienione w tym artykule nie odzwierciedlają poglądów Toptala ani autora.

Na poniższych obrazach możesz zobaczyć nasz oryginalny kolorowy wykres sieci z dwiema nakładkami etykiet użytkownika. W pierwszym węzły są wyróżnione przez ich wyniki PageRank, a w drugim przez ich wyniki pośrednie:

Obraz przedstawiający kolorowy wykres PageRank z wyróżnionymi 10 najlepszymi użytkownikami i ich sieciami. Trzech największych użytkowników to PSG_inside, TrollFootball i ESPNFC. ESPNFC znajduje się po lewej stronie fabuły i jest w kolorze fioletowym, a PSG_inside po prawej stronie, w kolorze czerwonym. TrollFootball znajduje się wyżej i na prawo od nich, pomiędzy użytkownikami w kolorze zielonym, niebieskim i pomarańczowym.
Dyskusja Messiego z 10 wyróżnionymi użytkownikami PageRank

Obraz przedstawiający kolorowy wykres pomiędzy, z oznaczonymi i wyróżnionymi 10 największymi użytkownikami i ich sieciami. Wszyscy z 10 najlepszych użytkowników, którzy są bardziej zbliżeni pod względem wielkości niż na poprzednim obrazie, znajdują się w lewym dolnym rogu obrazu, który jest pomalowany na fioletowo. Są ciasno zgrupowane.
Dyskusja Messiego z 10 najlepszymi wyróżnionymi użytkownikami pośrednictwa

Gephi można wykorzystać do odtworzenia tych obrazów. Możesz oszacować wyniki pośrednie lub PageRank za pomocą przycisku Średnica sieci w panelu statystyk. Następnie możesz pokazać nazwy węzłów za pomocą atrybutów, jak pokazano w pierwszej części z tej serii.

Analiza tekstu: R i LDA

Możemy również analizować dyskusje w sieciach społecznościowych, aby zidentyfikować, o czym rozmawiali użytkownicy. Można do tego podejść na wiele sposobów. Zajmiemy się modelowaniem tematów za pomocą Latent Dirichlet Allocation (LDA), nienadzorowanej techniki uczenia maszynowego, która pozwala nam oszacować, który zestaw słów pojawia się razem. Następnie za pomocą tego zestawu słów możemy wywnioskować omawiany temat.

Pierwszym krokiem jest oczyszczenie tekstu. W tym celu definiujemy następującą funkcję:

 # 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) }

Musimy również usunąć słowa stop, duplikaty i puste wpisy. Następnie musimy przekonwertować nasz tekst na macierz dokumentu-terminów, która ma być przetworzona przez LDA.

W tym zestawie danych mamy użytkowników mówiących w wielu językach (angielskim, hiszpańskim, francuskim itp.). LDA działa najlepiej, jeśli skupimy się na jednym języku. Zamierzamy ją zastosować na użytkownikach największej społeczności wykrytej w pierwszej odsłonie tej serii, która składa się głównie z kont użytkowników anglojęzycznych.

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

Liczba tematów i wyniki spójności

Głównym hiperparametrem, który musimy zdefiniować w LDA, jest liczba (k) tematów, które chcemy oszacować. Skąd jednak możemy to wiedzieć wcześniej? Jednym z powszechnych podejść jest trenowanie modeli LDA na różnych wartościach k i mierzenie spójności każdej z nich. Zrobimy to dla wartości k od 3 do 20, ponieważ z mojego doświadczenia wynika, że ​​wartości spoza tego zakresu nie są warte sprawdzania:

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

Następnie wykreślamy wartość koherencji każdego z nich:

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

Wysoka wartość spójności świadczy o lepszej segmentacji tekstu na tematy:

Wykres przedstawiający wynik spójności dla różnych tematów. Wynik spójności waha się od nieco ponad 0,05 dla sześciu do siedmiu tematów, przy czym trzy do dwunastu tematów mają wynik poniżej 0,065. Wynik nagle osiąga szczyt około 0,105 dla 13 tematów. Następnie spada poniżej 0,06 dla 17 tematów, do prawie 0,09 dla 19 tematów, a kończy na nieco powyżej 0,07 dla 20 tematów.

Szczytowy wynik koherencji osiągamy przy k = 13, więc użyjemy modelu LDA wytrenowanego na 13 tematach. Dzięki funkcji GetTopTerms możemy zobaczyć 10 głównych słów dla każdego tematu i oszacować za ich pomocą semantykę tematu:

 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

W poniższej tabeli wyszczególniono pięć najważniejszych wykrytych tematów i 10 głównych słów, które je ilustrują:

t_1 t_2 t_3 t_4 t_5
1 Messi Messi Messi Messi Messi
2 lionel Instagram liga oszacować psg
3 Lionel Messi Poczta wygrać il Lew
4 psg milion cele Au Leo Messi
5 Madryt lubi ch wlać ahora
6 prawdziwy spo jony pierwszeństwo kompania
7 Barcelona koza ch_jony avec wa
8 Paryż psg ucl du ser
9 Real Madryt bar balon Qui jugador
10 mbapp większy świat je mejor

Chociaż większość użytkowników w tej społeczności to osoby posługujące się językiem angielskim, nadal jest wielu użytkowników języka francuskiego i hiszpańskiego (t_4 i t_5 w tabeli). Możemy wywnioskować, że pierwszy temat dotyczy poprzedniego zespołu Messiego (FC Barcelona), drugi dotyczy posta Messiego na Instagramie, a trzeci temat skupia się na osiągnięciach Messiego.

Teraz, gdy mamy tematy, możemy przewidzieć, który z nich był najczęściej omawiany. Aby to zrobić, najpierw połączymy tweety użytkowników (ponownie z największej społeczności):

 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 = " "))

Następnie oczyszczamy tekst jak poprzednio i tworzymy DTM. Następnie wywołujemy funkcję predict , używając naszego modelu LDA i DTM jako argumentów. Ponadto ustawiamy metodę na Gibbs, aby skrócić czas obliczeń, ponieważ mamy dużo tekstu do analizy:

 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)

Teraz w ramce danych com1.users.topics widzimy, ile każdy użytkownik mówił na każdy temat:

Rachunek t_1 t_2 t_3 t_4 t_5 […]
___99. 0,02716049 0.86666666 0,00246913 0,00246913 0,00246913
Szef__ 0,05185185 0,84197530 0,00246913 0,00246913 0,00246913
Memphis 0,00327868 0,00327868 0,03606557 0,00327868 0,00327868
___Alex1 0,00952380 0,00952380 0,00952380 0,00952380 0,00952380
[…]

Na koniec, korzystając z tych informacji, możemy utworzyć nowy atrybut na wykresie węzła, aby zdefiniować, o którym temacie najczęściej rozmawiał dany użytkownik. Następnie możemy stworzyć nowy plik GML, aby zwizualizować go w 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") 

Kolorowy wykres węzłów wygenerowany za pomocą Gephi, pokazujący ESPNFC jako najwyżej sklasyfikowanego użytkownika według centralności PageRank. ESPNFC znajduje się u dołu obrazu, a pod nim jest zgrupowanych wiele fioletowych węzłów.
Największa społeczność dyskusyjna Messiego pokolorowana według tematu i z użytkownikami wyróżnionymi przez centrum PageRank

Obraz przedstawiający odsetek użytkowników wyróżnionych każdym kolorem użytym na wykresie, gdzie fioletowy „t 6” jest najczęściej używanym kolorem (40,53% wszystkich użytkowników na wykresie), a następnie zielony „t 13” w 11.02 i niebiesko-błękitny „t 10” przy 9,68%. Szare „NA” na przedostatniej pozycji na liście 11 stanowi 2,25%.
Etykiety tematyczne i odsetek użytkowników dla każdego koloru użytego na wykresie

Wnioskowanie ważnych tematów i stosowanie centralnych sieci społecznościowych

W pierwszej odsłonie tej serii dowiedzieliśmy się, jak pozyskiwać dane z Twittera, tworzyć wykres interakcji, wykreślać go za pośrednictwem Gephi oraz wykrywać społeczności i ważnych użytkowników. W tej części rozszerzyliśmy tę analizę, demonstrując zastosowanie dodatkowych kryteriów do wykrywania wpływowych użytkowników. Pokazaliśmy również, jak wykryć i wnioskować, o czym mówią użytkownicy, i nakreślić to w sieci.

W następnym artykule będziemy nadal pogłębiać tę analizę, pokazując, w jaki sposób użytkownicy mogą wykryć plagę mediów społecznościowych: spamboty i trolle.

Dalsza lektura na blogu Toptal Engineering:

  • Analiza sieci społecznościowych za pomocą Power BI i R: przewodnik po niestandardowych wizualizacjach