Problem Research

a. Latar Belakang Permasalahan

Ketika menghadapi digitalisasi, “literasi digital” masih menjadi pekerjaan rumah bagi Indonesia. Maraknya berita bohong, misinterpretasi, hal-hal yang viral dengan cepat, kerap kali menyebabkan kegaduhan maupun degradasi intelektual di masyarakat.

The Inclusive Internet Index, The Economist (2021)

The Inclusive Internet Index, The Economist (2021)

Menurut The Inclusive Internet Index (by The Economist Intelligence Unit), Indonesia menempati urutan ke 72 di dunia ketika kita berbicara tentang kesiapan terhadap digitalisasi (meliputi Literasi Digital, Kebijakan, dan Internet Safety).

Berdasarkan data di atas, saya melihat bahwa harus ada upaya yang konsisten dari masa ke masa dalam peningkatan hal kesiapan digital. Salah satu upaya yang dapat dilakukan adalah, mengedukasi masyarakat tentang hal yang mungkin laten; yang tidak mereka sadari sebelumnya–yaitu bagaimana masyarakat bisa menganalisis isu-isu yang mereka sukai dengan melihat pola interaksi antar akun sosial media.

Warganet Indonesia cukup reaktif dalam menanggapi suatu hal di media sosial (khususnya Twitter). Bentuk-bentuk arus konten di twitter Indonesia saya bedakan secara garis besar, antara lain: - Berita - Respon perorangan - Respon buzzer - Respon tidak serius (nyeleneh)

Selain itu, pemetaan interaksi akun-akun pasti akan sangat menarik untuk dilihat. Saya tertarik pada berbagai publikasi Drone Emprit, sebuah platform publikasi SNA yang cukup dikenal pada kalangan akademisi ilmu sosial.

Maka dari itu, saya melihat bahwa Social Network Analysis dan Text Classification bisa menjadi salah satu repertoar yang baik untuk membangun literasi digital dimasyarakat. Dengan dikemas pada dashboard yang interaktif, saya berharap netizen bisa mengeksplor fitur yang ada di dalamnya sambil mempelajari stream informasi pada suatu topik (hashtags, query) yang mereka sukai.

Dashboard ini dapat saja digunakan bagi kebutuhan bisnis, pemerintah, maupun awam. Ide ini tidak tertutup kemungkinan pada luasnya latar belakang netizen di Indonesia.

b. Business impact yang ditawarkan pada project

Dengan memetakan pola interaksi dan sentimen, suatu bisnis maupun perseorangan dapat memperoleh pemetaan tentang pola relasi, komunitas/segmen, maupun respon suatu populasi (di Twitter) terhadap topik tertentu.

c. Target user dan benefit

Sebetulnya, target user utama dari dashboard ini tidak lain adalah warganet itu sendiri. Selain itu dashboard ini diharapkan dapat mendekatkan framework analisis data social behavior/user generated data kepada awam dan akademisi sosial.

d. Implementasi ke business serupa

Konsep SNA dan Text Classification dapat diimplementasi pada kasus-kasus berikut ini:

Case 1

Akademisi sosial dapat menganalisis data twitter dengan mudah tanpa harus menunggu publikasi dari beberapa organisasi yang biasa mengolah data social network (seperti Lab Big Data, Drone Emprit, dsb).

Case 2

Misalkan divisi marketing ingin melihat customer segmentation, mereka juga dapat menggunakan data dari hashed emails ataupun user-generated data yang mereka miliki menggunakan metode graph analytics.

Case 3

Misalkan ketika suatu trade saham maupun komoditas (crypto, forex) akan menghadapi suatu musim (politik, dsb) bagaimana kemudian perusahaan bisa mengambil sikap untuk meningkatkan atau mengurangi jumlah investasi pada sektor tertentu berdasarkan analisis sentimen, pastinya dengan menggunakan data train yang sudah disesuaikan klasifikasinya, misalkan emotional sentiment.

Case 4

