انتقل إلى المحتوى الرئيسي

الوحدة 1 — سلسلة معالجة النصّ: التنظيف والتطبيع

قبل أيّ تقطيع أو تضمين أو تصنيف، يجب أن يمرّ النصّ الخام بسلسلة من التحويلات الصغيرة تجعله قابلًا للمقارنة مع نظيره. هذه السلسلة تبدو تفصيلًا تقنيًّا، لكنّها تحسم جودة كلّ ما يأتي بعدها: نموذج يُدرَّب على نصّ مطبَّع تطبيعًا رديئًا يتعلّم غالبًا أنّ «الجيّد» و«جيد» و«الجيِّد» ثلاث كلمات مختلفة.

سنطبّق هذه السلسلة على الفكرة الناظمة للدورة: جسم من نحو 10 000 مراجعة عملاء بالعربية، موسومة بعدد النجوم من 1 إلى 5. لكلّ مراجعة نصّ من بضع جُمَل، ونيّة ظاهرة (رضًا أو تذمّر)، وأخطاء إملاء وتشكيل حرّ من الكاتب.

لماذا لا يكفي text.lower() في العربية

في الإنجليزية، تحويل الحالة إلى الأحرف الصغيرة يوحّد Product وproduct، ويكفي في أغلب الأحيان. أمّا في العربية فلا وجود لهذه الفكرة أصلًا: كلّ الحروف حالة واحدة. وفي المقابل هناك عائلة من مشكلات لا نظير لها في اللغات اللاتينية.

  • أشكال الهمزة: أ، إ، آ، ا. يكتبها كثير من المستخدمين بلا فرق، فيتقاطع أحمد واحمد في البيانات نفسها.
  • الياء والألف المقصورة: ي وى. في المصريّة الشائعة على الشبكة، تُختصر الياء طرفًا إلى ألف مقصورة.
  • التاء المربوطة والهاء: ة وه. الفرق حقيقي لكنّه يُهمَل غالبًا.
  • التشكيل: الفتحة والكسرة والضمّة والسكون والشدّة والتنوين. يظهر متقطّعًا، فيربك المطابقة الحرفية.
  • الكشيدة ـ: توسيع بصريّ لا معنى له، يضاف اعتباطيًّا في العناوين وأسماء التطبيقات.

نموذج يعتبر الْمَنْتَج والمنتج كلمتين مختلفتين يفتقد نصف السياق المفيد. ولذلك يبدأ كلّ خطّ إنتاج نصّي بترميز واحد، ثمّ تطبيع لهذه الظواهر بالتحديد.

تطبيع Unicode: NFC قبل كلّ شيء

نفس الحرف يمكن أن يُخزَّن بعدّة سلاسل بايتات. مثلًا، حرف الألف بهمزة تحتية إ يمكن أن يأتي بترميز مركَّب U+0625 وحده، أو بترميز مفكَّك مكوَّن من الألف U+0627 متبوعة بالهمزة أسفل U+0655. على الشاشة يبدوان متطابقين، لكنّ المقارنة النصّية تراهما مختلفَين، والنموذج يتعلّم مفردتَين حيث توجد كلمة واحدة.

الحلّ يقدّمه معيار Unicode بأربعة أشكال قياسية. الشكلان اللذان يهمّاننا هما NFC (شكل مركَّب موحَّد) وNFKC (شكل تلاؤمي). الأوّل يوحّد التمثيل مع الحفاظ على المعنى الرسومي، والثاني يذهب أبعد فيحوّل مثلًا الأرقام العربية الشرقية ٠١٢ إلى نظيرها الغربي 012. لجسم مراجعات، نبدأ دائمًا بـNFC. وقد نصعد إلى NFKC إذا كان الجسم يخلط بين ترميزَي الأرقام.

import unicodedata

def tab3_unicode(nass: str) -> str:
return unicodedata.normalize("NFC", nass)

# مثال: كلمتان بصريّتان متطابقتان لكنّهما مختلفتان قبل التطبيع.
brute = "\u0625" + "بداع" # همزة مركّبة
mfakkak = "\u0627\u0655" + "بداع" # ألف + همزة أسفل
print(brute == mfakkak) # False
print(tab3_unicode(brute) == tab3_unicode(mfakkak)) # True

هذه الخطوة تسبق كلّ ما تبقّى. تشغيلها بعد إزالة التشكيل مثلًا يعطي نتائج مضطربة، لأنّ رموز التشكيل نفسها تحتاج تطبيعًا.

إزالة التشكيل ومعالجة الحروف المتشابهة

على مراجعات مكتوبة بحرّية، التشكيل نادر ومتذبذب. نحذفه بالكامل. ثمّ نوحّد الأشكال الأربعة للهمزة، والياء بالمقصورة، ونحذف الكشيدة.

import re

TASHKEEL = re.compile(r"[\u064B-\u0652\u0670\u0640]") # حركات + خنجرية + كشيدة

def azal_tashkeel(nass: str) -> str:
return TASHKEEL.sub("", nass)

def wahhid_horouf(nass: str) -> str:
# نجعل كلّ أشكال الألف المهموزة ألفًا واحدة.
nass = re.sub(r"[إأآا]", "ا", nass)
# الألف المقصورة تصير ياء (اختيار شائع في التطبيع الاسترجاعي).
nass = nass.replace("ى", "ي")
# التاء المربوطة تصير هاء عند المطابقة اللغوية العامّة.
nass = nass.replace("ة", "ه")
return nass

