About

Artikel ini merupakan bagian dari Exploratory Data Analysis untuk pengembangan dashboard AKSATA. Query twitter search “Quweenjojo” menarik untuk dibahas karena pemilik akun twitter “Quweenjojo” sempat menjadi pusat perhatian warganet pada pertengahan 2021 dan Awal Februari 2022 yang lalu.

Quweenjojo dan klaim kekerasan seksual

knitr::include_graphics("input/jojoquween.png")

Tweet permintaan maaf yang viral pada awal Februari 2022 membawa warganet teringat dengan pernyataan Quweenjojo pada pertengahan tahun 2021 lalu. Saat itu ia mengklaim bahwa telah mendapat perlakuan kurang pantas (pelecehan seksual) dari seorang penyiar radio bernama Gofar Hilman, pada tahun 2018.

Reaksi warganet menanggapi viralnya kembali Quweenjojo cukup beragam. Pada umumnya mereka bingung untuk menentukan standing positionnya terhadap kasus ini–antara merasa bingung atas sikap Quweenjojo; ada yang mencurigai Gofar Hilman memaksa Quweenjojo memberikan pernyataan palsu; ada pula yang prihatin dan memberi semangat terhadap kondisi kesehatan mental Quweenjojo.
Memang sempat diakui kalau Quweenjojo menderita skizofrenia, dan sering mengalami hal-hal delusional.

Terlepas dari sentimen warganet, Analisis SNA ini dibuat untuk memahami pola pembicaraan yang terbentuk berdasarkan aktivitas mention/replies maupun quote tweet.

Data diambil menggunakan bahasa pemrograman R dan package Rtweet. Anda dapat melihat dokumentasi https://github.com/ropensci/rtweet untuk mengambil data melalui API twitter (open in new tab).

Dataset diambil beberapa hari pasca viralnya tweet, dengan jumlah observasi yang didapatkan sebanyak 10294 tweets.

SNA Workflow

Memuat Library

library(tidyverse)
library(igraph)
library(sigmajs)
library(graphTweets)

Memuat dan melihat struktur data

raw_data <- readRDS("quweenjojo.rds")
glimpse(raw_data)
#> Rows: 10,294
#> Columns: 35
#> $ created_at                    <chr> "Sat Feb 12 05:37:48 +0000 2022", "Fri F~
#> $ id                            <dbl> 1492372346107473920, 1492171619892338688~
#> $ id_str                        <chr> "1492372346107473921", "1492171619892338~
#> $ full_text                     <chr> "Selain kamera yang dipasang si Mbak seb~
#> $ truncated                     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE~
#> $ display_text_range            <dbl> 181, 61, 66, 51, 63, 140, 23, 77, 140, 5~
#> $ entities                      <list> [[<data.frame[1 x 2]>], [<data.frame[1 ~
#> $ metadata                      <list> [<data.frame[1 x 2]>], [<data.frame[1 x~
#> $ source                        <chr> "<a href=\"https://mobile.twitter.com\" ~
#> $ in_reply_to_status_id         <dbl> NA, NA, NA, 1492175242235871232, 1493196~
#> $ in_reply_to_status_id_str     <chr> NA, NA, NA, "1492175242235871233", "1493~
#> $ in_reply_to_user_id           <dbl> NA, NA, NA, 719755682908491776, 11192604~
#> $ in_reply_to_user_id_str       <chr> NA, NA, NA, "719755682908491781", "11192~
#> $ in_reply_to_screen_name       <chr> NA, NA, NA, "kincir_mainan", "beruangbes~
#> $ geo                           <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ coordinates                   <list> [<data.frame[1 x 3]>], [<data.frame[1 x~
#> $ place                         <list> [<data.frame[1 x 3]>], [<data.frame[1 x~
#> $ contributors                  <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ is_quote_status               <lgl> TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, ~
#> $ quoted_status_id              <dbl> 1492135004373405696, NA, 149213500437340~
#> $ quoted_status_id_str          <chr> "1492135004373405698", NA, "149213500437~
#> $ quoted_status                 <list> [<data.frame[1 x 27]>], [<data.frame[1 ~
#> $ retweet_count                 <dbl> 736, 401, 86, 0, 0, 1, 0, 663, 7809, 0, ~
#> $ favorite_count                <dbl> 3539, 4552, 494, 0, 0, 0, 0, 0, 0, 0, 0,~
#> $ favorited                     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE~
#> $ retweeted                     <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE~
#> $ possibly_sensitive            <lgl> FALSE, FALSE, FALSE, NA, NA, NA, FALSE, ~
#> $ lang                          <chr> "in", "in", "in", "en", "in", "in", "und~
#> $ retweeted_status              <list> [<data.frame[1 x 30]>], [<data.frame[1 ~
#> $ text                          <chr> "Selain kamera yang dipasang si Mbak seb~
#> $ favorited_by                  <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ display_text_width            <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ quoted_status_permalink       <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ query                         <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~
#> $ possibly_sensitive_appealable <lgl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, ~

