Karena data gak mungkin bohong

…dan karena bisa diolah sesuai pesanan


Maraknya bisnis analisis sentimen dalam beberapa tahun terakhir membuat saya jadi tertarik untuk mengetahui dan memahami implementasinya. Setelah bertukar informasi teknis dengan sejumlah pelaku bisnisnya, saya jadi tahu ada beberapa hal yang mungkin berdampak cukup signifikan terhadap hasil akhirnya.

Singkatnya, jika proses analisis sentimen dimulai dengan metode pengolahan yang salah, dampak pengolahan terhadap perhitungan statistik tentunya akan besar. Bayangkan jika ternyata impresi bahwa sebuah jenama (brand) atau seorang tokoh politik dinilai sangat baik padahal penilaian manual oleh manusia dari data yang sebenarnya dinilai sangat buruk. Tentunya impresi berpengaruh terhadap strategi yang diambil.

Saya coba batasi topik tulisan ini hanya sampai NLP untuk keperluan ML (Machine Learning) dan Statistik. Untuk bahasan seputar blunder-blunder di area Statistik yang sering terjadi, silakan pantau linimasa @lurino di Twitter.


NLP (Natural Language Processing) sangat membantu dalam pengolahan data terutama pada proses IR (information retrieval). Pada sumber data yang sifatnya unstructured, peran NLP menjadi sangat penting sebab jika hanya mengandalkan keywords atau regex rules, maka jumlah rules yang dibuat akan menjadi sangat banyak dan semakin sulit untuk dipelihara (unscalable) jika lingkup yang hendak dipantau mulai melebar.

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.

Demi kemudahan dalam membaca, saya bagi menjadi beberapa bagian menurut topik NLP dan membahas isu-isu yang ditemukan di lapangan (setelah mendapat informasi teknis implementasinya dari beberapa pegiat NLP/ML/Statistik di Jakarta) yang terlewatkan karena para pegiatnya terlalu fokus pada Machine Learning atau Statistik saja.

Sentence segmentation

Sentence segmentation adalah metode memecah teks menurut kalimat untuk mempermudah pemrosesan teks menjadi potongan-potongan yang kecil. Apa yang menjadi definisi akhir dari sebuah kalimat? Biasanya yang digunakan adalah tanda baca “.”, “?” dan “!”. Mudah, bukan?

Ternyata tidak!

Sebuah kalimat tidak selalu diakhiri oleh tiga tanda baca tersebut. Apalagi kalau dalam penulis teks asli kurang mematuhi aturan penggunaan tanda baca atau salah satu dari tiga tanda baca tersebut digunakan bukan sebagai akhir dari sebuah kalimat.

Contoh paling mudah adalah penggunaan tanda baca “.” sebagai akhir dari sebuah singkatan. Misalnya dalam sebuah kalimat “Acara tersebut bertempat di Jl. M.H. Thamrin No. 10, Jakarta.”. Algoritma sentence segmentation yang primitif akan memecah teks tersebut menjadi “Acara tersebut bertempat di Jl.”, “M.”, “H.”, “Thamrin No.”, “10, Jakarta.”. Jadi berantakan, ya?

Lalu bagaimana untuk menangani sebuah kutipan pernyataan lisan yang didalamnya tersusun dari sejumlah kalimat? Ternyata sama parahnya.

Saya contohkan paragraf berikut yang diambil dari sebuah artikel musik dari media Beritagar,

“Saya sangat bangga diminta jadi bagian dari kelompok yang luar biasa ini bersama Casey Chaos dan Ross Robinson. Karir saya di thrash metal terbentuk dari kecintaan saya terhadap genre punk,” ujar Lombardo dilansir Blabbermouth. Sebelumnya Lombardo dan rekannya itu pernah bersama di kelompok Grip Inc.

Sentence segmenter yang umum digunakan akan memecah paragraf tersebut menjadi

  • “Saya sangat bangga diminta jadi bagian dari kelompok yang luar biasa ini bersama Casey Chaos dan Ross Robinson.
  • Karir saya di thrash metal terbentuk dari kecintaan saya terhadap genre punk,” ujar Lombardo dilansir Blabbermouth.
  • Sebelumnya Lombardo dan rekannya itu pernah bersama di kelompok Grip Inc.