Misalkan web developer ingin memahami efisiensi website mereka menggunakan data cookies, kita dapat mewakili setiap page sebagai nodes melalui graph analytics.

Case 5

Misalkan web developer ingin memahami efisiensi website mereka menggunakan data cookies, kita dapat mewakili setiap page sebagai nodes melalui graph analytics.

Case 6

Divisi human capital suatu perusahaan pun dapat menggunakan framework serupa (graph analytics) untuk keperluan organizational network analysis.

e. Tujuan/output dari project

Project ini diharapkan mampu menjawab visi diatas, dengan menggunakan algoritma clustering dan Long Short Term Memory untuk analisis sentimen.

Data Collection

a. Informasi Singkat

Karena project ini salah satunya akan menggunakan unsupervised learning, sepertinya saya membutuhkan lebih dari satu dataset untuk dapat memastikan bahwa dashboard berjalan dengan baik.

Sejauh ini, data twitter yang saya miliki adalah data dari DSS Social Network Analysis. Saya ingin mengeksplor lebih jauh terkait kemungkinan error yang dapat terjadi dari graph analytics. Misalkan username yang tidak valid yang disebabkan kesalahan dalam cleansing, kesalahan dalam pengambilan data, dsb.

b. Darimana sumber data, bagaimana teknik pengumpulannya, apakah dapat dipertanggungjawabkan?

Data dari DSS tersebut diambil dari twitter API (Mas David) dengan topik “NFT”. Sementara Data untuk text classification belum dapat saya peroleh karena terkendala submission di Twitter Developer.

c. Apakah data sudah sesuai dengan kebutuhan bisnis? Sertakan alasannya

Pasti sesuai karena saya ingin membuat dashboard yang memungkinkan pengolahan berbagai data dengan struktur yang serupa (twitter API, menggunakan fitur import/upload to dashboard).

Data Preparation

a. Target dan/atau prediktor

  • Unsupervised: tidak ada

  • Text Classification : Text dan Label (berita, respon perorangan, respon buzzer, respon tidak serius)

b. Tahapan yang perlu dilakuan pada proses data preparation

  • Mengajukan izin twitter developer (terkendala)

  • Cleansing data untuk train model SNA dan Text Classification, membersihkan beberapa style text dari twitter API menggunakan regular expression dan beberapa package cleansing

  • Memisahkan “mentions” dari teks ke kolom terpisah

  • Mengambil data untuk text klasifikasi, memberi label secara manual (tableplus)

Exploratory Data Analysis

Read Library

library(tidyverse)

# graph
library(tidygraph)
library(ggraph)
library(igraph)

Read Data

tweets <- read_rds("nft.RDS")
head(tweets, 10)
tail(tweets, 20)

Memeriksa struktur data