def nazzif(nass: str) -> str:
nass = tab3_unicode(nass)
nass = azal_tashkeel(nass)
nass = wahhid_horouf(nass)
return nass.strip()

print(nazzif("المُنْتَجُ رَائِعٌ جِدًّا"))
# ينتج: "المنتج رائع جدا"

على مراجعاتنا، هذا وحده يخفّض حجم المفردات بنحو 15 بالمئة دون فقدان معلومة تصنيفية معتبَرة، ويرفع بضع نقاط من F1 في التصنيف المرجعي.

ما لا يجب حذفه في مسار المشاعر

الغريزة الأولى بعد التطبيع هي «تنظيف» النصّ بمزيد من الحذف: علامات الترقيم، الرموز التعبيرية، الأرقام، الروابط. هذا خطأ في مسار المشاعر بالذات.

  • علامات التعجّب والاستفهام: !!! و؟؟؟ علامات قويّة على الانفعال. تظهر مضاعَفة عند أعلى المراجعات وأدناها.
  • الرموز التعبيرية: 😍 و😡 مفردات كاملة، وربّما الأكثر دلالة على النجمات في المراجعات القصيرة.
  • التطويل بالحرف نفسه: رااااااائع يعبّر عن حماس. يمكن اختصاره إلى ثلاثة مكرّرات على الأكثر بدل الحذف الكامل.

في المقابل، مسار استرجاع المعلومات (البحث عن اسم منتج مثلًا) يقبل بحذف كلّ هذه العناصر لأنّه يقصّ الكلمة الجذر. القاعدة العملية: يُصمَّم التنظيف حسب المهمّة النهائية، لا حسب مبدأ عام.

الاحتفاظ بالنسخة الأصلية دائمًا

احفظ عمودَين في جدول البيانات: النصّ الأصلي والنصّ المطبَّع. عند تصحيح خطأ في التصنيف، ستحتاج إلى قراءة النصّ كما كتبه المستخدم، لا كما رآه النموذج. وحين تُبدّل قاعدة تطبيع، يمكنك إعادة توليد العمود المطبَّع في ثوانٍ بدل إعادة تحميل الجسم من المصدر.

الجذر والليم: خيار لا يُتَّخذ خفية

عائلة أدوات معالجة العربية تقدّم مقاربتين لتقليص المفردات: الليم (lemmatization) الذي يُرجع الكلمة إلى مدخل معجمي (يذهبونذهب)، والتجذير (stemming) الذي يقطع البادئات واللواحق دون فهم (المدرسوندرس).

الليم أدقّ لكنّه بطيء ويتطلّب مورد معجمي (مثل Farasa أو CAMeL Tools). التجذير سريع لكنّه يخلط بين كلمات جذرها واحد ومعناها متباعد (كتاب ومكتوب واكتتاب).

# مثال قصير باستخدام PyArabic لأداة تجذير خفيفة.
from pyarabic import araby, stack

def jazzir(kalimah: str) -> str:
return araby.strip_tashkeel(kalimah)

# مقاربة أدقّ ستحتاج camel_tools أو farasa.

متى تختار كلّ منهما؟ إن كنت تبني نموذجًا مرجعيًّا بـTF-IDF على مراجعات قصيرة، فالتجذير كافٍ ويرفع F1. أمّا إن كنت تُدخل النصّ إلى نموذج مدرَّب مسبقًا مثل AraBERT، فلا تُجذّر ولا تُلْيم: النموذج تعلّم على النصّ العربي المكتوب طبيعيًّا، وأيّ حذف يبعده عن توزيع تدريبه.

لا تُوحِّد الحروف المتشابهة قبل نموذج مدرَّب مسبقًا

النماذج المدرَّبة مسبقًا (AraBERT، AraELECTRA، mBERT) تدرَّبت على نصّ بالهمزات كما هي. تطبيقُ wahhid_horouf قبلها يُنتج جُذاذات مختلفة عمّا رأت أثناء التدريب، فيهبط الأداء بشكل صامت. احتفظ بالتنظيف الحدّ الأدنى (NFC وإزالة التشكيل) في مسار المحوّلات، ووسّعه فقط في مسار TF-IDF أو استرجاع المعلومات.

في الخلاصة

  • يبدأ كلّ مسار نصّي بتطبيع Unicode إلى NFC، قبل أيّ حذف أو توحيد آخر، وإلّا تعاملنا مع كائنات مختلفة بيولوجيًّا وإن بدت متطابقة على الشاشة.
  • العربية تطرح مشكلاتها الخاصّة: أشكال الهمزة والألف المقصورة والتاء المربوطة والتشكيل والكشيدة. توحيدها يقلّص المفردات بنحو 15 بالمئة على مراجعات حرّة.
  • التنظيف يُصمَّم للمهمّة، لا كمبدأ عام: علامات الترقيم والرموز التعبيرية تُحتفظ بها في مسار المشاعر، وتُحذَف في مسار الاسترجاع.
  • الليم والتجذير قرار متناقض مع النماذج المدرَّبة مسبقًا: نطبّقهما مع TF-IDF، ونتجنّبهما تمامًا قبل AraBERT وأمثاله.

الوحدة التالية: التقطيع، الخطوة التي تحوّل السلسلة النصّية إلى قائمة جُذاذات، بأربع خوارزميات مختلفة ذات كلفة مختلفة على العربية.