Bagi manusia yang suka musik mungkin akan familier dengan nama-nama “Casey Chaos” dan “Ross Robinson” (ada di kalimat pertama), lalu bisa menarik hubungan konteks dengan genre musik “punk” (ada di kalimat kedua) lewat grup band “Amen”. Tapi sayangnya komputer belum bisa sampai ke titik itu, kecuali sudah dibekali dengan pengetahuan terlebih dahulu.

Ribet? Itu baru permulaan…

Tokenization

Tokenization adalah metode pemecah teks menjadi token-token yang berurutan (ini istilah representasi kata atau frasa di NLP). Proses tokenization primitif biasanya hanya memecah teks dengan whitespace sebagai pembagi, lalu mengubahnya menjadi huruf kecil supaya seragam.

Misalnya, teks “Ini ibu Budi.” akan menjadi “ini”, “ibu”, “budi.” Masalah muncul ketika ada teks lain “Budi sedang belajar.”, yang akan menjadi “budi”, “sedang”, “belajar.”.

Bagi manusia mudah untuk memahami bahwa token “budi.” dan “budi” merujuk ke konsep yang sama. Tapi sayangnya komputer tidak menganggap seperti itu. Dua token tersebut akan diperlakukan berbeda.

Lalu, ada pula algoritma tokenization yang menghilangkan tanda baca. Saya contohkan seperti ini…

Contoh sederhana implementasi tokenizer menggunakan bahasa pemrograman Python

Algoritma ini akan menghasilkan token “ini”, “ibu”, “budi” untuk kalimat pertama. dan “budi”, “sedang”, “belajar” untuk kalimat kedua.

Masalah selesai? Ternyata belum. Bagaimana dengan kata yang mengandung tanda baca di dalamnya? Seperti pada “Jean-Claude van Damme” atau pada “PDI-P”? Hasilnya akan menjadi “jean”, “claude” , “van”, “damme” dan “pdi”, “p”.

Tentunya algoritma tokenizer bisa disesuaikan untuk menghilangkan tanda baca yang ada di awal dan di akhir kata saja.

Dari implementasi tokenizer yang saya amati, hampir semuanya menghasilkan satu kata untuk setiap token. Sayangnya dalam bahasa Indonesia (dan bahasa lainnya juga, sih), kita juga mengenal frasa yang terdiri dari dua kata atau lebih untuk merujuk ke sebuah entity. Contohnya “rumah sakit”, “surat tugas”, “nada dasar” dan masih banyak lagi.

Tapi apakah banyak yang peduli soal ini? Sepertinya ada… tapi sedikit. Hajar, Bleh!

Stopwords

Bisa dibilang hampir semua implementasi NLP untuk keperluan ML baik itu dalam bahasa Inggris ataupun secara spesifik bahasa Indonesia menggunakan metode stopwords removal.

Sekadar mengingatkan saja, stopwords removal menghilangkan sejumlah kelas kata penghubung ataupun yang jumlahnya banyak namun tidak mempengaruhi konten dokumen secara keseluruhan sebagai bagian dari pre-processing. Ini dilakukan biasanya untuk meningkatkan performa sistem agar sistem bisa secara efektif dimanfaatkan untuk mengolah konten yang benar-benar dianggap penting saja.

Misalkan teks salah satu judul berita, “Jam Malam Ancam Warga Thailand Tak Nonton Bareng Piala Dunia” (saya ambil dari Liputan6 hari ini) token-token “jam”, “malam”, “tak” dan “bareng” ada dalam stopwords list standar.

Padahal, token “jam” dan “malam” membentuk sebuah frasa “jam malam”, lalu “nonton” dan “bareng” juga membentuk frasa “nonton bareng”. Jika ke-empat token tersebut dihilangkan dari judul maka token-token yang tersisa adalah “ancam”, “warga”, “thailand”, “nonton”, “piala”, “dunia”.

Jika fokusnya analisis hanyalah “piala dunia”, mungkin tidak terlalu signifikan dengan hilangnya “jam malam” dan “nonton bareng”, tapi tentu konteks dengan “nonton bareng” “piala dunia” di “thailand” yang sedang diberlakukan “jam malam” tidak akan diperoleh.