glimpse(tweets)
#> Rows: 17,681
#> Columns: 90
#> $ user_id                 <chr> "1482989135279554561", "1465321321018101774", ~
#> $ status_id               <chr> "1484077026751705091", "1484077026546008068", ~
#> $ created_at              <dttm> 2022-01-20 08:15:10, 2022-01-20 08:15:10, 202~
#> $ screen_name             <chr> "MdMurad46986696", "artur_litau", "uzayhayat17~
#> $ text                    <chr> "<U+0001F6F8>There are different crystals on the earth. ~
#> $ source                  <chr> "Twitter Web App", "Twitter for iPhone", "Twit~
#> $ display_text_width      <dbl> 140, 13, 4, 69, 140, 140, 140, 140, 139, 140, ~
#> $ reply_to_status_id      <chr> NA, "1484076661943513088", "148407336790914663~
#> $ reply_to_user_id        <chr> NA, "1469819305", "1728743684", NA, NA, NA, NA~
#> $ reply_to_screen_name    <chr> NA, "drmctchr333", "misscryptolog", NA, NA, NA~
#> $ is_quote                <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS~
#> $ is_retweet              <lgl> TRUE, FALSE, FALSE, TRUE, TRUE, TRUE, TRUE, TR~
#> $ favorite_count          <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0~
#> $ retweet_count           <int> 4105, 0, 0, 1305, 822, 264, 13, 1, 344, 1942, ~
#> $ quote_count             <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ reply_count             <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ hashtags                <list> NA, NA, NA, NA, NA, <"NFTs", "HODL", "gems", ~
#> $ symbols                 <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "REVO~
#> $ urls_url                <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ urls_t.co               <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ urls_expanded_url       <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ media_url               <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ media_t.co              <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ media_expanded_url      <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ media_type              <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ ext_media_url           <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ ext_media_t.co          <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ ext_media_expanded_url  <list> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ ext_media_type          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ mentions_user_id        <list> "717023423696871424", <"1469819305", "1441155~
#> $ mentions_screen_name    <list> "SpaceDAOBSC", <"drmctchr333", "BabyGhosts_NF~
#> $ lang                    <chr> "en", "en", "en", "en", "en", "en", "en", "en"~
#> $ quoted_status_id        <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_text             <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_created_at       <dttm> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, N~
#> $ quoted_source           <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_favorite_count   <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_retweet_count    <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_user_id          <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_screen_name      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_name             <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_followers_count  <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_friends_count    <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_statuses_count   <int> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_location         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_description      <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ quoted_verified         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ retweet_status_id       <chr> "1483999732905111552", NA, NA, "14840733679091~
#> $ retweet_text            <chr> "<U+0001F6F8>There are different crystals on the earth. ~
#> $ retweet_created_at      <dttm> 2022-01-20 03:08:02, NA, NA, 2022-01-20 08:00~
#> $ retweet_source          <chr> "Twitter Web App", NA, NA, "Twitter for iPhone~
#> $ retweet_favorite_count  <int> 4046, NA, NA, 369, 813, 272, 19, 1, 377, 1173,~
#> $ retweet_retweet_count   <int> 4105, NA, NA, 1305, 822, 264, 13, 1, 344, 1942~
#> $ retweet_user_id         <chr> "717023423696871424", NA, NA, "1728743684", "3~
#> $ retweet_screen_name     <chr> "SpaceDAOBSC", NA, NA, "misscryptolog", "Brecc~
#> $ retweet_name            <chr> "SpaceDAO", NA, NA, "Miss Cryptolog", "Brecci"~
#> $ retweet_followers_count <int> 51808, NA, NA, 557859, 187762, 124776, 341, 78~
#> $ retweet_friends_count   <int> 128, NA, NA, 281, 846, 235, 2, 3149, 166, 11, ~
#> $ retweet_statuses_count  <int> 48, NA, NA, 13019, 10258, 2349, 71, 259, 122, ~
#> $ retweet_location        <chr> "Metaverse", NA, NA, "", "DM for PAID promo <U+0001F525>~
#> $ retweet_description     <chr> "SpaceDAO innovation on GameFi world!\nTelegra~
#> $ retweet_verified        <lgl> FALSE, NA, NA, FALSE, TRUE, FALSE, FALSE, FALS~
#> $ place_url               <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ place_name              <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ place_full_name         <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ place_type              <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ country                 <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ country_code            <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ geo_coords              <list> <NA, NA>, <NA, NA>, <NA, NA>, <NA, NA>, <NA, ~
#> $ coords_coords           <list> <NA, NA>, <NA, NA>, <NA, NA>, <NA, NA>, <NA, ~
#> $ bbox_coords             <list> <NA, NA, NA, NA, NA, NA, NA, NA>, <NA, NA, NA~
#> $ status_url              <chr> "https://twitter.com/MdMurad46986696/status/14~
#> $ name                    <chr> "Md Murad", "Artur Litau", "Uzay Hayat", "Uzay~
#> $ location                <chr> "", "", "", "", "", "", "", "", "", "", "Lagos~
#> $ description             <chr> "", "", "#SUPERFAMILY\n@LaCryptoMonkey\n#RichQ~
#> $ url                     <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "h~
#> $ protected               <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS~
#> $ followers_count         <int> 2, 4, 302, 302, 96, 96, 299, 299, 6, 6, 43, 52~
#> $ friends_count           <int> 55, 34, 4163, 4163, 4838, 4838, 732, 732, 1357~
#> $ listed_count            <int> 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0~
#> $ statuses_count          <int> 166, 44, 21653, 21653, 50394, 50394, 2316, 231~
#> $ favourites_count        <int> 78, 76, 17321, 17321, 9710, 9710, 2076, 2076, ~
#> $ account_created_at      <dttm> 2022-01-17 08:12:36, 2021-11-29 14:07:40, 202~
#> $ verified                <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALS~
#> $ profile_url             <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "h~
#> $ profile_expanded_url    <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, "h~
#> $ account_lang            <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ profile_banner_url      <chr> NA, NA, "https://pbs.twimg.com/profile_banners~
#> $ profile_background_url  <chr> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA~
#> $ profile_image_url       <chr> "http://pbs.twimg.com/profile_images/148298921~

