Tuesday, November 24, 2015

IndeXuara: Algoritma Fonetik Bahasa Indonesia



Background

Ini bermula dari keisengan saya membuat app android untuk membantu anak saya belajar membaca. Dalam aplikasi tersebut si anak diminta membaca kata yang ditampilkan. Dengan memanfaatkan engine Speech Recognizer dari Android, aplikasi akan menilai apakah pengucapannya sudah benar.

Secara umum Speech Recognizer Android bekerja sangat baik. Namun terkadang kata yang dihasilkan memiliki penulisan yang sedikit berbeda dengan kata yang ditampilkan meskipun pengucapannya sama. Sebagai contoh, untuk kata BAKPAU, meskipun si anak dapat mengucapkan dengan benar ternyata kata yang dihasilkan oleh Speech Recognizer adalah BAKPAO. Akibatnya ucapan tersebut dianggap salah.

Salah satu cara untuk menangani hal ini adalah dengan memberi toleransi. Misal jika hanya satu huruf yang berbeda ucapannya tetap dianggap benar. Metrik Levenshtein Distance cocok untuk digunakan untuk hal ini. Tapi efek dari penggunaan teknik ini ternyata aplikasi jadi terlalu permisif. BABE dibaca BABU akan dianggap benar. Sebaliknya, karena anak kecil biasanya masih agak cadel, saya ingin jika kata TARI dilafalkan seperti TALI tetap dianggap benar.


Solusinya adalah menggunakan algoritma fonetik, yaitu algoritma yang dapat mengelompokkan kata/nama berdasarkan pengucapannya. Pada dasarnya algoritma ini adalah sebuah fungsi f di mana f(x1) = f(x2) jika x1 & x2 adalah kata dengan pengucapan yang sama/mirip.
 

Algoritma fonetik yang populer diantaranya adalah Soundex dan Metaphone. Namun keduanya ini dirancang khusus untuk bahasa Inggris. Untuk bahasa-bahasa Eropa lainnya pun biasanya diperlukan pengembangan lebih lanjut. Untuk Bahasa Indonesia tidak banyak referensi mengenai algoritma fonetik. Saya menemukan algoritma Priyadi yang dibuat oleh, well, Priyadi . Namun algoritma tersebut masih belum memenuhi kebutuhan saya, terutama karena kurang penanganan dalam variasi diftong dan penyederhanaan konsonan yang kurang sesuai keinginan saya. Akhirnya saya pun tergerak untuk membuat sendiri algoritma fonetik untuk Bahasa Indonesia.

Specification

Saya mendefinisikan algoritma saya dalam 2 Level. Level pertama fokus pada penyederhanaan diftong dan penyederhanaan konsonan secara terbatas. Level ini dapat menemukan kemiripin pengucapan dalam variasi penulisan. Contoh:
  • f1(“ANGPAU”) = f1(“ANGPAO”) = f1(“ANGPAW”)
  • f1(“FAISAL”) = f1(“FEISAL”)
  • f1(“AL-QAEDA”) = f1(“AL-KAIDAH”)
  • f1(“BAKSO”) = f1(“BASO”)
  • f1(“SYUKUR”) = f1(“SUKUR”)
  • f1(“RAMAI”) = f1(“RAME”)
  • f1(“TAKSI”) = f1(“TAXI”)
  • f1(“BOBBY”) = f1(“BOBI”)
  • f1(“KWALITAS”) = f1(“KUALITAS”)
  • f1(“SAITOU HAJIME”) = f1(“SAITOH HAJIME”)
  • f1(“MAYA”) = f1(“MAIA”)