Jadi, penyesuaian stopwords list perlu dilakukan setiap kali sebuah proyek analisis dimulai. Memang bukan sesuatu yang melelahkan, tapi jika tidak dilakukan maka ini akan dapat mengakibatkan salah interpretasi terhadap data.

Konyolnya… banyak yang tidak melakukan hal itu. Kebanyakan para penggiat ML yang kurang paham NLP akan menggunakan stopwords list yang dicomot dari NLP framework yang mereka gunakan dan biasanya itu hanya diambil dari surat kabar daring (online) atau Wikipedia.

Stemming

Stemming adalah metode mapping token ke bentuk dasarnya, namun bentuk dasar tersebut tidak berarti sama dengan akar kata (root word).

Contohnya kata “politisasi” tergantung dari algoritma stemming bahasa Indonesia yang digunakan bisa menjadi “politis”. Lalu kata “depolitisasi” akan menjadi “depolitis”.

Masalah muncul ketika kita hendak menemukan token-token yang bermakna sama. Dua token yang saya contohkan di atas, “politisasi” dan “depolitisasi” sangat berhubungan erat. Namun karena setelah melalui stemming, keduanya menjadi dua stemmed tokens yang berbeda (“politis” dan “depolitis”).

Isu lain adalah ketika algoritma stemming diperlakukan pukul rata, akibatnya entity akan terpotong dan sering kali “hilang”.

Contohnya, jika algoritma stemming digunakan untuk menghilangkan suffix-wati”. Untuk token “peragawati”, “biarawati” atau “wartawati” sudah benar karena akan menjadi “peraga”, “biara” dan “warta”. Namun bagaimana untuk nama seseorang seperti “Megawati” atau “Kurniawati”?

Mumet, ya? Sabar, itu belum seberapa.

Word sense disambiguation

Katakan persoalan-persoalan di atas sudah terselesaikan. Dengan memecah teks menjadi kalimat, dari kalimat menjadi token. Ternyata masih ada isu lain, yaitu Word sense disambiguation (WSD).

WSD ada sebagai solusi masalah mengidentifikasi makna sebuah kata (yang bisa punya banyak maknanya) tergantung konteks dan penempatannya dalam sebuah kalimat. Contoh paling sederhana, kata “tahu”. Menurut Kateglo, yang isi untuk kata tersebut diambil dari KBBI III, ada 7 makna kata “tahu” jika digunakan sebagai kata kerja dan satu makna jika kata tersebut digunakan sebagai nomina (kata benda).

Entry kata “tahu” di Kateglo.

Setelah dokumen teks terpecah-pecah menjadi serialised tokens, maka akan sulit mengidentifikasi makna sebuah token. Terlebih jika token tersebut ada dalam stopwords list.

Tapi tenang saja, implementasi NLP yang fokusnya lebih untuk keperluan Statistik atau ML biasanya tidak menghiraukan adanya perbedaan makna, semua dipukul rata, semua dianggap hanya punya satu makna. Dampaknya? Sangat tergantung konteks dan domain dari dokumen teks yang diolah. Artinya bisa besar atau SANGAT BESAR!

Semantic similarity

Nah, area ini jarang sekali disentuh. Mungkin tidak banyak yang paham apa masalahnya, dan kalaupun paham masih bingung tentang solusinya.

Semantic similarity bisa dibilang adalah kebalikan dari Word Sense Disambiguation karena dua atau lebih token bisa memiliki makna yang sama.

Ketika merujuk ke entity, manusia bisa punya banyak alias untuk entity tersebut. Suka-suka gue, deh! Mungkin begitu kira-kira yang ada dibenak penulis. Contohnya entity “Probowo”, “Prabowo Subianto”, dan “Prabowo Subianto Djojohadikusumo” TERNYATA (drum roll!) merujuk ke orang yang sama. Demikian pula (supaya adil), “Joko Widodo”, “Jokowi” dan “Joko Widono bin Noto Mihardjo”.

Ingin contoh yang ekstrim? Perhatikan gambar berikut,