Melihat banyak data yang merupakan retweet

tweets %>% 
  count(is_retweet)

Melihat akun dengan jumlah retweet terbanyak

tweets %>% 
  filter(is_retweet) %>% 
  select(retweet_count) %>% 
  summary()
#>  retweet_count  
#>  Min.   :    0  
#>  1st Qu.:   88  
#>  Median :  458  
#>  Mean   : 1379  
#>  3rd Qu.: 1395  
#>  Max.   :49552
tweets %>% 
  filter(retweet_count == 49552) %>% 
  select(screen_name,user_id, text)

User dengan screen name b1nary_eth merupakan akun dengan jumlah retweet terbanyak pada dataset. adapun isi tweet tersebut dapat kita pahami sebagai pertanyaan sekaligus pertanyaan tentang in-game-currency yang menggunakan NFT. Bagaiamana kemudian berbagai game-NFT dapat bertahan, karena banyak entitas serupa justru tidak mampu bertahan karena kebijakan in game currency nya sendiri (menggunakan NFT/kripto).

(lihat referensi di sini)

Data cleansing, eksplorasi data

cleansing <- tweets %>% 
  select(screen_name, mentions_screen_name) %>%
  mutate(mentions_screen_name = as.character(mentions_screen_name)) 
head(cleansing, 100)

Normalisasi mentions_screen_name menggunakan regular expression

–> sekaligus menyiapkan objek edge_df

edge_df <- 
cleansing %>% 
  select(screen_name, mentions_screen_name) %>% 
  mutate(mentions_screen_name = str_replace_all(string = mentions_screen_name, 
                                               pattern = "^c\\(|\\)$",
                                               replacement = "")) %>% 
  separate_rows(mentions_screen_name, sep = ",") %>% 
  na.omit() %>% 
  mutate(mentions_screen_name = str_replace_all(string = mentions_screen_name,
                                                pattern = "[[:punct]]+",
                                                replacement = "")) %>%
  rename(from = screen_name,
         to = mentions_screen_name)

head(edge_df, 100)

Membuat data frame nodes_df (kumpulan screen_name pada edge_df)

nodes_df <- data.frame(name = unique(c(edge_df$from,edge_df$to)),
                        stringsAsFactors = F)

tail(nodes_df,10)

Antara data edge dan nodes belum terlalu rapi, masih ada quotation mark (" "), saya ingin membersikan menggunakan regex pada function str_replace_all

nodes_df1 <- nodes_df %>%  
  mutate(name = str_replace_all(string = name,
                                pattern = "\"",
                                replacement = ""))
head(nodes_df1)
edge_df1 <- edge_df %>% 
  mutate(to = str_replace_all(string = to,
                                pattern = "\"",
                                replacement = ""))

head(edge_df1)

Membuat graph dengan fungsi tbl_graph()

graph_tweets <- tbl_graph(nodes = nodes_df1, 
                          edges = edge_df1,
                          directed = F)