Algoritma Level 1 adalah sebagai berikut:
  1. Ganti konsonan yang muncul berulang menjadi hanya satu huruf
  2. Penyederhanaan diftong:
    • AI, AE, AY, EI, EY  => E 
    • AU, AO, AW, OU, OW => O 
    • EU => E
    • IE => I
  3. Penyederhanaan konsonan:
    • SY => S
    • KH di akhir suku kata => dihilangkan
      KH di awal suku kata => K
    • CH di akhir suku kata => dihilangkan
      CH di awal suku kata => C 
    • B di akhir suku kata => P 
    • D di akhir suku kata => T 
    • G di akhir suku kata => dihilangkan (kecuali G di NG) 
    • H => dihilangkan 
    • K di akhir suku kata => dihilangkan 
    • Q di akhir suku kata => dihilangkan
      selain itu => K
    • V => F
    • X => S
  4. Substitusi Semivokal:
    • W setelah U,O => dihilangkan
      W sebelum U => dihilangkan

      selain itu => I
    • Y setelah I, E => dihilangkan
      Y setelah S dan bukan akhir suku kata => dihilangkan
      Y setelah N dan bukan akhir suku kata => Y (dipertahankan)
      Y sebelum I => dihilangkan
      selain itu => I
  5. Ulang langkah 1 (konsonan ganda mungkin muncul kembali setelah penggantian)
Sedangkan level kedua melakukan penyederhaaan konsonan lebih lanjut. Efeknya adalah penggolongan konsonan menjadi lebih longgar. Cocok untuk mengakomodasi mereka yang kesulitan melafalkan "el" atau “ep” :). Contoh:
  • f2(KERAS) = f2(KELAS)
  • f2(SAIFUDDIN) = f2(SAEPUDIN)
  • f2(REZA) = f2(RAISA)   <= Dua nama ini memang cocok bersanding :)
Algoritma Level 2 adalah sebagai berikut:
  1. Terapkan algoritma level 1
  2. Penyederhanaan konsonan lanjutan:
    • NG, NY => N
    • D => T
    • C, J, Z => S
    • B, F => P
    • R => L
    • G => K
  3. Ganti konsonan yang muncul berulang menjadi hanya satu huruf
Hal yang perlu diperhatikan jika input kata menggunakan ejaan lama, maka perlu dilakukan normalisasi menjadi EYD sebelum menerapkan algoritma di atas. Selain itu perlu dipertimbangkan juga bagaimana menentukan akhir suku kata. Dalam implementasi yang saya buat, saya hanya menggunakan aturan sederhana yang mungkin tidak terlalu akurat.

Room for Improvements

  • Kondisi saat ini penyederhanaan diftong masih terlalu agresif. Kombinasi vokal AI atau AU tidak selalu merupakan diftong. Misalkan pada kata DAI, MAU, JAUH.  Solusi yang terpikir adalah menggunakan daftar pengecualian. 
  • Penyederhanaan konsonan V juga sedikit ambigu. Orang Indonesia biasa melafalkan V persis seperti F. Sementara dalam bahasa-bahasa Eropa juga Sansekerta lafal V lebih mendekati W. Pada akhirnya saya memang memutuskan V disubstitusi dengan F, meskipun ini berakibat f1("DEVI") != f1("DEWI"). Tapi setidaknya f2("NOVEMBER") = f2("NOPEMBER").
  • Penanganan vokal schwa. Schwa adalah vokal dengan bunyi e pepet (IPA: ə) yang dilafalkan "setengah hati". Biasanya muncul di belakang R (atau terkadang L). Contohnya E pada kata BERAPA yang sering terreduksi menjadi BRAPA. Atau sebaliknya dimunculkan: PRANCIS ==> PERANCIS. Algoritma di atas belum bisa mendeteksi kemiripan ini. Masalahnya tidak semua E di belakang R merupakan schwa. Contoh: PERAK atau PERAN. Satu opsi solusinya adalah justru selalu menambahkan E di depan R jika R tidak didahului huruf vokal. Yang pasti masih perlu dipikirkan lebih lanjut.    
  • Penanganan spasi atau tanda baca yang terkadang muncul dalam nama. seperti (-) atau ( ' ). Saat ini algoritma di atas mengasumsikan tidak ada karakter-karakter tersebut.
Demikian hasil keisengan saya. Karena terinspirasi dari Soundex, saya namakan algoritma ini IndeXuara. Implementasinya dalam Java bisa diunduh di sini. Semoga bermanfaat.

App belajar membaca dapat diunduh dari Android Play Store: ABACA


Update 27/11/2015:
Perbaikan aturan untuk semivokal W & Y: kondisi lebih spesifik & dipindahkan ke belakang. Pada dasarnya W & Y selalu diganti dengan U & I (sebelumnya W & Y di awal suku kata tidak diganti)