Gambar di atas adalah formula regex untuk penyebutan nama Muammar al-Gaddafi, atau Qaddafi, atau Khadafi, atau …aaaarrgghh, ada 34,500 lebih kemungkinan cara penulisan namanya!

Masalah di dunia nyata seperti apa? Simak baik-baik tweet @lurino berikut ini,

https://twitter.com/lurino/status/465460101466177536
https://twitter.com/lurino/status/465462507331547136

Saya sependapat dengan apa yang disampaikan @lurino bahwa manusia dapat dengan mudah membedakan, namun tidak bagi mesin (komputer).

Lagi-lagi… apakah mereka yang katanya diminta untuk memonitor media sosial paham tentang masalah ini? Mungkin saja. Tapi mungkin ada yang baru tahu setelah baca tulisan ini.

TF*IDF dan cosine similarity

Bahasan ini sudah sedikit masuk ke ranah ML dan Statistik. Namun karena di NLP, dua tf*idf dan cosine similarity umum digunakan, jadi terpaksa saya bahas.

Dalam domain IR, tf*idf digunakan untuk memberikan bobot dokumen teks untuk mencari tahu relevansinya dalam sebuah corpus (kumpulan dokumen).

Sedikit mengingatkan, tf (term frequency) adalah nilai frekuensi kemunculan token dalam sebuah dokumen dan idf (inverse document frequency) adalah ukuran penyebaran token tersebut di dalam corpus. Lalu, cosine similarity adalah cara mengukur kesamaan dari dua vektor dari inner product space dengan menggunakan cosinus sudut diantara dua vektor tersebut.

Vektor yang saya sebut di atas merujuk pada representasi token yang sudah dikonversi menjadi binari (0 dan 1) karena pada dasarnya komputer adalah alat untuk menghitung.

Untuk contoh dua frasa sederhana A = “ini ibu budi” dan B = “itu bapak budi”, setelah dilakukan proses tokenisasi dan digabungkan hasilnya maka akan diperoleh daftar token “bapak”, “budi”, “ibu”, “ini”, dan “itu”. Lalu vektorisasi dilakukan ke masing-masing frasa akan diperoleh hasil a = “0, 1, 1, 1, 0” untuk frasa pertama dan b = “1, 1, 0, 0, 1” untuk frasa kedua dengan 0 sebagai representasi tidak ditemukannya token dalam teks dan 1 sebagai representasi ditemukannya token dalam teks.

Jika stopwords list digunakan, maka kata “ini” dan “itu” akan dihilangkan sehingga daftar token keseluruhan akan menjadi “bapak”, “budi” dan “ibu” saja. Representasi vektornya pun akan menjadi singkat menjadi a = “0, 1, 1” untuk frasa pertama dan b = “1, 1, 0” untuk frasa kedua.

Sampai di sini, kita bisa saja menghitung cosine similarity berdasarkan representasi vektor.

sim(A, B) = a . b / |a| * |b|

Namun karena diyakini tidak semua kata diciptakan sama, oleh karena itu bobotnya dalam corpus teks pun tidak akan sama. tf*idf digunakan untuk memberikan bobot setiap token, misalnya dengan memberikan bobot lebih rendah untuk token yang sering muncul (selaras dengan konsep stopwords).

Jika kita memutuskan untuk tidak menggunakan stopwords maka nilai a = “0.0, 0.8, 0.7, 0.1, 0.0” dan b = “0.6, 0.8, 0.0, 0.0, 0.1”. Nilai-nilai tersebut hanyalah karangan saya saja. Bobot tf*idf untuk token “bapak” (0.6) lebih kecil dari token “ibu” (0.7) karena token “bapak” lebih sering muncul dalam corpus.

Dalam skenario implementasi umum, tf*idf bekerja sangat baik. SANGAT baik! Namun ada satu-dua kasus yang membuat penggunaan tf*idf menjadi tidak efektif.

Skenario pertama, jika corpus hanya terdiri dari satu dokumen saja. Jika tidak menggunakan tf*idf, nilai cosine similarity yang akan diperoleh adalah 1. Namun ketika tf*idf digunakan, semua representasi token akan menjadi 0 dan tidak dapat dihitung karena 0/0 akan menghasilkan pesan error “a division by zero”.