graph_tweets
#> # A tbl_graph: 18490 nodes and 33011 edges
#> #
#> # An undirected multigraph with 1882 components
#> #
#> # Node Data: 18,490 x 1 (active)
#>   name           
#>   <chr>          
#> 1 MdMurad46986696
#> 2 artur_litau    
#> 3 uzayhayat17    
#> 4 _andierna_     
#> 5 Cardatson      
#> 6 minguinnnnn_   
#> # ... with 18,484 more rows
#> #
#> # Edge Data: 33,011 x 2
#>    from    to
#>   <int> <int>
#> 1     1  9504
#> 2     2  9505
#> 3     2  9506
#> # ... with 33,008 more rows

Saya menggunakan undirected graph karena ingin mengabaikan arah interaksi antara from dan to, dan apakah interaksi terjadi secara dua arah atau searah.

Centrality Measurement

Kita akan mengukur centrality dari setiap Nodes dengan parameter berikut:

  • Degree: untuk menemukan user yang terkoneksi secara lokal (dalam satu cluster)

  • Betweenness: untuk menemukan user yang menjadi perantara terhadap beberapa cluster

  • Closeness: untuk menemukan user yang memiliki bisa memberi influence tercepat terhadap yang lain

  • Eigen: mengukur pengaruh dari setiap user dari banyaknya keterhubungan dengan node-node lainnya; lalu dipertimbangkan juga koneksi yang dimiliki oleh setiap user; bobot dari berbagai koneksi yang dimiliki

options(scipen = 100)
graph_tweets <- graph_tweets %>% 
  activate(nodes) %>%
  mutate(degree = centrality_degree(), # Calculate degree centrality
         between = centrality_betweenness(normalized = T), # Calculate betweeness centrality
         closeness = centrality_closeness(), # Calculate closeness centrality
         eigen = centrality_eigen()
         )  # Calculate eigen centrality

graph_tweets
#> # A tbl_graph: 18490 nodes and 33011 edges
#> #
#> # An undirected multigraph with 1882 components
#> #
#> # Node Data: 18,490 x 5 (active)
#>   name            degree      between     closeness    eigen
#>   <chr>            <dbl>        <dbl>         <dbl>    <dbl>
#> 1 MdMurad46986696      1 0            0.00000000950 1.92e- 7
#> 2 artur_litau          3 0.000112     0.00000000949 3.21e-11
#> 3 uzayhayat17          4 0.0000000173 0.00000000950 6.88e- 2
#> 4 _andierna_           3 0.000000984  0.00000000950 1.12e- 3
#> 5 Cardatson            2 0.0000000117 0.00000000293 7.35e-18
#> 6 minguinnnnn_         3 0.0000130    0.00000000950 7.81e- 5
#> # ... with 18,484 more rows
#> #
#> # Edge Data: 33,011 x 2
#>    from    to
#>   <int> <int>
#> 1     1  9504
#> 2     2  9505
#> 3     2  9506
#> # ... with 33,008 more rows
network_act_df <- graph_tweets %>% 
  activate(nodes) %>% 
  as.data.frame()

head(network_act_df,10)

Eksplorasi data pada akun yang memiliki centrality tinggi

kp_activity <- data.frame(
  network_act_df %>% arrange(-degree) %>% select(name) %>% slice(1:6),
  network_act_df %>% arrange(-between) %>% select(name) %>% slice(1:6),
  network_act_df %>% arrange(-closeness) %>% select(name) %>% slice(1:6),
  network_act_df %>% arrange(-eigen) %>% select(name) %>% slice(1:6)
) %>% setNames(c("degree","betweenness","closeness","eigen"))
kp_activity

Berdasarkan hasil analisis centralities, terlihat bahwa akun f_sara termasuk dalam semua golongan centrality, yang berarti akun tersebut paling populer secara lokal maupun global (eigen).
Selain itu, besar kemungkinan jugaf_sara terhubung dengan kebanyakan cluster, sehingga arus informasi dari semua cluster diakomodasi oleh akun tersebut.

Namun, temuan dapat saja berbeda apabila terdapat aktivitas mentioning yang berlebihan yang ditujukan pada akun f_sara, terlepas dari apa dan siapa identitas akun tersebut.

