Normalisasi teks adalah penyeragaman bentuk teks sebelum teks dihitung, dan setiap keputusan normalisasi menghilangkan sebagian informasi. Topik ini membahas tiga keputusan yang paling sering diambil, yaitu penyeragaman huruf besar-kecil, penggantian tanda baca dengan spasi, dan perlakuan terhadap angka. Satu pipeline kecil berbasis re dijalankan pada dua kalimat berbeda, dan demo interaktif di browser menerapkan keputusan yang sama secara langsung. Setelah membaca topik ini, pilihan normalisasi dapat disesuaikan dengan jenis informasi yang masih diperlukan oleh model.
Normalisasi sebagai penyeragaman bentuk#
Model teks memperlakukan rangkaian huruf secara harfiah. Kata March dan march dianggap dua jenis token yang berbeda, demikian pula Room 4 dan Room 12 sebelum angkanya disentuh. Normalisasi menyamakan bentuk-bentuk tersebut agar hitungan token terkumpul pada satu jenis, dengan risiko menyatukan hal yang seharusnya tetap berbeda.
Tiga keputusan normalisasi yang paling umum meliputi penyeragaman huruf besar-kecil, penghapusan tanda baca, dan perlakuan terhadap angka. Huruf kecil mengurangi jumlah jenis token secara drastis pada teks nyata. Tanda baca dihapus karena jarang menjadi fitur yang berguna pada model frekuensi, sedangkan angka kadang dipertahankan dan kadang dibuang. Setiap keputusan menghapus informasi tertentu, dan informasi itulah yang perlu diketahui sebelum memilih.
Keputusan huruf besar-kecil#
Penyeragaman ke huruf kecil dilakukan dengan metode lower(). Dampaknya paling terlihat pada jumlah jenis kata yang berbeda dalam korpus, yakni ukuran kosakata (vocabulary). Jalankan potongan berikut untuk membandingkan kosakata dengan kapital dan tanpa kapital pada korpus tiga kalimat.
import re
def token_dasar(teks: str) -> list[str]:
# pemecahan per spasi, lalu tanda baca di tepi kata dibuang
return [re.sub(r"^[^a-zA-Z]+|[^a-zA-Z]+$", "", t) for t in teks.split()]
korpus = [
"The seminar begins in March.",
"They march in March.",
"March days are longer than February days.",
]
semua_kata = []
for k in korpus:
semua_kata.extend(token_dasar(k))
print("dengan kapital :", sorted(set(semua_kata)))
print("semua huruf kecil :", sorted(set(k.lower() for k in semua_kata)))
print("jumlah jenis kata :", len(set(semua_kata)), "->", len(set(k.lower() for k in semua_kata)))dengan kapital : ['February', 'March', 'The', 'They', 'are', 'begins', 'days', 'in', 'longer', 'march', 'seminar', 'than']
semua huruf kecil : ['are', 'begins', 'days', 'february', 'in', 'longer', 'march', 'seminar', 'than', 'the', 'they']
jumlah jenis kata : 12 -> 11Jumlah jenis kata turun dari 12 menjadi 11 karena March dan march menyatu menjadi satu jenis, sedangkan The dan They tidak menemukan pasangannya pada korpus kecil ini. Pada korpus nyata, penurunannya jauh lebih besar karena nama, gelar, dan awalan kalimat menumpuk pada kata yang sama. Penurunan itu membantu model frekuensi, tetapi juga menghapus perbedaan yang dibawa huruf besar, misalnya nama diri pada dokumen yang diolah untuk pengenalan entitas.
Tanda baca dan angka#
Tanda baca sebaiknya diganti menjadi spasi, bukan sekadar dihapus, agar kata-kata yang bersambungan tidak menyatu. Kebijakan ini tetap menimbulkan efek samping yang perlu diantisipasi. Apostrof pada kepemilikan seperti Ada's menghasilkan potongan s yang tersisa setelah apostrof diganti spasi, dan titik pada 9.30 memisahkan angka menjadi dua potongan.
Perlakuan terhadap angka terbagi dua arah. Angka dibuang bila model hanya membutuhkan tema, misalnya klasifikasi topik, karena angka yang jarang muncul menambah kosakata tanpa menambah makna. Angka dipertahankan bila angkanya sendiri adalah isinya, misalnya nomor ruangan pada jadwal atau nilai pada catatan sensor. Tidak ada pilihan yang lebih benar secara umum, dan keputusannya bergantung pada informasi yang perlu dipertahankan.
Pipeline normalisasi kecil#
Tiga keputusan di atas, ditambah perapian spasi sebagai langkah penutup, dirangkai menjadi satu fungsi pada berkas berikut. Fungsi tersebut dijalankan terhadap dua kalimat yang berbeda karakternya, satu berisi waktu dan nomor ruangan, sedangkan satu lagi berisi singkatan gelar dan kepemilikan.
"""Pipeline normalisasi kecil: huruf kecil, tanda baca, dan angka."""
import re
def normalisasi(teks: str) -> str:
# langkah 1: seluruh huruf dijadikan huruf kecil
teks = teks.lower()
# langkah 2: karakter selain huruf, angka, dan spasi diganti spasi
teks = re.sub(r"[^a-z0-9\s]", " ", teks)
# langkah 3: deretan angka diganti spasi
teks = re.sub(r"\d+", " ", teks)
# langkah 4: spasi ganda dirapatkan menjadi satu
teks = re.sub(r"\s+", " ", teks).strip()
return teks
kalimat_1 = "The Seminar Room 4 opens at 9.30, and Room 12 at 10.00!"
kalimat_2 = "Dr. Ada's survey listed 3 findings; Budi's list had none."
for k in (kalimat_1, kalimat_2):
print("sebelum :", k)
print("sesudah :", normalisasi(k))
print()sebelum : The Seminar Room 4 opens at 9.30, and Room 12 at 10.00!
sesudah : the seminar room opens at and room at
sebelum : Dr. Ada's survey listed 3 findings; Budi's list had none.
sesudah : dr ada s survey listed findings budi s list had noneKeluaran pertama menunjukkan angka hilang bersama 9.30 dan 10.00, sehingga dua jadwal yang berbeda tidak lagi terbedakan oleh angkanya. Keluaran kedua menunjukkan potongan s yang tersisa dari kepemilikan Ada's dan Budi's, serta gelar Dr. yang kehilangan titiknya. Dua efek ini adalah harga yang dibayar demi kosakata yang rapi, dan keduanya perlu dicatat ketika model ternyata membutuhkan informasi tersebut.
Uji normalisasi di browser#
Demo interaktif berikut menerapkan tiga pilihan yang sama pada teks yang diketik langsung di halaman, yaitu huruf kecil, penggantian tanda baca dengan spasi, dan penghapusan angka, ditambah hasil rangkaiannya. Ubah teks pada kotak masukan dan amati bagaimana setiap pilihan mengubah teksnya secara berbeda.
Kode sumber demo
<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="utf-8">
<title>Demo normalisasi teks</title>
<style>
body { font-family: sans-serif; margin: 16px; color: #1f3a4d; }
textarea { width: 100%; box-sizing: border-box; height: 64px; font-size: 14px; padding: 8px; }
.label { margin-top: 12px; font-size: 13px; font-weight: bold; }
.keluaran { background: #eef3f8; border: 1px solid #c8d8e6; border-radius: 6px; padding: 8px;
font-family: monospace; font-size: 13px; min-height: 18px; white-space: pre-wrap; }
</style>
</head>
<body>
<textarea id="masukan">The Seminar Room 4 opens at 9.30, and Room 12 at 10.00!</textarea>
<div class="label">Huruf kecil</div>
<div class="keluaran" id="keluaran-kecil"></div>
<div class="label">Tanpa tanda baca</div>
<div class="keluaran" id="keluaran-baca"></div>
<div class="label">Tanpa angka</div>
<div class="keluaran" id="keluaran-angka"></div>
<div class="label">Rangkaian ketiganya</div>
<div class="keluaran" id="keluaran-lengkap"></div>
<script>
var masukan = document.getElementById('masukan');
function keHurufKecil(t) { return t.toLowerCase(); }
function tanpaTandaBaca(t) {
return t.replace(/[^a-z0-9\s]/gi, ' ').replace(/\s+/g, ' ').trim();
}
function tanpaAngka(t) { return t.replace(/\d+/g, ' ').replace(/\s+/g, ' ').trim(); }
function perbarui() {
var t = masukan.value;
document.getElementById('keluaran-kecil').textContent = keHurufKecil(t);
document.getElementById('keluaran-baca').textContent = tanpaTandaBaca(t);
document.getElementById('keluaran-angka').textContent = tanpaAngka(t);
document.getElementById('keluaran-lengkap').textContent = tanpaAngka(tanpaTandaBaca(keHurufKecil(t)));
}
masukan.addEventListener('input', perbarui);
perbarui();
</script>
</body>
</html>Dua hal perlu diamati dari demo tersebut. Tanda baca yang diganti spasi membuat potongan s muncul pada teks yang memuat kepemilikan, sama seperti keluaran pipeline di atas. Angka yang dihapus menyatukan Room 4 dan Room 12 menjadi room, dan efek inilah yang harus dipilih dengan sadar ketika angka dibuang.
Kesalahan umum#
- Menimpa teks asli dengan hasil normalisasi. Proses penyeragaman menghapus informasi dan tidak dapat dipulihkan. Simpan versi aslinya di kolom atau berkas terpisah agar normalisasi dapat diulang dengan kebijakan yang berbeda.
- Menghapus tanda baca tanpa menggantinya dengan spasi. Rangkaian seperti
will,domenyatu menjadiwilldodan mengubah kosakata. Ganti setiap karakter selain huruf dan angka dengan spasi sebelum merapikan spasi ganda. - Menerapkan satu kebijakan angka untuk semua kebutuhan. Pembuangan angka pada jadwal atau catatan pengukuran menghilangkan isinya. Tentukan perlakuan angka berdasarkan kebutuhan model, bukan kebiasaan.
Ringkasan#
- Normalisasi menyamakan bentuk token agar hitungan terkumpul, dengan harga berupa informasi yang hilang secara permanen.
- Huruf kecil menurunkan jumlah jenis token secara signifikan, tetapi juga menghapus petunjuk kapitalisasi yang dibutuhkan pengenalan entitas.
- Tanda baca sebaiknya diganti spasi alih-alih dihapus, agar potongan
spada kepemilikan tidak menyatu dengan kata di sekitarnya. - Angka dibuang untuk kebutuhan topik dan dipertahankan bila angkanya sendiri merupakan isi, misalnya nomor ruangan.
Referensi#
- Feature extraction dari teks — scikit-learn — Menjelaskan praproses teks dan konsekuensi pilihan normalisasi pada fitur.
- Natural Language Processing with Python — Bird, Klein & Loper, O’Reilly/NLTK — Bab 3 membahas normalisasi dan keputusan huruf besar-kecil pada teks.
- Speech and Language Processing, draf edisi ke-3 — Jurafsky & Martin, Stanford — Bab tentang tokenisasi menguraikan keputusan normalisasi beserta informasi yang hilang.