Skenario kedua, jika corpus hanya terdiri dari dua dokumen A dan B (seperti contoh di atas). Jika tidak menggunakan tf*idf, nilai cosine similarity yang diperoleh adalah 0.666666666667.

Contoh program Python yang digunakan untuk menghitung Cosine Similarity tanpa stopwords dan tf*idf

Namun ketika stopwords dan tf*idf digunakan, token “budi” menjadi common token, dan akan menjadi 0 karena idf-nya adalah 0. “bapak” dan “ibu” adalah token unik untuk masing-masing frasa dan akan mendapat nilai dotproduct 0.

Dua skenario tersebut mungkin akan SANGAT jarang ditemukan di implementasi di dunia nyata dan sebagai tindakan preventif adalah selalu punya corpus teks yang cukup dan melakukan smoothing.

Perolehan data Twitter

Media sosial Twitter sering digunakan sebagai sumber data analisis sentimen. Sayangnya tidak ada cara untuk mendapatkan keseluruhan data Twitter kecuali lewat partnernya. Memang Twitter memberikan akses ke API server secara gratis (yang umum dimanfaatkan oleh pegiat NLP/ML adalah streaming API-nya), namun perlu diingat bahwa data diperoleh lewat beberapa metode yang berbeda dan ini menjadi pertanyaan penting seputar efektifitas IR-nya.

Metode pertama, akses streaming API dengan keywords matching. Metode ini dapat dengan mudah dipertanyakan karena sifat alami dari pendefinisian keyword itu sendiri. Seberapa sering keyword tersebut diperbarui? Seberapa banyak jumlah keywords yang disiapkan? Apakah analis benar paham tentang domain informasi yang hendak diperoleh lewat streaming API twitter? Tahu bahwa Twitter membatasi jumlah keywords per query? Semua tentunya bisa dijawab, entah memang jawabannya benar-benar dilakukan atau sekadar ngeles.

Metode kedua, akses streaming API dengan geo location query. Perlu diketahui koordinat geo location yang diberikan sewaktu query akan berbentuk kotak. Jika query dilakukan untuk lingkup Indonesia, tentu area Malaysia, Singapura, Brunei Darussalam, East Timor serta sedikit area Papua Nugini dan Filipina akan terikut serta. Tidak percaya? Silakan lihat peta berikut.

Lalu apa masalahnya? Mungkin anda lupa bahwa Malaysia, Singapura dan Brunei Darussalam masih satu rumpun dengan Indonesia sehingga ada banyak kesamaan bahasa yang digunakan. Demikian pula bahasa yang digunakan di Filipina dengan beberapa daerah di Sulawesi atau bahasa di Papua Nugini dengan bahasa di Papua. Walau yang terakhir mungkin tidak terlalu jadi masalah.

Mungkin ada yang berpikir solusinya adalah dengan mengidentifikasi bahasa. Perlu diketahui pula bahwa sebagian besar implementasi language detection gagal mengidentifikasi bahasa-bahasa yang saya sebutkan di atas. Belum lagi ketika bahasa yang digunakan bercampur dengan bahasa lain, seperti bahasa Inggris dan bahasa-bahasa daerah yang sering tercampur (code-mixing, lihat bahasan khusus tentang ini di bawah) dalam penggunaan sehari-hari.

Alasan pembenaran yang paling sering saya dengan adalah “metode sampling”. Biasanya saya akan bertanya apakah si pegiat tahu berapa jumlah persis jumlah keseluruhan tweet sehingga tahu benar berapa persen sampel yang diperoleh. Saya belum pernah tahu Twitter mengeluarkan jumlah persis Tweet dari suatu negara, kalau pun pernah saya yakin itu hanya estimasi dan saya yakin Twitter pun mengalami kendala identifikasi seperti yang saya sebutkan di atas.

Retweet

Pernah dengar pernyataan retweet is not endorsement? Jika seseorang melakukan retweet (RT), tidak selamanya ia mendukung konten yang di-retweet. Bisa jadi hanya berbagi dengan pengikutnya supaya menjadi bahan diskusi. Bahan yang di-retweet bisa berupa pernyataan seseorang atau headline sebuah media online.