# Memahami siapa f_sara

lookup <- tweets %>% 
  select(screen_name, mentions_screen_name, text, retweet_count) %>%
  mutate(mentions_screen_name = as.character(mentions_screen_name)) %>% 
  mutate(mentions_screen_name = str_replace_all(string = mentions_screen_name, 
                                               pattern = "^c\\(|\\)$",
                                               replacement = "")) %>% 
  na.omit() %>% 
  mutate(mentions_screen_name = str_replace_all(string = mentions_screen_name,
                                                pattern = "[[:punct]]+",
                                                replacement = "")) %>%
  mutate(mentions_screen_name = str_replace_all(string = mentions_screen_name,
                                pattern = "\"",
                                replacement = "")) %>%
  separate_rows(mentions_screen_name, sep = ",")

lookup
inspect_sara <- lookup %>% 
  filter(mentions_screen_name == "f_sara") %>% 
  arrange(desc(retweet_count)) %>% 
  distinct(text, mentions_screen_name, screen_name)

inspect_sara[41:105,]

Setelah pencarian lebih lanjut, sayangnya akun dengan nama screen_name f_sara tidak terkait dengan tweet bertopik NFT/kripto.

Berdasarkan data, kita dapat melihat bahwa f_sara sering terkait dengan tweet dari sebuah akun yang bernama @nft_spartan.

nft_spartan merupakan kolektor dan investor NFT, akun tersebut sering terlibat dalam suatu givaway maupun info dan ‘tips and trick’.
Dalam dunia yang sarat dengan unsur FOMO (Fear Of Missing Out) seperti game, cryptocurrency maupun NFT, kita mungkin sering melihat akun yang “menggaungkan isu” secara intensif/spamming.

Analisis saya, karena pada saat ini kita mengacu pada mentions_screen_name, kemungkinan besar akun nft_spartan melakukan mention secara acak dan hidden kepada beberapa screen name untuk memperkenalkan isi kontennya. Namun disayangkan, karena target mentionnya terlihat seperti akun nonaktif.

Graph Visualization

Membuat Cluster

set.seed(123)
graph_tweets <- graph_tweets %>% 
  activate(nodes) %>% 
  mutate(community = group_louvain()) %>% 
  activate(edges) %>% 
  filter(!edge_is_loop())  # Remove loop edges
graph_tweets %>% 
  activate(nodes) %>% 
  as.data.frame() %>% 
  count(community)

Mengambil cluster 1-5 saja, dengan asumsi 5 data dari klaster terbanyak sudah representatif (jumlah dari n1-n5)

# fungsi untuk mendapatkan orang orang penting di tiap cluster
important_user <- function(data) {
  name_person <- data %>%
  as.data.frame() %>% 
  filter(community %in% 1:5) %>% 
  select(-community) %>% 
  pivot_longer(-name, names_to = "measures", values_to = "values") %>% 
  group_by(measures) %>% 
  arrange(desc(values)) %>% 
  slice(1:6) %>% 
  ungroup() %>% 
  distinct(name) %>% 
  pull(name)
  
  return(name_person)
}

Visualisasi data graph yang sudah dibuat

important_person <- 
graph_tweets %>% 
  activate(nodes) %>% 
  important_user()
set.seed(100)
graph_tweets %>%
  activate(nodes) %>%
  mutate(ids = row_number(),
         community = as.character(community)) %>%
  filter(community %in% 1:5) %>% 
  arrange(community,ids) %>%
  mutate(node_label = ifelse(name %in% important_person, name, NA)) %>%
  ggraph(layout = "fr") +
  geom_edge_link(alpha = 0.3 ) +
  geom_node_point(aes(size = degree, fill = community), shape = 21, alpha = 0.7, color = "grey30") +
  geom_node_label(aes(label = node_label), repel = T, alpha = 0.8 ) +
  guides(size = "none") +
  labs(title = "Top 5 Community of #NFT", 
       color = "Interaction",
       fill = "Community") +
  theme_void() +
  theme(legend.position = "top")

