Saya Briandamar Kencana seorang data enthusiast. Saya lulus dengan gelar sarjana statistik. Saya memiliki beberapa pengalaman kerja di bidang data, seperti magang di momobil.id, independent research and advisory Indonesia, staf data analis di Alif Aza Asia dan asisten peneliti di Bank Indonesia, dan kemudian saya melanjutkan karir saya sebagai analis di sebuah bank komersial di Indonesia. Selain itu, saya telah berpartisipasi dalam beberapa kursus pelatihan data di Algoritma Data Science School, Coursera, Udemy dan Dicoding.
Data ini merupakan data yang diperoleh dari salah satu group percakapan yang saya miliki di Whatsapp. Kemudian saya eksport data tersebut menjadi data dengan format.txt. Bagaimana cara mengeksport data histori chat Whatsapp dapat dilihat pada gambar dibawah ini :
Eksport Chat
Whatsapp adalah aplikasi pesan yang memungkinkan kita bertukar pesan tanpa pulsa. Memiliki aplikasi ini, kita dapat terhubung kembali dengan teman-teman kita dengan mudah. Saya pribadi menggunakan aplikasi ini sudah sangat lama, dan sangat mengandalkan aplikasi ini untuk bertukar pesan dengan teman-teman saya. Hingga suatu hari saya mendapatkan pesan undangan hadir pernikahan dari salah satu teman SMA saya pada kelas 10 dahulu. Disitu saya berjumpa dengan teman-teman lama, mengobrol bareng dan berlanjut dengan membuat suatu group whatsapp yang dinamakan “Rebahan People” untuk dapat berkomunikasi lebih lanjut. Percakapan sangat intens dan terlihat masing masing orang menikmati group yang dibuat tersebut, karena memang kita masing-masing sudah lama sekali tidak bertemu dan sampai Kita merencanakan untuk pergi jalan-jalan ke puncak melalui group Whatsapp tersebut.
Namun seperti setiap orang yang akan menemukan titik jenuhnya, maka group pun bisa jadi menemukan titik jenuhnya. saya menggunakan data histori pada analisis ini per tanggal 25 July 2020. Saya akan mengamati beberapa informasi sebagai berikut :
Pertama yang harus dilakukan adalah melakukan data-preprocessing karena data yang ingin diharapkan adalah dalam bentuk dataframe dan kita perlu memecah setiap text menjadi beberapa bagian informasi.
library(readr)
library(dplyr)
library(tibble)
library(tidyr)
library(stringr)
library(lubridate)
library(emo)
library(textfeatures)
data_whatsapp <-
read_lines("Chat WhatsApp dengan Rebahan People.txt")
glimpse(data_whatsapp)
#> chr [1:25537] "08/11/2019 22.07 - Pesan yang dikirim ke grup ini kini diamankan dengan enkripsi end-to-end. Ketuk untuk info selengkapnya." ...
Saya menggunakan fungsi read_lines untuk membaca data yang tersimpalan dalam bentuk .txt menjadi karakter untuk setiap line. Kemudian saya akan memisahkan bagian-bagian pengirim , datetime, dan text menggunakan fungsi dibawah ini :
wachats <-
data_whatsapp %>%
enframe(name = NULL, value = "content") %>%
separate(
content,
into = c("datetime", "content"),
sep = "(?<=\\d{2}/\\d{2}/\\d{4} \\d{2}.\\d{2}) - ",
fill = "left"
) %>%
mutate(
chatid = case_when(
!is.na(datetime) ~ row_number(),
TRUE ~ NA_integer_
)
) %>%
fill(chatid, datetime) %>%
group_by(chatid) %>%
summarise(
datetime = unique(datetime),
content = paste0(content, collapse = "\n"),
n_lines = n()
) %>%
ungroup() %>%
filter(str_detect(content, ":")) %>%
separate(
content,
into = c("author", "text"),
sep = ": ",
extra = "merge"
) %>%
mutate(
datetime = dmy_hm(datetime)
)
glimpse(wachats)
#> Rows: 20,722
#> Columns: 5
#> $ chatid <int> 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,...
#> $ datetime <dttm> 2019-11-08 22:35:00, 2019-11-08 22:35:00, 2019-11-08 22:3...
#> $ author <chr> "Beby", "Beby", "Beby", "Beby", "Beby", "Beby", "Beby", "B...
#> $ text <chr> "Curug aja gapulau ajaa nginep ? Hahahah", "Lopeyuhh guyss...
#> $ n_lines <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
DT::datatable(head(wachats,50),
options = list(
pageLength = 10,
scrollX = TRUE,
scrollY = "500px"),
caption = htmltools::tags$caption(
style = 'caption-side:bottom; text-align: right;',
'Data Source:', htmltools::em('Group Whatsapp')))
Setelah berhasil memisahkan informasi-informasi yang semula dalam satu karakter menjadi dataframe, selanjutnya saya akan mengektrak informasi dari setiap kolom text, seperti emoji yang digunakan, jumlah kata yang digunakan, jumlah url yang digunakan, dan lain sebagainya.
n_newlines <- function(x) {
na <- is.na(x)
if (all(na))
return(0)
m <- gregexpr("\n", x)
x <- vapply(m, function(x) sum(x > 0, na.rm = TRUE), FUN.VALUE = integer(1))
x[na] <- NA_integer_
x
}
wachats_features <-
wachats %>%
mutate(
hour = hour(datetime),
day = wday(datetime, week_start = 1),
any_media = str_detect(text, "<Media omitted>"),
any_emoji = emo::ji_detect(text),
emoji = emo::ji_extract_all(text),
n_emojis = emo::ji_count(text),
n_chars = nchar(text),
n_words = textfeatures:::n_words(text),
n_nonasciis = textfeatures:::n_nonasciis(text),
n_digits = textfeatures:::n_digits(text),
n_hashtags = textfeatures:::n_hashtags(text),
n_mentions = textfeatures:::n_mentions(text),
n_commas = textfeatures:::n_commas(text),
n_periods = textfeatures:::n_periods(text),
n_exclaims = textfeatures:::n_exclaims(text),
n_newlines = n_newlines(text),
n_caps = textfeatures:::n_caps(text),
n_lowers = textfeatures:::n_lowers(text),
n_urls = textfeatures:::n_urls(text),
n_puncts = textfeatures:::n_puncts(text)
) %>%
relocate(n_lines, .before = n_emojis) %>%
mutate(
across(
starts_with("n_"),
~ if_else(text == "<Media omitted>", NA_integer_, .x)
)
)
glimpse(wachats_features)
#> Rows: 20,722
#> Columns: 25
#> $ chatid <int> 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ...
#> $ datetime <dttm> 2019-11-08 22:35:00, 2019-11-08 22:35:00, 2019-11-08 2...
#> $ author <chr> "Beby", "Beby", "Beby", "Beby", "Beby", "Beby", "Beby",...
#> $ text <chr> "Curug aja gapulau ajaa nginep ? Hahahah", "Lopeyuhh gu...
#> $ hour <int> 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,...
#> $ day <dbl> 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5...
#> $ any_media <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE,...
#> $ any_emoji <lgl> FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, ...
#> $ emoji <list> [<>, <>, <>, <>, <>, <>, <>, "\U0001f618", <>, <>, <>,...
#> $ n_lines <int> 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
#> $ n_emojis <int> 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0...
#> $ n_chars <int> 39, 14, 5, 15, 33, 6, 24, 65, 11, 15, 21, 6, 14, 7, 17,...
#> $ n_words <int> 7, 2, 1, 2, 5, 1, 3, 10, 2, 3, 3, 1, 3, 2, 4, 3, 11, 6,...
#> $ n_nonasciis <int> 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0...
#> $ n_digits <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0...
#> $ n_hashtags <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_mentions <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_commas <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0...
#> $ n_periods <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_exclaims <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_newlines <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_caps <int> 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1...
#> $ n_lowers <int> 30, 12, 4, 13, 28, 5, 19, 53, 9, 12, 18, 5, 11, 5, 12, ...
#> $ n_urls <int> 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0...
#> $ n_puncts <int> 1, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2...
DT::datatable(head(wachats_features,50),
options = list(
pageLength = 10,
scrollX = TRUE,
scrollY = "500px"),
caption = htmltools::tags$caption(
style = 'caption-side:bottom; text-align: right;',
'Data Source:', htmltools::em('Group Whatsapp')))
Setelah berhasil mengekstrak informasi diatas, maka tahapan selanjutnya saya akan melakukan proses data visualisasi untuk mendapatkan informasi atau insight yang terkandung dalam data yang saya miliki.
Data visualisasi yang pertama akan saya lakukan adalah melihat pergerakan jumlah chat untuk semua anggota group dari awal group dibuat sampai data tanggal 25 July 2020.
library(tidyr)
library(forcats)
library(ggplot2)
library(ggalt)
library(hrbrthemes)
library(wordcloud2)
library(plotly)
library(ggrepel)
library(glue)
# Daily number of chats ---------------------------------------------------
wachats_features %>%
mutate(datetime=as_date(datetime)) %>%
count(datetime) %>%
plot_ly(x = ~datetime,
y = ~n,
name = 'Count',
type = "scatter",
mode = 'lines',
line = list(color = "#9e0d38",
width = 4)) %>%
layout(yaxis = list(title = "Jumlah Chat",color="#c7c1c3"),
xaxis = list(title = "Tanggal", color="#c7c1c3"),
showlegend = FALSE,
hovermode = "compare") %>%
layout(plot_bgcolor='rgb(37, 42, 50)') %>%
layout(paper_bgcolor='rgb(37, 42, 50)')
Berdasarkan informasi diatas, saya mendapatkan infromasi bahwa seperti yang ditulis dalam bagian permasalahan sebelumnya jumlah chat pada saat awal group dibuat, jumlah chat sangat rame atau intens, namun mulai bulan april 2020 sudah mulai sepi. Hal tersebut dipicu karena korona masuk ke indonesia pada bulan Maret sehingga tidak ada lagi obrolan untuk kumpul-kumpul dan sudah jarang ketemu, hingga terus berlanjut sampai tanggal 25 july 2020.
plot6terbanyak<-wachats_features %>%
mutate(datetime=as_date(datetime)) %>%
count(author) %>%
mutate(keterangan = glue("Author : {author}
Count : {n}")) %>%
arrange(desc(n)) %>%
head(6) %>%
ggplot(aes(x = reorder(author, n), y = n, text=keterangan)) +
geom_col(aes(fill = n), show.legend = F) +
theme(text = element_text(color = "#444444"),
panel.background = element_rect(fill = '#252a32'),
panel.grid.minor = element_line(color = '#bab6b8'),
panel.grid.major = element_line(color = '#696868'),
plot.title = element_text(size = 15, colour = "#c7c1c3"),
plot.subtitle = element_text(size = 12),
plot.caption = element_text(colour="#2b0905", face = "italic",vjust = 1,hjust = 1),
axis.title.x = element_text(hjust = 0,size = 8),
axis.text.x = element_text(colour = "#c7c1c3"),
axis.title.y = element_text(vjust =1,angle = 0, size=8),
axis.text.y = element_text(colour = "#c7c1c3"),
plot.background = element_rect(fill = "#252a32"))+
scale_fill_gradient(high = "#9e0d38", low = "#c7c1c3")+
ylab("") + xlab("") +
coord_flip() +
ggtitle("Jumlah Chat")
ggplotly(plot6terbanyak, tooltip="text")
kemudian saya ingin melihat siapa yang paling aktif chat di group tersebut. Saya mengambil 6 teratas, didapatkan informasi yang paling sering aktif chat dari awal group adalah beby, winda,saya,tebe,abi dan imam. Kemudian saya ingin melihat aktifitas chat mereka dari awal sampai tanggal 25 july 2020.
wachats_features %>%
mutate(datetime=as_date(datetime)) %>%
group_by(author) %>%
filter(author==c("Beby","Winda 64","Damar","Tebe","Abi","Imam")) %>%
count(datetime) %>%
arrange(desc(datetime)) %>%
ggplot(aes(x = datetime, y=n, group=author))+
geom_line(colour = "#9e0d38")+
theme(text = element_text(color = "#444444"),
panel.background = element_rect(fill = '#252a32'),
panel.grid.minor = element_line(color = '#bab6b8'),
panel.grid.major = element_line(color = '#696868'),
plot.title = element_text(size = 15, colour = "#c7c1c3"),
plot.subtitle = element_text(size = 12),
plot.caption = element_text(colour="#2b0905", face = "italic",vjust = 1,hjust = 1),
axis.title.x = element_text(hjust = 0,size = 8,color="#9e0d38"),
axis.text.x = element_text(colour = "#c7c1c3"),
axis.title.y = element_text(vjust =1,angle = 0, size=8,color="#9e0d38"),
axis.text.y = element_text(colour = "#c7c1c3"),
plot.background = element_rect(fill = "#252a32"))+
labs(title = "Trend 6 Orang Teraktif Berdasarkan Jumlah Chat\nRebahan People",
x = "Tanggal",
y = "Jumlah\nChat")+
facet_wrap(~author, ncol = 2, scales = "free_y")
Gambar diatas menunjukan bahwa beberapa orang yang paling aktif pun di group tersebut, sudah jarang berkomunikasi lagi di group. Dapat dilihat dari grafik tersebut hanya beby yang masih suka banyak chat. Selanjtnya saya akan mencari emoji apa yang sering digunakan pada oborlan-oborlan di group tersebut. Hasil yang didapatkan sangat banyak emoji yang digunakan, ini menunjukan beberapa karakter anggota dalam suatu group.
wachats_features %>%
filter(any_emoji == TRUE) %>%
unnest_longer(emoji) %>%
count(emoji, sort = TRUE) %>%
wordcloud2(
fontFamily = "Roboto Condensed",
backgroundColor = "#1e1e1e"
)
Kemudian saya mencoba lebih dalam emoji yang banyak digunakan untuk setiap orang, saya ambil contoh untuk 6 orang diatas didapatkan hasil sebagai berikut :
wachats_features %>%
filter(author==c("Beby","Winda 64","Damar","Tebe","Abi","Imam")) %>%
unnest(emoji) %>%
count(author, emoji, sort = TRUE) %>%
group_by(author) %>%
top_n(n = 10) %>%
ggplot(aes(x = reorder(emoji, n), y = n, fill = author)) +
geom_col(show.legend = FALSE) +
ylab("") +
xlab("") +
coord_flip() +
facet_wrap(~author, ncol = 2, scales = "free_y") +
ggtitle("Emoji yang sering digunakan")
Selanjutnya saya akan melakaukan proses data profiling menggunakan PCA dan K-mean Clustering uuntuk melihat dan mengelompokan beberapa anggota group kedalam kelompok yang memiliki kemiripan. Dibawah ini saya kan menggunakan 6 variabel saja yaitu jumlah chat, jumlah emoji, jumlah kata, jumlah capslock penulisan yang digunakan dan jumlah url yang dikirimkan.
library(dplyr)
library(tidyr)
library(tibble)
library(purrr)
library(ggplot2)
library(hrbrthemes)
library(FactoMineR)
library(janitor)
# Adjust data format for modeling -----------------------------------------
wachats_prep <-
wachats_features %>%
group_by(author) %>%
summarise(
n_chats = n(),
n_emojis=sum(n_emojis),
n_words=sum(n_words),
n_caps=sum(n_caps),
n_urls=sum(n_urls)) %>%
filter(!author %in% c("+62 815-8888-706","+6287883787670")) %>%
column_to_rownames("author")
wachats_prep_scale<-scale(wachats_prep)
# Run PCA -----------------------------------------------------------------
wachats_pca<-prcomp(wachats_prep_scale)
summary(wachats_pca)
#> Importance of components:
#> PC1 PC2 PC3 PC4 PC5
#> Standard deviation 2.072 0.66908 0.42085 0.2775 0.05694
#> Proportion of Variance 0.859 0.08953 0.03542 0.0154 0.00065
#> Cumulative Proportion 0.859 0.94853 0.98395 0.9993 1.00000
fancy_biplot <- function(PC, x="PC1", y="PC2", colors=c('white', '#9e0d38', '#e1e80e', '#6ae1e6')) {
# PC being a prcomp object
library(ggplot2)
data <- data.frame(obsnames=row.names(PC$x), PC$x)
plot <- ggplot(data, aes_string(x=x, y=y)) + geom_text(alpha=.4, size=3, aes(label=obsnames), color=colors[1])+theme(text = element_text(color = "#444444"),
panel.background = element_rect(fill = '#252a32'),
panel.grid.minor = element_line(color = '#4a4b4d'),
panel.grid.major = element_line(color = '#515254'),
plot.title = element_text(size = 15, colour = "#c7c1c3"),
plot.subtitle = element_text(size = 12),
plot.caption = element_text(colour="#2b0905", face = "italic",vjust = 1,hjust = 1),
axis.title.x = element_text(hjust = 0,size = 8,colour = "#c7c1c3"),
axis.text.x = element_text(colour = "#c7c1c3"),
axis.title.y = element_text(vjust =1,angle = 0, size=8,colour = "#c7c1c3"),
axis.text.y = element_text(colour = "#c7c1c3"),
plot.background = element_rect(fill = "#252a32"))
plot <- plot + geom_hline(aes(yintercept=0), size=.2,color=colors[2]) + geom_vline(aes(xintercept=0), size=.2, color=colors[2])
datapc <- data.frame(varnames=rownames(PC$rotation), PC$rotation)
mult <- min(
(max(data[,y]) - min(data[,y])/(max(datapc[,y])-min(datapc[,y]))),
(max(data[,x]) - min(data[,x])/(max(datapc[,x])-min(datapc[,x])))
)
datapc <- transform(datapc,
v1 = .7 * mult * (get(x)),
v2 = .7 * mult * (get(y))
)
plot <- plot + coord_equal() + geom_text(data=datapc, aes(x=v1, y=v2, label=varnames), size = 4, vjust=1, color=colors[3])
plot <- plot + geom_segment(data=datapc, aes(x=0, y=0, xend=v1, yend=v2), arrow=arrow(length=unit(0.2,"cm")), alpha=0.75, color=colors[4])
plot
}
fancy_biplot(wachats_pca)
Gambar diatas menunjukan sesuatu yang menarik menggunakan PCA, seperti Abi yang cenderung menggunakan banyak capslock pada setiap chatnya, saya dan winda yang cenderung lebih banyak menggunakan kata dalam setiap chat dan beby yang cenderung lebih banyak menggunakan emoji dan sering mengirimkan chat di group, serta beberapa orang seperti septi yang cendderung jarang chat atau aktif di group.
Selanjutnya saya akan masuk k tahap clustering menggunakan metode k-means untuk mengelompokan beberapa rnag tersebut dalam beberapa kelompok kemiripan
library(factoextra)
fviz_nbclust(wachats_prep_scale , kmeans, method = "wss")
RNGkind(sample.kind = "Rounding")
set.seed(2)
wachat_cluster <- kmeans(wachats_prep_scale, 5)
fviz_cluster(object = wachat_cluster, data = wachats_prep_scale)
Saya akan ambil 5 kelompok karena penurunan dari
wss sudah lebih sedikit dari grafik diatas. Setelah saya menentukan jumlah cluster yang akan dibuat, kemudian saya kan memvisualisasikannya kedalam suatu plot diatas dan didapatkan informasi bahwa beby masuk dalam kluster 1 karena karakterisiknya memang berbeda, sama seperti abi yang karakteristiknya berbeda dari yang lain, saya,tebe dan winda masuk dalam satu kluster 3, imam dan razaq masuk dalam kluster 4 dan yang tadi terihat jarang aktif masuk ke kluster 5.
Kemudian saya kan memvisualisasikan beberapa karateristik dari setiap cluster kedalam bar chart dibawah ini :
wachat_profiling <- wachats_prep %>%
mutate(cluster = as.factor(wachat_cluster$cluster)) %>%
group_by(cluster) %>%
summarise_all(mean)
wachat_profiling %>%
pivot_longer(cols = -1, names_to = "type", values_to = "score") %>%
ggplot(aes(x = cluster, y = score)) +
geom_col(aes(fill = cluster)) +
facet_wrap(~type)
Berdasarkan grafik diatas, kluster 1 orang yang paling sering chat dan paling panjang kalau udah chat serta sering menggunakan emoji di setiap chatnya. Kluster 2 orang yang lebih sering menggunakan capslock untuk setiap chatnya. Kluster 3 adalah orang-orang yang jumlah chat dan katanya cukup banyak. Kluster 4 adalah orang-orang yang secukupnya chat di group, tidak terlalu sering muncul dan tidak bisa dibilang jarang aktif juga.Sedangkan kluster 5 adalah orang-orang yang jarang sekali aktif di group percakapan.
Setelah melakukan EDA, PCA, dan clustering analysis didapatkan informasi yang dapat disimpulkan sebagai berikut :
beby yang paling terlihat, selalu chat dengan jumlah kata yang banyak dan sering menggunakan emoji.Semoga bermanfaat :)
A work by Briandamar Kencana
damarbrian@gmail.com