Konyolnya, semua implementasi analisis sentimen yang saya ketahui memberlakukan itu retweet sebagai individual tweet. Bayangkan jika sebuah headline bernada negatif di-retweet oleh ribuan orang? Apakah benar bahwa ribuan orang tersebut beropini sama dengan media online yang menurunkan headline tersebut? Apakah ribuan orang yang melakukan retweet benar-benar adalah manusia dan bukan bot?

Penjelasan paling sederhana yang bisa saya berikan: Worldwide Trending Topic adalah tuhan baru.

Kondisi di atas diperparah dengan kebiasaan pengguna yang membalas lewat inline retweet.

@A: ih… gak OK kok! RT @B: XYZ pemimpin yang hebat dan tegas!

Apakah XYZ dari contoh tweet di atas akan dinilai positif ataukah negatif?

Ada yang pernah menanggapi pada saya, bahwa konten inline RT dihilangkan dan tidak dihitung sehingga menjadi seperti ini…

@A: ih… gak OK kok!

Nah, yang “gak OK” itu apa atau siapa?

Code-mixing dan miskinnya ungkapan emosional

Para pengguna bahasa Inggris sepertinya harus berterimakasih banyak kepada Shakespeare yang telah “menciptakan” istilah-istilah baru yang banyak diantaranya mewakili emosi manusia. Sayangnya, Shakespeare bukan orang Indonesia dan tidak berbahasa Indonesia semasa hidupnya. Sehingga kita masih miskin kata-kata yang bisa digunakan untuk merepresentasikan suatu kondisi emosional.

Selain itu pada bahasa Inggris, kontribusi besar Robert Plutchik dengan psychoevolutionary theory of emotion-nya membuat kita semakin mudah untuk mengklasifikasikan respon emosional manusia.

Plutchik’s Wheel of Emotions

Tertarik untuk tahu padanannya dalam bahasa Indonesia? Ivan Lanin telah berbaik hati menerjemahkannya.

Ya, benar. Bahasa Indonesia sangat miskin perbendaharaan kata yang merepresentasikan emosi manusia karena akan memicu peminjaman kata (code-mixing) bahasa asing atau bahasa daerah dalam pengunaannya sehari-hari. Dikaitkan dengan analisis sentimen, tentunya ini berpengaruh besar karena mesin penganalisis sentimen biasanya hanya mampu menangani satu atau dua bahasa yang sudah didefinisikan sebelumnya.

Mau contoh yang ekstrim? Perhatikan tweet berikut.

https://twitter.com/lantip/status/477880903071305728

Belum lama ini saya menulis soal miskinnya perbendaharaan kata bahasa Indonesia yang dapat digunakan sebagai penghinaan. Bentuk penghinaan yang populer digunakan di Indonesia adalah kosa kata yang erat dengan alat kelamin dan binatang. Jarang ditemui dalam pengunaan sehari-hari, bentuk penghinaan eufemisme.

Lalu apa relevansi code-mixing dan klasifikasi emosi dengan implementasi analisis sentimen bahasa Indonesia? BUAAAAANYAAAAAAAAAKKKK!!!!!!!!

Soal klasifikasi emosi, tanggapan yang paling sering saya dapat adalah bisa diselesaikan dengan menerjemahkan dari bahasa Inggris atau dari bahasa daerah ke bahasa Indonesia. Biasanya akan saya tanggapi dengan pertanyaan apakah si pemberi tanggapan tersebut mengetahui bahwa bahasa Inggris lebih kompleks daripada bahasa Indonesia dan jika dilakukan mapping pun masih belum bisa mewakili konteks.

Terjemahan kata “like” dalam bahasa Inggris ke bahasa Indonesia

Yakin bahwa hanya dengan menerjemahkan saja cukup?

Soal code-mixing, dari semua implementasi yang sudah dibagi informasi teknisnya kepada saya. Semua hanya mengambil kata-kata yang sudah teridentifikasi secara manual saja (ada dalam word dictionary).

Lalu bagaimana dengan istilah-istilah baru yang muncul dari waktu ke waktu atau istilah-istilah lokal yang hanya digunakan dalam sebuah kelompok sosial tertentu saja?

Sudah merasa pusing?


Apakah masalah-masalah di atas ada solusinya? Tentu saja ada.