Memeriksa kembali “orang penting”

Saya sedikit skeptis dengan hasil top 5 community diatas, bagaimana eksistensi akunnya di twitter, apakah sama seperti f_sara.

Maka dari itu saya ingin melihat screen_name, mentions_screen_name, dan text yang melibatkan akun yang saya curigai.

Saya tertarik untuk inspect akun missryolog.

missryolog <- lookup %>% 
  filter(mentions_screen_name == "missryolog") %>% 
  arrange(desc(retweet_count)) %>% 
  distinct(text, mentions_screen_name, screen_name)

head(missryolog,100)

Dapat kita lihat dari isi tweet, bahwa pada akun missryolog pun masih berkaitan dengan spamming nft_spartan.

Selanjutnya, sebetulnya apa isi dari akun missryolog?

knitr::include_graphics("images/ryolog.png")

Ternyata, missryolog bukanlah merupakan akun yang aktif (atau bahkan salah alamat). Dari hasil eksplorasi object yang sudah saya buat secara khusus, saya memiliki perkiraan bahwa missryolog merupakan kesalahan penulisan dari misscryptolog.

missryolog[991:1052,]
knitr::include_graphics("images/cryptolog.png")

Kesimpulan

Berdasarkan hasil visualisasi dan centrality, dapat disimpulkan bahwa cluster yang berwarna hijau yang memiliki keterhubungan dengan nodes dari cluster lainnya. Namun, sepertinya terdapat beberapa nama akun yang tidak valid; entah itu dikarenakan proses cleansing atau karena data asalnya (mohon pencerahan).

Banyak akun investor NFT yang melakukan spamming terhadap akun-akun lain secara acak, dilihat dari relevansi mentions_screen_name terhadap pemeriksaan eksistensi akun tersebut di twitter (contohnya: f_sara).

Akun @nft_spartan was a great spammer

Rekomendasi: apakah clustering SNA bisa dijadikan interaktif?

NetworkD3 Experiment

library(networkD3)
src <- c("A", "A", "A", "A",
         "B", "B", "C", "C", "D")

target <- c("B", "C", "D", "J", "E",
            "F", "G", "H", "I")

networkData <- data.frame(src, target)
simpleNetwork(networkData)

Load data dummy

data("MisLinks")
data("MisNodes")

Visualisasi graph interaktif

forceNetwork(Links = MisLinks, Nodes = MisNodes, Source = "source", 
             Target = "target", Value = "value", NodeID = "name", 
             Nodesize = "size", 
             radiusCalculation = "Math.sqrt(d.nodesize)+6",
             Group = "group", opacity = 1, opacityNoHover = F, width = 1000, height = 700, fontSize = 12)

Melihat struktur data forceNetwork()

MisLinks
MisNodes

Struktur data sedikit berbeda dengan ggraph.. apakah hasil tbl_graph() kompatibel untuk plotting NetworkD3?

Hal yang perlu diantisipasi

  • Kesalahan cleansing, encoding, dsb

  • Interaksi mentions yang seakan membuat seseorang memiliki centrality tinggi, padahal akun tersebut merupakan “korban” spamming

  • Membuat directed graph

  • Mendapatkan data twitter secara real time

Dashboard Mock Up

contoh tampilan page 1

contoh tampilan page 1

contoh tampilan page 2

contoh tampilan page 2

Product Design

Rencana algoritma machine learning yang akan digunakan

  • SNA (clustering, graph analytics directed dan undirected)

  • LSTM (untuk classification) –> arsitektur deep learning perlu dieksplorasi

Fitur yang akan ada di dashboard

  • Embed text Tweet berdasarkan hasil pembelajaran mesin (untuk klasifikasi)

  • Embed mock up profile berdasarkan centralities SNA (jika memungkinkan)

  • UI menggunakan framework bootstrap 4 di R-shiny

  • Satu halaman edukasi graph analytics (konsep masih dipikirkan)