Setelah mengikuti praktikum ini, mahasiswa diharapkan mampu:
stringr, untuk mengambil informasi tertentu
dari data teks, khususnya data hasil web scraping.Materi praktikum ini merupakan kelanjutan dari materi kuliah Pertemuan 3: Data Management (Manajemen Data).
Sebelum memulai praktikum, kita perlu menyiapkan beberapa package yang akan digunakan.
Package yang dibutuhkan adalah:
stringr → untuk mengolah dan mencari pola pada data
teks menggunakan RegEx.dplyr → untuk melakukan manajemen dan manipulasi data,
seperti memilih, membuat, dan mengubah peubah.tokenizers → untuk memecah teks menjadi unit yang lebih
kecil, seperti kata atau kalimat.tm → untuk membantu proses pengolahan dan preprocessing
data teks.stopwords → untuk menyediakan daftar kata umum yang
biasanya dihapus dalam analisis teks, seperti yang,
dan, di, dan sebagainya.wordcloud → untuk membuat visualisasi kata dalam bentuk
word cloud.textclean → untuk membantu membersihkan teks, misalnya
karakter atau pola tertentu yang tidak diperlukan.katadasaR → untuk melakukan stemming Bahasa
Indonesia, yaitu mengubah kata berimbuhan menjadi bentuk kata
dasarnya.Package dapat di-install menggunakan sintaks berikut:
install.packages(c("stringr", "dplyr", "tokenizers", "tm", "stopwords", "wordcloud", "textclean"))
# Khusus stemming Bahasa Indonesia, gunakan salah satu:
# install.packages("devtools")
# devtools::install_github("nurandi/katadasaR") # Sastrawi versi RRegular Expression (RegEx) adalah pola yang digunakan untuk mencari, mencocokkan, atau mengambil bagian tertentu dari sebuah teks.
Sederhananya, RegEx dapat dianggap sebagai aturan pencarian.
Misalnya kita memiliki teks:
Samsung Galaxy A54 RAM 8GB ROM 256GB
Dengan RegEx, kita dapat mencari informasi tertentu dari teks tersebut, misalnya:
8 sebagai informasi RAM,256 sebagai informasi memori internal,Samsung sebagai merek HP.Jadi, RegEx sangat berguna ketika kita memiliki data teks dalam jumlah banyak dan ingin mengambil informasi tertentu secara otomatis.
Beberapa simbol RegEx yang sering digunakan adalah:
| Simbol | Arti | Contoh sederhana |
|---|---|---|
() |
Mengelompokkan pola | (Samsung|Xiaomi) |
\| |
OR / salah satu pola | Samsung\|Xiaomi |
[a-z] |
Huruf kecil a sampai z | samsung |
[A-Z] |
Huruf besar A sampai Z | Samsung |
[0-9] |
Angka 0 sampai 9 | 8, 256 |
\\w |
Huruf, angka, atau underscore | Galaxy_A54 |
\\d |
Angka | 8, 256 |
\\s |
Spasi atau whitespace | spasi antar kata |
+ |
Satu atau lebih kemunculan | \\d+ → satu atau lebih angka |
* |
Nol atau lebih kemunculan | a* |
^ |
Menandai awal teks | ^Samsung |
$ |
Menandai akhir teks | GB$ |
RegEx dapat digunakan di R dengan dua cara, yaitu menggunakan
base R atau package tambahan seperti
stringr.
Pada praktikum ini, kita akan lebih banyak menggunakan package
stringr karena penamaan fungsinya lebih konsisten dan lebih
mudah dibaca.
Beberapa fungsi stringr yang sering digunakan
adalah:
| Fungsi | Kegunaan |
|---|---|
str_detect() |
Memeriksa apakah suatu pola terdapat di dalam teks |
str_extract() |
Mengambil bagian teks pertama yang sesuai dengan pola |
str_extract_all() |
Mengambil semua bagian teks yang sesuai dengan pola |
str_locate() |
Menentukan posisi suatu pola di dalam teks |
str_replace() |
Mengganti pola pertama yang ditemukan |
str_replace_all() |
Mengganti semua pola yang ditemukan |
Sebagai gambaran sederhana, misalkan kita memiliki teks:
Misalkan kita memiliki beberapa data teks berikut:
Data di atas memiliki bentuk yang berbeda-beda. Ada yang hanya terdiri dari huruf, hanya angka, maupun gabungan huruf, angka, dan simbol tertentu. Sekarang kita akan mencoba beberapa fungsi RegEx untuk melihat bagaimana R dapat mengenali pola tertentu dari data teks tersebut.
## [1] "Roti Bangsawan" "RB@email.id" "roti_bang29@gmail.com"
Fungsi str_subset() digunakan untuk mengambil elemen
yang mengandung pola tertentu. Pada contoh ini, kita mencari elemen yang
mengandung huruf "a".
## [1] FALSE TRUE FALSE TRUE TRUE
Fungsi str_detect() digunakan untuk memeriksa apakah
suatu pola terdapat di dalam teks.
Hasil yang diberikan berupa:
TRUE jika pola ditemukanFALSE jika pola tidak ditemukanPola [0-9] berarti mencari angka dari 0 sampai 9.
## [[1]]
## character(0)
##
## [[2]]
## [1] "08128712"
##
## [[3]]
## character(0)
##
## [[4]]
## [1] "29"
##
## [[5]]
## [1] "382"
Fungsi str_extract_all() digunakan untuk mengambil semua
pola yang sesuai.
Pola [0-9]+ berarti mencari satu atau lebih angka yang
muncul secara berurutan.
## [[1]]
## [1] "Roti" "Bangsawan"
##
## [[2]]
## character(0)
##
## [[3]]
## [1] "RB" "email" "id"
##
## [[4]]
## [1] "roti" "bang" "gmail" "com"
##
## [[5]]
## [1] "F" "BKSB"
Pola [A-Za-z]+ digunakan untuk mengambil kumpulan huruf,
baik huruf besar maupun huruf kecil.
## [1] "Roti Bangsawan" "08128712" "RB@email.net"
## [4] "roti_bang29@gmail.net" "F382BKSB"
Fungsi str_replace() digunakan untuk mengganti pola
pertama yang ditemukan.
Tanda | berarti OR (atau).
Jadi pola "com|id" berarti mencari "com"
atau "id", kemudian menggantinya dengan
"net".
## [1] "#oti##angsawan" "08128712" "###email#id"
## [4] "roti#bang29#gmail#com" "#382####"
Fungsi str_replace_all() digunakan untuk mengganti semua
pola yang ditemukan.
Tanda ^ di dalam [] berarti
selain.
Jadi pola [^a-z0-9] berarti mencari karakter selain
huruf kecil a-z dan angka 0-9, kemudian
menggantinya dengan simbol #.
Perlu diperhatikan bahwa RegEx bersifat
case-sensitive, sehingga huruf besar juga tidak
termasuk dalam pola a-z.
## [1] "Roti Bangsawan" "08128712" "RBemailid"
## [4] "rotibang29gmailcom" "F382BKSB"
Fungsi str_remove_all() digunakan untuk menghapus semua
karakter yang sesuai dengan pola.
Pada contoh ini, karakter yang dihapus adalah:
._@Latihan Kecil
Sebelum menjalankan setiap sintaks di atas, coba tebak terlebih dahulu hasil yang akan muncul.
Kemudian perhatikan perbedaan antara:
## [1] NA "08128712" NA "29" "382"
dan
## [[1]]
## character(0)
##
## [[2]]
## [1] "08128712"
##
## [[3]]
## character(0)
##
## [[4]]
## [1] "29"
##
## [[5]]
## [1] "382"
Diskusikan bersama:
Apa perbedaan hasil dari str_extract() dan
str_extract_all()?
str_extract() hanya mengambil pola pertama yang
ditemukan pada setiap elemen, sedangkan str_extract_all()
mengambil semua pola yang sesuai.
Perhatikan contoh data hasil web scraping berikut.
Data masih tersimpan dalam satu kolom teks, padahal di dalam setiap elemen sebenarnya terdapat beberapa informasi sekaligus, yaitu:
x <- c(
"93.142 km,Automatic,Tangerang Selatan,",
"33.827 km,Automatic,Jakarta Utara,",
"54.801 km,Automatic,Tangerang Selatan,",
"25.160 km,Manual,Tangerang Selatan,",
"95.389 km,Automatic,Jakarta Utara,",
"140.903 km,Automatic,Tangerang Selatan,",
"103.106 km,Automatic,Bekasi,",
"46.694 km,Automatic,Jakarta Utara,",
"24.619 km,Manual,Tangerang Selatan,",
"22.670 km,Automatic,Tangerang Selatan,",
"94.946 km,Automatic,Bekasi,",
"104.055 km,Automatic,Tangerang Selatan,",
"63.203 km,Automatic,Jakarta Utara,",
"79.013 km,Automatic,Tangerang Selatan,",
"81.128 km,Manual,Jakarta Utara,",
"44.889 km,Automatic,Jakarta Utara,",
"98.215 km,Automatic,Tangerang Selatan,",
"73.975 km,Automatic,Jakarta Utara,"
)
head(x)## [1] "93.142 km,Automatic,Tangerang Selatan,"
## [2] "33.827 km,Automatic,Jakarta Utara,"
## [3] "54.801 km,Automatic,Tangerang Selatan,"
## [4] "25.160 km,Manual,Tangerang Selatan,"
## [5] "95.389 km,Automatic,Jakarta Utara,"
## [6] "140.903 km,Automatic,Tangerang Selatan,"
Jika kita melihat salah satu elemen:
93.142 km,Automatic,Tangerang Selatan,
sebenarnya terdapat tiga informasi:
93.142 km → jarak tempuhAutomatic → tipe transmisiTangerang Selatan → wilayahNamun, semua informasi tersebut masih tergabung dalam satu teks.
Dalam analisis data, kondisi seperti ini perlu dirapikan agar setiap informasi memiliki peubah atau kolom masing-masing.
Pertanyaan:
Bagaimana cara memisahkan data tersebut menjadi tiga peubah:
Jarak_TempuhTipeAsalSebelum melihat sintaksnya, coba perhatikan pola pada data.
Petunjuk:
Setiap informasi dipisahkan oleh tanda koma ,.
Jadi, kita dapat memanfaatkan tanda koma tersebut sebagai pola pemisah.
strsplit() + RegEx sebagai Pemisah (Delimiter)Setelah mengetahui bahwa setiap informasi dipisahkan oleh tanda koma
,, kita dapat menggunakan fungsi strsplit()
untuk memecah teks tersebut.
Pola:
",\\s*"
berarti:
, → pisahkan teks pada setiap tanda koma\\s* → abaikan spasi yang mungkin muncul setelah
komaJadi, setiap elemen pada data x akan dipecah menjadi
beberapa bagian.
Kita dapat melihat hasilnya dengan:
## [[1]]
## [1] "93.142 km" "Automatic" "Tangerang Selatan"
##
## [[2]]
## [1] "33.827 km" "Automatic" "Jakarta Utara"
##
## [[3]]
## [1] "54.801 km" "Automatic" "Tangerang Selatan"
##
## [[4]]
## [1] "25.160 km" "Manual" "Tangerang Selatan"
##
## [[5]]
## [1] "95.389 km" "Automatic" "Jakarta Utara"
##
## [[6]]
## [1] "140.903 km" "Automatic" "Tangerang Selatan"
##
## [[7]]
## [1] "103.106 km" "Automatic" "Bekasi"
##
## [[8]]
## [1] "46.694 km" "Automatic" "Jakarta Utara"
##
## [[9]]
## [1] "24.619 km" "Manual" "Tangerang Selatan"
##
## [[10]]
## [1] "22.670 km" "Automatic" "Tangerang Selatan"
##
## [[11]]
## [1] "94.946 km" "Automatic" "Bekasi"
##
## [[12]]
## [1] "104.055 km" "Automatic" "Tangerang Selatan"
##
## [[13]]
## [1] "63.203 km" "Automatic" "Jakarta Utara"
##
## [[14]]
## [1] "79.013 km" "Automatic" "Tangerang Selatan"
##
## [[15]]
## [1] "81.128 km" "Manual" "Jakarta Utara"
##
## [[16]]
## [1] "44.889 km" "Automatic" "Jakarta Utara"
##
## [[17]]
## [1] "98.215 km" "Automatic" "Tangerang Selatan"
##
## [[18]]
## [1] "73.975 km" "Automatic" "Jakarta Utara"
Namun, hasil strsplit() masih berbentuk
list. Agar lebih mudah dianalisis, kita ubah hasil
tersebut menjadi data.frame.
max_length <- max(sapply(split_words, length))
split_words_df <- data.frame(
t(sapply(split_words, function(w) {
length(w) <- max_length
return(w)
})),
stringsAsFactors = FALSE
)Sintaks di atas digunakan untuk:
Selanjutnya, kita beri nama kolom sesuai informasi yang terdapat di dalam data.
## Jarak_Tempuh Tipe Asal
## 1 93.142 km Automatic Tangerang Selatan
## 2 33.827 km Automatic Jakarta Utara
## 3 54.801 km Automatic Tangerang Selatan
## 4 25.160 km Manual Tangerang Selatan
## 5 95.389 km Automatic Jakarta Utara
## 6 140.903 km Automatic Tangerang Selatan
## 7 103.106 km Automatic Bekasi
## 8 46.694 km Automatic Jakarta Utara
## 9 24.619 km Manual Tangerang Selatan
## 10 22.670 km Automatic Tangerang Selatan
## 11 94.946 km Automatic Bekasi
## 12 104.055 km Automatic Tangerang Selatan
## 13 63.203 km Automatic Jakarta Utara
## 14 79.013 km Automatic Tangerang Selatan
## 15 81.128 km Manual Jakarta Utara
## 16 44.889 km Automatic Jakarta Utara
## 17 98.215 km Automatic Tangerang Selatan
## 18 73.975 km Automatic Jakarta Utara
Sekarang data yang sebelumnya masih berada dalam satu kolom teks sudah berhasil dipisahkan menjadi tiga peubah:
Jarak_TempuhTipeAsalJarak_Tempuh Menjadi NumerikPerhatikan peubah Jarak_Tempuh.
Nilainya masih berbentuk teks, misalnya:
"93.142 km"
Padahal untuk analisis lebih lanjut, jarak tempuh sebaiknya berbentuk numerik.
Karena tanda titik . pada data tersebut merupakan
pemisah ribuan, bukan tanda desimal, maka proses yang dilakukan
adalah:
Misalnya:
"93.142 km"
akan menjadi:
"93142 km"
Selanjutnya, kita masukkan hasil tersebut kembali ke dalam data.
df_oke <- split_words_df
df_oke$Jarak_Tempuh <- w3
df_oke$Tipe <- as.factor(df_oke$Tipe)
df_oke$Asal <- as.factor(df_oke$Asal)Untuk memeriksa tipe masing-masing peubah:
## 'data.frame': 18 obs. of 3 variables:
## $ Jarak_Tempuh: num 93142 33827 54801 25160 95389 ...
## $ Tipe : Factor w/ 2 levels "Automatic","Manual": 1 1 1 2 1 1 1 1 2 1 ...
## $ Asal : Factor w/ 3 levels "Bekasi","Jakarta Utara",..: 3 2 3 3 2 3 1 2 3 3 ...
Dan untuk melihat hasil akhirnya:
## Jarak_Tempuh Tipe Asal
## 1 93142 Automatic Tangerang Selatan
## 2 33827 Automatic Jakarta Utara
## 3 54801 Automatic Tangerang Selatan
## 4 25160 Manual Tangerang Selatan
## 5 95389 Automatic Jakarta Utara
## 6 140903 Automatic Tangerang Selatan
## 7 103106 Automatic Bekasi
## 8 46694 Automatic Jakarta Utara
## 9 24619 Manual Tangerang Selatan
## 10 22670 Automatic Tangerang Selatan
## 11 94946 Automatic Bekasi
## 12 104055 Automatic Tangerang Selatan
## 13 63203 Automatic Jakarta Utara
## 14 79013 Automatic Tangerang Selatan
## 15 81128 Manual Jakarta Utara
## 16 44889 Automatic Jakarta Utara
## 17 98215 Automatic Tangerang Selatan
## 18 73975 Automatic Jakarta Utara
Sekarang data sudah lebih siap untuk dianalisis:
Jarak_Tempuh → numerikTipe → factorAsal → factorstr_split() dari Package stringrSelain menggunakan strsplit() dari base R, kita juga
dapat menggunakan fungsi str_split() dari package
stringr.
Cara ini lebih ringkas karena hasil pemisahan dapat langsung dibuat menjadi bentuk tabel.
df_alt <- x %>%
str_split(",\\s*", simplify = TRUE) %>%
as.data.frame(stringsAsFactors = FALSE) %>%
select(1:3)Pada sintaks di atas:
str_split() digunakan untuk memisahkan teks.",\\s*" berarti teks dipisahkan pada tanda koma,
serta spasi setelah koma diabaikan.simplify = TRUE membuat hasil pemisahan langsung
berbentuk matriks.as.data.frame() mengubah hasilnya menjadi data
frame.select(1:3) mengambil tiga kolom pertama yang kita
butuhkan.Selanjutnya, kita beri nama masing-masing kolom:
Peubah Jarak_Tempuh masih berbentuk teks, misalnya:
"93.142 km"
Oleh karena itu, kita perlu membersihkannya agar menjadi numerik.
df_alt$Jarak_Tempuh <- as.numeric(
str_extract(
str_remove_all(df_alt$Jarak_Tempuh, "[.]"),
"[0-9]+"
)
)Proses tersebut dilakukan secara berurutan:
str_remove_all(..., "[.]") menghapus tanda titik.str_extract(..., "[0-9]+") mengambil bagian
angkanya.as.numeric() mengubah hasilnya menjadi data
numerik.Selanjutnya, kita ubah peubah kategorik menjadi factor:
Untuk melihat hasil akhirnya:
## Jarak_Tempuh Tipe Asal
## 1 93142 Automatic Tangerang Selatan
## 2 33827 Automatic Jakarta Utara
## 3 54801 Automatic Tangerang Selatan
## 4 25160 Manual Tangerang Selatan
## 5 95389 Automatic Jakarta Utara
## 6 140903 Automatic Tangerang Selatan
## 'data.frame': 18 obs. of 3 variables:
## $ Jarak_Tempuh: num 93142 33827 54801 25160 95389 ...
## $ Tipe : Factor w/ 2 levels "Automatic","Manual": 1 1 1 2 1 1 1 1 2 1 ...
## $ Asal : Factor w/ 3 levels "Bekasi","Jakarta Utara",..: 3 2 3 3 2 3 1 2 3 3 ...
Sekarang kita memiliki hasil yang sama seperti pada Cara 1, tetapi dengan sintaks yang lebih ringkas.
Gunakan data df_alt untuk menjawab beberapa pertanyaan
berikut.
Periksa apakah nilai Jarak_Tempuh pada
df_oke dan df_alt menghasilkan nilai yang
sama.
## [1] TRUE
Jika hasilnya TRUE, berarti kedua cara menghasilkan
nilai Jarak_Tempuh yang sama.
## # A tibble: 2 × 2
## Tipe Rata_rata_Jarak
## <fct> <dbl>
## 1 Automatic 76589.
## 2 Manual 43636.
Perhatikan apakah mobil dengan transmisi Automatic dan
Manual memiliki rata-rata jarak tempuh yang berbeda.
boxplot(
Jarak_Tempuh ~ Asal,
data = df_alt,
xlab = "Wilayah",
ylab = "Jarak Tempuh (km)",
main = "Jarak Tempuh Mobil Berdasarkan Wilayah"
)Boxplot digunakan untuk membandingkan distribusi
Jarak_Tempuh pada masing-masing wilayah.
Perhatikan median, penyebaran data, dan kemungkinan adanya nilai yang jauh berbeda dari observasi lainnya.
Sekarang kita akan menggunakan contoh data hasil web scraping produk handphone.
Data terdiri atas dua peubah utama:
nama_hp → berisi nama lengkap produkharga_hp → berisi harga dalam format RupiahNamun, sebenarnya di dalam nama_hp masih terdapat
beberapa informasi yang dapat kita ambil, seperti:
Selain itu, harga_hp juga masih berbentuk teks sehingga
perlu diubah menjadi numerik sebelum dapat digunakan untuk analisis.
data_hp <- data.frame(
nama_hp = c(
"Xiaomi Redmi 9C Smartphone [4GB/ 64GB]",
"Asus Zenfone 3 ZE520KL Smartphone [32GB/ 4GB]",
"Xiaomi Poco M3 Pro 5G Smartphone [4GB/64GB]",
"Samsung Galaxy S21 FE 8/256GB RAM 8 ROM 256 Handphone Hp Smartphone Android Garansi Resmi",
"Vivo Y15S 3/64 GB RAM 3 ROM 64GB Handphone Hp Smartphone Android Original Murah Garansi Resmi",
"OPPO A31 Handphone Android - Black [4/128]",
"Advan NasaPlus 2GB 16GB Smartphone Android10 Garansi Resmi",
"Samsung Galaxy A04e 3/32 GB RAM 3GB 32GB Smartphone Android",
"Infinix Hot 30i 8/128 RAM 8GB ROM 128GB 8 128 GB HP Android",
"POCO C40 3/32 GB - Resmi"
),
harga_hp = c(
"Rp1.589.000", "Rp1.299.000", "Rp2.250.000", "Rp7.099.000",
"Rp1.480.000", "Rp2.547.902", "Rp845.000", "Rp1.137.000",
"Rp1.475.000", "Rp1.258.000"
),
stringsAsFactors = FALSE
)
data_hp## nama_hp
## 1 Xiaomi Redmi 9C Smartphone [4GB/ 64GB]
## 2 Asus Zenfone 3 ZE520KL Smartphone [32GB/ 4GB]
## 3 Xiaomi Poco M3 Pro 5G Smartphone [4GB/64GB]
## 4 Samsung Galaxy S21 FE 8/256GB RAM 8 ROM 256 Handphone Hp Smartphone Android Garansi Resmi
## 5 Vivo Y15S 3/64 GB RAM 3 ROM 64GB Handphone Hp Smartphone Android Original Murah Garansi Resmi
## 6 OPPO A31 Handphone Android - Black [4/128]
## 7 Advan NasaPlus 2GB 16GB Smartphone Android10 Garansi Resmi
## 8 Samsung Galaxy A04e 3/32 GB RAM 3GB 32GB Smartphone Android
## 9 Infinix Hot 30i 8/128 RAM 8GB ROM 128GB 8 128 GB HP Android
## 10 POCO C40 3/32 GB - Resmi
## harga_hp
## 1 Rp1.589.000
## 2 Rp1.299.000
## 3 Rp2.250.000
## 4 Rp7.099.000
## 5 Rp1.480.000
## 6 Rp2.547.902
## 7 Rp845.000
## 8 Rp1.137.000
## 9 Rp1.475.000
## 10 Rp1.258.000
Perhatikan bahwa data hasil scraping biasanya memiliki format yang tidak selalu konsisten.
Misalnya informasi RAM dan memori internal dapat ditulis sebagai:
4GB/64GB
8/256GB
RAM 8 ROM 256
3/32 GB
Karena itu, kita perlu mencari pola tertentu menggunakan RegEx.
harga_hp Menjadi NumerikPeubah harga_hp masih berbentuk teks seperti:
"Rp1.589.000"
Agar dapat digunakan untuk perhitungan, kita perlu mengubahnya
menjadi angka 1589000.
Prosesnya dilakukan dalam beberapa tahap.
Contohnya:
Rp1.589.000
menjadi:
Rp1589000
Lihat hasilnya:
## nama_hp
## 1 Xiaomi Redmi 9C Smartphone [4GB/ 64GB]
## 2 Asus Zenfone 3 ZE520KL Smartphone [32GB/ 4GB]
## 3 Xiaomi Poco M3 Pro 5G Smartphone [4GB/64GB]
## 4 Samsung Galaxy S21 FE 8/256GB RAM 8 ROM 256 Handphone Hp Smartphone Android Garansi Resmi
## 5 Vivo Y15S 3/64 GB RAM 3 ROM 64GB Handphone Hp Smartphone Android Original Murah Garansi Resmi
## 6 OPPO A31 Handphone Android - Black [4/128]
## 7 Advan NasaPlus 2GB 16GB Smartphone Android10 Garansi Resmi
## 8 Samsung Galaxy A04e 3/32 GB RAM 3GB 32GB Smartphone Android
## 9 Infinix Hot 30i 8/128 RAM 8GB ROM 128GB 8 128 GB HP Android
## 10 POCO C40 3/32 GB - Resmi
## harga_hp harga_numerik
## 1 Rp1.589.000 1589000
## 2 Rp1.299.000 1299000
## 3 Rp2.250.000 2250000
## 4 Rp7.099.000 7099000
## 5 Rp1.480.000 1480000
## 6 Rp2.547.902 2547902
## 7 Rp845.000 845000
## 8 Rp1.137.000 1137000
## 9 Rp1.475.000 1475000
## 10 Rp1.258.000 1258000
Sekarang kita memiliki dua bentuk harga:
harga_hp → teks asli hasil scrapingharga_numerik → angka yang siap digunakan untuk
analisisSelanjutnya kita ingin mengambil informasi merek dari
nama_hp.
Pada sebagian besar data, merek berada pada kata pertama.
Misalnya:
Xiaomi Redmi 9C Smartphone
maka mereknya adalah:
Xiaomi
Kita dapat mengambil kata pertama menggunakan:
## merek_v1
## Advan Asus Infinix OPPO POCO Samsung Vivo Xiaomi
## 1 1 1 1 1 2 1 2
Pola [A-Za-z]+ berarti mengambil satu atau lebih huruf
besar maupun huruf kecil.
Namun, pada data hasil scraping tidak selalu dapat diasumsikan bahwa kata pertama merupakan merek.
Misalnya jika terdapat data:
Handphone Samsung A12 ...
maka kata pertama adalah Handphone, padahal mereknya
adalah Samsung.
Untuk menangani kondisi seperti ini, kita dapat mengecualikan beberapa kata yang bukan merupakan merek.
merek_v2 <- str_extract(
data_hp$nama_hp,
"\\b(?!Handphone\\b|HP\\b|Hp\\b)[A-Za-z]+\\b"
)
table(merek_v2)## merek_v2
## Advan Asus Infinix OPPO POCO Samsung Vivo Xiaomi
## 1 1 1 1 1 2 1 2
Pada pola tersebut digunakan negative lookahead:
(?!...)
yang berarti:
jangan mengambil pola tertentu.
Pada contoh ini, kata Handphone, HP, dan
Hp tidak akan dianggap sebagai merek.
Teknik seperti ini berguna ketika format data hasil scraping tidak konsisten.
Informasi RAM dan memori internal memiliki format yang cukup beragam.
Contohnya:
4GB/64GB
8GB ROM 256GB
3GB 32GB
Salah satu pendekatan yang dapat digunakan adalah mengambil semua
angka yang berada sebelum tulisan GB.
## [[1]]
## [1] "4" "64"
##
## [[2]]
## [1] "32" "4"
##
## [[3]]
## [1] "4" "64"
##
## [[4]]
## [1] "256"
##
## [[5]]
## [1] "64" "64"
##
## [[6]]
## character(0)
##
## [[7]]
## [1] "2" "16"
##
## [[8]]
## [1] "32" "3" "32"
##
## [[9]]
## [1] "8" "128" "128"
##
## [[10]]
## [1] "32"
Pola:
[0-9]+(?=\\s?GB)
dapat dibaca sebagai:
[0-9]+ → cari satu atau lebih angka(?=...) → angka tersebut harus diikuti pola
tertentu\\s? → boleh terdapat satu spasi atau tidakGB → diikuti tulisan GBJadi, RegEx akan mengambil angka yang berhubungan dengan informasi kapasitas dalam GB.
Selanjutnya kita membuat aturan sederhana:
get_ram <- function(v) {
if (length(v) >= 2) {
min(as.numeric(v))
} else {
NA
}
}
get_rom <- function(v) {
if (length(v) >= 2) {
max(as.numeric(v))
} else {
NA
}
}Kemudian fungsi tersebut diterapkan pada seluruh data:
data_hp$RAM_GB <- sapply(
angka_gb,
get_ram
)
data_hp$Memori_Internal_GB <- sapply(
angka_gb,
get_rom
)Lihat hasil akhirnya:
## nama_hp
## 1 Xiaomi Redmi 9C Smartphone [4GB/ 64GB]
## 2 Asus Zenfone 3 ZE520KL Smartphone [32GB/ 4GB]
## 3 Xiaomi Poco M3 Pro 5G Smartphone [4GB/64GB]
## 4 Samsung Galaxy S21 FE 8/256GB RAM 8 ROM 256 Handphone Hp Smartphone Android Garansi Resmi
## 5 Vivo Y15S 3/64 GB RAM 3 ROM 64GB Handphone Hp Smartphone Android Original Murah Garansi Resmi
## 6 OPPO A31 Handphone Android - Black [4/128]
## 7 Advan NasaPlus 2GB 16GB Smartphone Android10 Garansi Resmi
## 8 Samsung Galaxy A04e 3/32 GB RAM 3GB 32GB Smartphone Android
## 9 Infinix Hot 30i 8/128 RAM 8GB ROM 128GB 8 128 GB HP Android
## 10 POCO C40 3/32 GB - Resmi
## RAM_GB Memori_Internal_GB harga_numerik
## 1 4 64 1589000
## 2 4 32 1299000
## 3 4 64 2250000
## 4 NA NA 7099000
## 5 64 64 1480000
## 6 NA NA 2547902
## 7 2 16 845000
## 8 3 32 1137000
## 9 8 128 1475000
## 10 NA NA 1258000
Sekarang beberapa informasi yang sebelumnya masih tersembunyi di
dalam teks nama_hp sudah berhasil dibuat menjadi peubah
baru.
Perhatian
Pendekatan:
angka terkecil = RAM dan angka terbesar = memori internal
merupakan heuristik, yaitu aturan praktis yang digunakan untuk membantu proses ekstraksi.
Aturan tersebut tidak selalu benar untuk seluruh data.
Pada data nyata, hasil ekstraksi tetap perlu diperiksa karena format hasil web scraping dapat berbeda-beda atau tidak konsisten.
Gunakan data data_hp untuk mengerjakan latihan
berikut.
Perbaiki hasil merek_v2 agar merek seperti:
samsung
diubah menjadi:
Samsung
Gunakan fungsi:
Tipe_GaransiBuat peubah baru bernama Tipe_Garansi dengan
ketentuan:
"Resmi" jika nama_hp mengandung kata
"Garansi Resmi" atau "Resmi""Tidak Diketahui" jika tidak ditemukanGunakan fungsi str_detect().
Setelah sebelumnya kita belajar mengambil informasi dari data teks menggunakan RegEx, sekarang kita akan belajar membersihkan dan menyiapkan data teks agar lebih siap digunakan untuk analisis.
Proses ini disebut preprocessing teks.
Secara umum, preprocessing teks terdiri atas empat tahapan utama:
"yang", "dan", "di", dan
sebagainya.Sebagai ilustrasi, kita menggunakan beberapa contoh komentar berikut:
komentar <- c(
"Yg bisa membubarkan DPR memang rakyat, tp nyatanya susah!! https://youtu.be/xxxxx",
"Jangan kasih kendor menyuarakan hapus tunjangan DPR!!! #DemoRakyat",
"Bismillah ya Allah semoga tidak ada demo terjadi di tempat saya :)",
"Hapus DPR???",
"Saudara2 silakan berdemo, sampaikan aspirasi dgn baik yaa...",
"Semoga pejuang2 rakyat diberi keselamatan dan kesehatan, aamiin 123"
)
komentar## [1] "Yg bisa membubarkan DPR memang rakyat, tp nyatanya susah!! https://youtu.be/xxxxx"
## [2] "Jangan kasih kendor menyuarakan hapus tunjangan DPR!!! #DemoRakyat"
## [3] "Bismillah ya Allah semoga tidak ada demo terjadi di tempat saya :)"
## [4] "Hapus DPR???"
## [5] "Saudara2 silakan berdemo, sampaikan aspirasi dgn baik yaa..."
## [6] "Semoga pejuang2 rakyat diberi keselamatan dan kesehatan, aamiin 123"
Data di atas masih berupa teks mentah. Masih terdapat huruf besar dan kecil, URL, tanda baca, hashtag, angka, serta bentuk kata yang belum seragam.
Kita akan membersihkannya secara bertahap.
Text cleaning adalah proses membersihkan teks dari karakter atau bagian yang tidak dibutuhkan.
Pada tahap ini kita akan:
clean_text <- komentar %>%
str_to_lower() %>%
str_remove_all("http\\S+|www\\.\\S+") %>%
str_remove_all("#\\S+") %>%
str_replace_all("[[:punct:]]", " ") %>%
str_remove_all("[0-9]+") %>%
str_squish()
clean_text## [1] "yg bisa membubarkan dpr memang rakyat tp nyatanya susah"
## [2] "jangan kasih kendor menyuarakan hapus tunjangan dpr"
## [3] "bismillah ya allah semoga tidak ada demo terjadi di tempat saya"
## [4] "hapus dpr"
## [5] "saudara silakan berdemo sampaikan aspirasi dgn baik yaa"
## [6] "semoga pejuang rakyat diberi keselamatan dan kesehatan aamiin"
Penjelasan fungsi yang digunakan:
str_to_lower() → mengubah seluruh huruf menjadi huruf
kecil.str_remove_all("http\\S+|www\\.\\S+") → menghapus
URL.str_remove_all("#\\S+") → menghapus hashtag.str_replace_all("[[:punct:]]", " ") → mengganti tanda
baca dengan spasi.str_remove_all("[0-9]+") → menghapus angka.str_squish() → merapikan spasi berlebih.Sebagai contoh:
"Jangan kasih kendor menyuarakan hapus tunjangan DPR!!! #DemoRakyat"
setelah proses cleaning akan menjadi lebih sederhana, misalnya:
"jangan kasih kendor menyuarakan hapus tunjangan dpr"
Tujuan text cleaning adalah membuat format teks menjadi lebih seragam sebelum masuk ke tahap berikutnya.
Setelah teks dibersihkan, langkah berikutnya adalah tokenization.
Tokenization adalah proses memecah teks menjadi unit yang lebih kecil.
Unit tersebut dapat berupa:
## [[1]]
## [1] "yg" "bisa" "membubarkan" "dpr" "memang"
## [6] "rakyat" "tp" "nyatanya" "susah"
##
## [[2]]
## [1] "jangan" "kasih" "kendor" "menyuarakan" "hapus"
## [6] "tunjangan" "dpr"
Misalnya teks:
"jangan kasih kendor menyuarakan hapus tunjangan dpr"
akan dipecah menjadi:
"jangan"
"kasih"
"kendor"
"menyuarakan"
"hapus"
"tunjangan"
"dpr"
Jadi, satu kalimat yang panjang sekarang sudah berubah menjadi kumpulan kata.
Selain kata, kita juga dapat memecah teks berdasarkan kalimat.
contoh_paragraf <- "Demo berlangsung damai. Massa membubarkan diri sore hari."
tokenize_sentences(contoh_paragraf)## [[1]]
## [1] "Demo berlangsung damai." "Massa membubarkan diri sore hari."
Pada contoh tersebut, paragraf akan dipecah menjadi dua kalimat.
Setelah teks dipecah menjadi kata-kata, masih terdapat banyak kata umum yang sering muncul tetapi biasanya kurang memberikan informasi penting.
Kata-kata tersebut disebut stopwords.
Contoh stopwords Bahasa Indonesia antara lain:
yang
dan
di
ke
dari
untuk
pada
Kita dapat mengambil daftar stopwords Bahasa Indonesia menggunakan
package stopwords.
## [1] "ada" "adalah" "adanya" "adapun" "agak" "agaknya"
## [7] "agar" "akan" "akankah" "akhir" "akhiri" "akhirnya"
## [13] "aku" "akulah" "amat"
Selanjutnya, kita membuat fungsi untuk menghapus stopwords dari setiap kumpulan token.
Kemudian fungsi tersebut diterapkan pada seluruh komentar.
## [[1]]
## [1] "yg" "membubarkan" "dpr" "rakyat" "tp"
## [6] "susah"
##
## [[2]]
## [1] "kasih" "kendor" "menyuarakan" "hapus" "tunjangan"
## [6] "dpr"
Setelah tahap ini, kata-kata umum yang terdapat dalam daftar stopwords akan dihapus sehingga kita dapat lebih fokus pada kata-kata yang lebih informatif.
Tahap berikutnya adalah stemming.
Stemming adalah proses mengubah kata berimbuhan menjadi bentuk kata dasarnya.
Contohnya:
menyuarakan → suara
berdemo → demo
kesehatan → sehat
Untuk Bahasa Indonesia, salah satu algoritma stemming yang umum digunakan adalah Nazief-Adriani.
Di R, proses ini dapat dilakukan menggunakan package
katadasaR.
Package ini perlu di-install terlebih dahulu melalui GitHub.
# Install hanya satu kali
# install.packages("devtools")
# devtools::install_github("nurandi/katadasaR")
library(katadasaR)
stem_kalimat <- function(tokens) {
sapply(tokens, katadasar)
}
hasil_stem <- lapply(
token_bersih,
stem_kalimat
)
hasil_stem[1:2]Perlu diperhatikan bahwa chunk di atas menggunakan:
eval=FALSE
karena package katadasaR perlu di-install terlebih
dahulu dari GitHub.
Jika package sudah berhasil di-install, eval=FALSE dapat
diubah menjadi:
eval=TRUE
agar kode dapat langsung dijalankan.
Sekarang kita sudah memahami setiap tahap preprocessing secara terpisah.
Selanjutnya, beberapa tahapan text cleaning dapat kita gabungkan ke dalam satu fungsi agar lebih praktis.
preprocess_id <- function(text) {
text %>%
str_to_lower() %>%
str_remove_all("http\\S+|www\\.\\S+") %>%
str_remove_all("#\\S+") %>%
str_replace_all("[[:punct:]]", " ") %>%
str_remove_all("[0-9]+") %>%
str_squish()
}Kemudian fungsi tersebut diterapkan pada seluruh komentar.
hasil_akhir <- data.frame(
teks_asli = komentar,
teks_bersih = sapply(komentar, preprocess_id),
row.names = NULL
)
hasil_akhir## teks_asli
## 1 Yg bisa membubarkan DPR memang rakyat, tp nyatanya susah!! https://youtu.be/xxxxx
## 2 Jangan kasih kendor menyuarakan hapus tunjangan DPR!!! #DemoRakyat
## 3 Bismillah ya Allah semoga tidak ada demo terjadi di tempat saya :)
## 4 Hapus DPR???
## 5 Saudara2 silakan berdemo, sampaikan aspirasi dgn baik yaa...
## 6 Semoga pejuang2 rakyat diberi keselamatan dan kesehatan, aamiin 123
## teks_bersih
## 1 yg bisa membubarkan dpr memang rakyat tp nyatanya susah
## 2 jangan kasih kendor menyuarakan hapus tunjangan dpr
## 3 bismillah ya allah semoga tidak ada demo terjadi di tempat saya
## 4 hapus dpr
## 5 saudara silakan berdemo sampaikan aspirasi dgn baik yaa
## 6 semoga pejuang rakyat diberi keselamatan dan kesehatan aamiin
Sekarang kita dapat membandingkan:
teks_asli → teks sebelum preprocessingteks_bersih → teks setelah proses cleaningSecara sederhana, alur preprocessing teks yang kita lakukan adalah:
Teks Mentah
↓
Text Cleaning
↓
Tokenization
↓
Stopwords Removal
↓
Stemming
↓
Teks Siap Dianalisis
Gunakan data komentar di atas untuk mengerjakan latihan berikut.
Tambahkan langkah pada fungsi preprocess_id() untuk
menghapus emoji atau karakter non-ASCII.
Gunakan:
Setelah proses stopwords removal, gabungkan seluruh token menjadi satu kumpulan kata.
Kemudian hitung frekuensi kemunculan setiap kata menggunakan fungsi:
Tampilkan 5 kata yang paling sering muncul.
wordcloud.Pada praktikum ini, kita telah mempelajari dua bagian utama, yaitu manajemen data menggunakan Regular Expression (RegEx) dan preprocessing data teks.
Ringkasan tahapan yang telah dipelajari adalah sebagai berikut:
| Tahapan | Tujuan | Fungsi R yang Digunakan |
|---|---|---|
| Ekstraksi dengan RegEx | Mengambil informasi tertentu dari data teks dan membentuk peubah baru | str_split(), str_detect(),
str_extract(), str_extract_all(),
str_remove_all() |
| Konversi tipe data | Mengubah data teks menjadi format yang sesuai untuk analisis | as.numeric(), as.factor() |
| Text Cleaning | Membersihkan teks dari URL, tanda baca, angka, hashtag, dan spasi berlebih | str_to_lower(), str_remove_all(),
str_replace_all(), str_squish() |
| Tokenization | Memecah teks menjadi kata atau kalimat | tokenize_words(),
tokenize_sentences() |
| Stopwords Removal | Menghapus kata-kata umum yang kurang memberikan informasi penting | stopwords::stopwords() |
| Stemming | Mengubah kata berimbuhan menjadi bentuk kata dasar | katadasaR::katadasar() |
Secara sederhana, alur yang telah kita pelajari dapat digambarkan sebagai berikut:
Data Mentah
↓
Manajemen / Ekstraksi Informasi
↓
Penyesuaian Tipe Data
↓
Text Cleaning
↓
Tokenization
↓
Stopwords Removal
↓
Stemming
↓
Data Siap untuk Analisis Lanjutan
Setelah data teks selesai dipreproses, tahapan selanjutnya dapat berupa:
Tahapan tersebut akan dipelajari pada materi selanjutnya.