Package rtweet versi 0.7.900 menghasilkan metadata yang berbeda dengan versi sebelumnya. Metadata Rtweet versi terbaru berbentuk nested dataframe. Maka dari itu, saya harus menormalisasi data ke bentuk yang lebih sederhana dan mudah digunakan untuk clustering.

Data Preprocessing

Subset dan normalisasi variabel “retweeted status”

# Subset dan normalisasi variabel "retweeted status"

ret_status_user <- raw_data %>%
  select(retweeted_status) %>%
  unnest_wider(retweeted_status) %>%
  rename(created_at_retweet = created_at) %>%
  rename(id_ret = id) %>%
  rename(id_str_ret = id_str) %>%
  select(
    -entities,
    -lang,
    -metadata,
    -source,
    -truncated,
    -in_reply_to_status_id,
    -in_reply_to_status_id_str,
    -in_reply_to_user_id
  ) %>%
  rename(text_ret = full_text) %>%
  unnest_wider(user) %>%
  rename(description_user = description) %>%
  rename(attached_url = url) %>%
  # select(-...1) %>%
  unnest_wider(entities) %>%
  select(
    -display_text_range,
    -description,
    -quoted_status,
    -extended_entities,
    -place,
    -withheld_in_countries
  )

Mengambil hanya list “entities”

# List "user_mentions" terdapat pada variabel entities, saya harus mengubahnya menjadi list

to_mentions <- raw_data %>%
  select(entities) %>%
  mutate(entities = as.list(entities))

head(to_mentions)

Subset list screen_name di dalam list entities dan user_mentions

list_mention <- lapply(to_mentions$entities, function(x) {x[["user_mentions"]]$screen_name})

# Mengubah hasil subset menjadi character list c("","")

mentions_chr <- unlist(unlist(as.character(list_mention)))

Finalisasi struktur data

# Settling object ret_status_user dengan menambahkan character list, 
# menghilangkan tweet tanpa interaksi mention/reply

object_fix <- ret_status_user %>%
  mutate(mentions_screen_name = mentions_chr)%>%
  mutate(mentions_screen_name = ifelse(
    mentions_screen_name == "NA",
    NA,
    as.character(mentions_screen_name))) %>% 
  drop_na(text_ret) %>% 
  mutate(mentions_screen_name = ifelse(mentions_screen_name == screen_name, NA, as.character(mentions_screen_name))) %>% 
  select(-url)

# Subset hanya variabel yang dibutuhkan 
 
cleansing <- object_fix %>% 
  select(screen_name, mentions_screen_name, name)
# Mengkonversi character list c("","") menggunakan notasi regular expression

tweets <-
  cleansing %>%
  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 = "[[:]]+",
      replacement = ""
    )
  ) %>%
  rename(from = screen_name,
         to = mentions_screen_name) %>%
  
  mutate(to = str_replace_all(
    string = to,
    #to,
    pattern = "\"",
    replacement = ""
  ))

tweets

Visualisasi menggunakan graphTweets dan SigmaJs

gt <- tweets %>%
  gt_edges(from, to) %>%
  gt_nodes() %>%
  gt_collect()

# transform ke dataframe nodes dan edges (agar nantinya mudah dibaca oleh shiny)

tmp_nodes <- gt$nodes %>% as.data.frame()

tmp_edges <- gt$edges %>% as.data.frame()

nodes <- tmp_nodes %>%
  mutate(
    id = nodes,
    label = nodes,
    size = n,
    color = "#337def"
  )

edges <- tmp_edges %>%
  mutate(id = 1:n())

sigmajs() %>%
  sg_force_start() %>%
  sg_nodes(nodes, id, label, size, color) %>%
  sg_edges(edges, id, source, target) %>%
  sg_force_stop(15000)

Nodes dari visualisasi ini hoverable (untuk melihat username pada klaster). Visualisasi juga dapat di zoom sesuai keinginan.

Dapat kita lihat bahwa interaksi warganet pada topik “Quweenjojo” membentuk satu klaster utama dan beberapa klaster clique/ngerumpi. Klaster utama berisikan orang-orang yang secara jelas menyebut nama akun “@quweenjojo” di dalam tweetnya. Dalam kata lain, dapat kita simpulkan bahwa lebih banyak reaksi warganet yang langsung membalas tweet klarifikasi dari quweenjojo; daripada mereka yang melakukan “quote tweet” secara tidak langsung.

Berdasarkan visualisasi di atas, terdapat beberapa klaster “clique” yang berbentuk nodes-nodes kecil di sekeliling klaster besar. Pada topik ini, clique terbentuk dari interaksi tidak langsung atau “quote tweet”.

Inspect

(Sebagian) Interaksi username yang terhubung dengan username “Quweenjojo”

target <-
  c(
    "HanienNia",
    "Aermani_",
    "AdalardBanim",
    "agusatriawibawa",
    "LaxusRalenion",
    "chumaidijusuf",
    "fairyfoxlady",
    "_bernacleboy",
    "cyborgrunge",
    "riodwinurhafizh"
  )

object_fix %>%
  distinct() %>%
  select(text_ret, screen_name, mentions_screen_name, id_str_ret) %>%
  filter(screen_name %in% target)

Beberapa nodes klaster “Clique”/ ngerumpi

knitr::include_graphics("input/ngurahsaka.png")

knitr::include_graphics("input/komnasperempuan.png")

Inspect: interaksi klaster “cliques”

library(dplyr)
target2 <-
  c(
    "ngurahsaka",
    "komnasperempuan",
    "sentrisman",
    "f_andhikaa",
    "ence_dwi",
    "araghutama",
    "adefs97",
    "backfirecricket"
  )

object_fix %>%
  distinct() %>%
  select(text_ret, screen_name, mentions_screen_name, id_str_ret) %>%
  filter(screen_name %in% target2)

Final Analysis

Berdasarkan hasil visualisasi SNA dan inspect tweets, ternyata narasi yang dikemukakan antara klaster clique dengan klaster utama sedikit berbeda. Klaster clique lebih didominasi mereka yang sudah memiliki standing position terhadap topik: antara mengambil sikap netral, negatif, atau justru ingin memperluas diskursus (secara terpisah) dengan circle mereka sendiri.

Besar dan terpusatnya visualisasi klaster utama pada satu username (yakni Quweenjojo), melambangkan banyaknya orang yang merespon tweet Quweenjojo secara langsung; juga dengan narasi yang sifatnya langsung pula (seperti: “I don’t get it…”; “Ok now im real worried, i hope you’re okay and not under any pressure…”)

Berfokus pada pemilik akun Quweenjojo, sudah tentu apa yang ia lakukan membuat kegaduhan di media sosial dan kehidupan orang yang tertuduh. Namun, kira-kira sekitar satu minggu setelah viralnya tweet permintaan maaf, Gofar Hilman menceritakan kondisi Quweenjojo yang sesungguhnya, di dalam sebuah podcast.

Bagi penderita gangguan mental, mengakui kesalahan merupakan tindakan yang sulit dan patut kita apresiasi.

Hanya mereka yang bertanggung jawab menangani kesehatan mental Quweenjojo yang mampu memberi keterangan dengan lebih jelas. Namun pasti, sifat dari informasi tersebut sangatlah personal.