علم البيانات ·10 دقائق قراءة

تحليل النصوص العربية ببايثون: من التطبيع إلى الموضوعات وتحليل المشاعر

دليل عملي لتحليل النصوص العربية ببايثون: التطبيع وإزالة التشكيل والتطويل، والتقطيع وكلمات التوقف، وTF-IDF، والنمذجة الموضوعية، وتحليل المشاعر بالمعاجم ونماذج BERT، وتقييم النتائج.

في هذه المقالة
  1. لماذا تحتاج العربية معالجة خاصة؟
  2. التطبيع: توحيد أشكال الكتابة
  3. التقطيع وكلمات التوقف
  4. تمثيل النصوص رقميًا باستخدام TF-IDF
  5. النمذجة الموضوعية: NMF وLDA
  6. تحليل المشاعر: المعجم أم النموذج المدرب؟
  7. طريقة المعجم
  8. النماذج اللغوية المدربة مسبقًا
  9. تقييم النتائج
  10. أخطاء شائعة
  11. أسئلة شائعة
  12. هل أزيل التشكيل دائمًا؟
  13. كيف أتعامل مع اللهجات في البيانات؟
  14. هل R مناسبة لتحليل النصوص العربية؟
  15. هل تغني النمذجة الموضوعية عن الترميز اليدوي؟

تجمع مؤسسة آلاف الإجابات المفتوحة في استبيان رضا، أو آلاف الشكاوى عبر بوابتها الإلكترونية، أو تعليقات المستخدمين عن خدمة جديدة، ثم تكتشف أن قراءتها يدويًا لا تنتهي، وأن الدروس الجاهزة على الإنترنت مكتوبة للإنجليزية وتتعثر أمام العربية: الكلمة نفسها تكتب بعدة أشكال، وحروف العطف والجر والضمائر تلتصق بها، واللهجات تختلط بالفصحى. تحليل النصوص العربية ببايثون ممكن ومفيد، لكنه يعتمد على قرارات معالجة صغيرة تغير النتائج أكثر مما يتوقع كثيرون. يعرض هذا المقال سلسلة العمل خطوة خطوة بكود قابل للتشغيل: التطبيع، والتقطيع، وكلمات التوقف، وتمثيل TF-IDF، والنمذجة الموضوعية، وتحليل المشاعر بالمعاجم وبنماذج BERT العربية، ثم تقييم النتائج.

لماذا تحتاج العربية معالجة خاصة؟

ثلاث خصائص تجعل الطرق المصممة للإنجليزية قاصرة حين تطبق على العربية كما هي:

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

كل خطوة في هذا المقال تتعامل مع واحدة من هذه الخصائص. والأمثلة تستخدم تعليقات قصيرة اصطناعية عن خدمات عامة، كتبت لغرض التوضيح فقط.

التطبيع: توحيد أشكال الكتابة

التطبيع (Normalization) يحول الأشكال المتعددة للكلمة إلى شكل واحد قبل العد والتحليل. الدالة التالية تزيل علامات التشكيل والتطويل، وتوحد أشكال الألف، وتحول الألف المقصورة إلى ياء، والتاء المربوطة إلى هاء اختياريًا، وتحذف الترقيم والأرقام:

import re

DIACRITICS = re.compile(r"[u0617-u061Au064B-u0652u0670]")
TATWEEL = "u0640"

def normalize_arabic(text, unify_ta_marbuta=True):
    text = DIACRITICS.sub("", text)            # remove tashkeel marks
    text = text.replace(TATWEEL, "")           # remove tatweel (kashida)
    text = re.sub("[إأآ]", "ا", text)           # unify alef with hamza/madda
    text = text.replace("ى", "ي")              # alef maqsura -> ya
    if unify_ta_marbuta:
        text = text.replace("ة", "ه")          # ta marbuta -> ha
    text = re.sub(r"[^ws]", " ", text)       # drop punctuation, incl. Arabic marks
    text = re.sub(r"[d_]", " ", text)         # drop digits and underscores
    return re.sub(r"s+", " ", text).strip()

# Tatweel and a diacritic are built from escapes so the source stays plain
sample = "إدارة المدرسة" + TATWEEL * 3 + " على" + "u064E" + " الطريق الصحيح؟"
print(normalize_arabic(sample))

النطاق من U+064B إلى U+0652 يشمل التنوين بأنواعه والفتحة والضمة والكسرة والشدة والسكون، وU+0670 هو الألف الخنجرية. وتعطي الدالة للمثال: «اداره المدرسه علي الطريق الصحيح». لاحظ أن كل خطوة قرار له ثمن:

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

لهذا جعلنا تحويل التاء المربوطة خيارًا يمكن إيقافه. والقاعدة العملية: اختر خطوات التطبيع حسب الهدف، ووثقها، وطبقها بالطريقة نفسها على كل النصوص وعلى قوائم الكلمات التي تستخدمها لاحقًا. وإذا كنت ستستخدم نموذجًا لغويًا مدربًا مسبقًا، فخفف التطبيع واتبع ما توصي به بطاقة النموذج، لأن مقطعه الداخلي (tokenizer) تدرب على نص بشكل معين.

التقطيع وكلمات التوقف

التقطيع (Tokenization) بالمسافات يكفي لتجربة أولى، لكنه يترك اللواصق ملتصقة بالكلمات. لمعالجة أعمق توجد أدوات متخصصة للعربية، منها CAMeL Tools التي تقدم تحليلًا صرفيًا وتقطيعًا للواصق، وFarasa للتقطيع الصرفي، والمجذع ISRI في مكتبة NLTK الذي يقطع السوابق واللواحق دون معجم. والفرق بين الطريقين مهم: التجذيع سريع لكنه قد يدمج كلمات متباعدة المعنى، والتحليل الصرفي الذي يعيد الكلمة إلى أصلها المعجمي أدق لكنه أبطأ ويحتاج موارد أكثر.

أما كلمات التوقف (Stop Words)، وهي الكلمات الكثيرة التكرار القليلة الدلالة مثل «في» و«من» و«عن»، فلا توجد لها قائمة عربية واحدة صالحة لكل غرض. ابدأ بقائمة عامة ثم عدلها حسب مجالك، وتذكر أمرين: أن تطبع القائمة نفسها بدالة التطبيع، وإلا بقيت «على» في القائمة بينما صارت «علي» في النص؛ وأن تحتفظ بأدوات النفي مثل «لا» و«لم» و«غير» إذا كان هدفك تحليل المشاعر، لأن حذفها يقلب المعنى.

تمثيل النصوص رقميًا باستخدام TF-IDF

يحول TF-IDF كل نص إلى متجه يعطي وزنًا أعلى للكلمات المتكررة في النص والنادرة في بقية النصوص. ونمرر دالة التطبيع إلى TfidfVectorizer مباشرةً حتى تطبق على كل نص بالطريقة نفسها:

from sklearn.feature_extraction.text import TfidfVectorizer

docs = [  # short synthetic comments about public services
    "تأخر إصدار الرخصة أكثر من شهر والموظفون لا يردون على الهاتف",
    "الموظفة كانت متعاونة جدا وأنهت المعاملة بسرعة",
    "الموقع الإلكتروني يتوقف عند رفع المستندات",
    "انتظرت ساعات طويلة في الطابور دون أي تنظيم",
    "شكرا لفريق خدمة العملاء على المتابعة والرد السريع",
    "التطبيق لا يقبل الدفع الإلكتروني ويظهر خطأ متكرر",
    "المعاملة تأخرت كثيرا ولم يصلني أي إشعار",
    "تعامل راق من الموظفين واستقبال ممتاز",
    "صفحة التسجيل في الموقع بطيئة وتطلب كلمة المرور كل مرة",
    "مدة الانتظار طويلة والمكتب مزدحم",
    "الخدمة ممتازة والموظف شرح لي الخطوات بوضوح",
    "رابط التطبيق لا يعمل والدعم الفني لا يرد",
]
raw_stops = ["في", "من", "على", "إلى", "عن", "أو", "ثم", "هذا", "هذه", "التي",
             "الذي", "كان", "كانت", "لا", "لم", "أن", "مع", "كل", "أي", "دون",
             "لي", "جدا", "عند", "أكثر", "كثيرا"]
stops = sorted({normalize_arabic(w) for w in raw_stops})  # normalize the list too

vec = TfidfVectorizer(preprocessor=normalize_arabic, stop_words=stops,
                      ngram_range=(1, 2), sublinear_tf=True)
X = vec.fit_transform(docs)
terms = vec.get_feature_names_out()
print(X.shape)

الإعداد ngram_range=(1, 2) يضيف الثنائيات إلى الكلمات المفردة، فيلتقط عبارات مثل «الانتظار طويله» التي تحمل معنى لا تحمله كل كلمة وحدها. وفي البيانات الحقيقية ارفع min_df لاستبعاد الكلمات التي تظهر في نص أو نصين فقط. وحذفنا أدوات النفي هنا لأن الهدف التالي استكشاف الموضوعات لا المشاعر.

النمذجة الموضوعية: NMF وLDA

النمذجة الموضوعية (Topic Modeling) تبحث عن مجموعات من الكلمات تتكرر معًا، وتعرض كل نص مزيجًا من هذه الموضوعات. نستخدم هنا تحليل المصفوفات غير السالبة (NMF) فوق مصفوفة TF-IDF:

from sklearn.decomposition import NMF

nmf = NMF(n_components=3, init="nndsvda", random_state=42, max_iter=1000)
doc_topics = nmf.fit_transform(X)

# Top terms per topic, then the dominant topic for each comment
for k, weights in enumerate(nmf.components_):
    top = weights.argsort()[::-1][:6]
    print(f"topic {k}: " + " | ".join(terms[top]))
print(doc_topics.argmax(axis=1))

في هذا المثال الصغير ظهر موضوع للمشكلات التقنية في الموقع والتطبيق، وآخر للانتظار والازدحام، وثالث يخلط بين تأخر المعاملات والثناء على الموظفين. النتائج توضيحية وتختلف حسب البيانات، واثنا عشر تعليقًا أقل بكثير مما تحتاجه نمذجة موضوعية حقيقية. أما LDA فنموذج احتمالي يعمل على عدد مرات التكرار الخام، فاستخدم معه CountVectorizer بدل TF-IDF، وهو متاح في scikit-learn باسم LatentDirichletAllocation.

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

تحليل المشاعر: المعجم أم النموذج المدرب؟

طريقة المعجم

أبسط طريقة أن تعد الكلمات الإيجابية والسلبية من معجم، مع قلب القطبية إذا سبقت الكلمة أداة نفي:

POSITIVE = {"ممتاز", "ممتازه", "متعاونه", "سريع", "شكرا", "راق", "بوضوح"}
NEGATIVE = {"تاخر", "تاخرت", "بطيئه", "خطا", "مزدحم", "طويله", "يتوقف"}
NEGATORS = {"لا", "لم", "ليس", "غير", "دون"}

def lexicon_score(text):
    tokens = normalize_arabic(text).split()
    score = 0
    for i, tok in enumerate(tokens):
        polarity = (tok in POSITIVE) - (tok in NEGATIVE)
        if polarity and i > 0 and tokens[i - 1] in NEGATORS:
            polarity = -polarity        # a negator flips the sign
        score += polarity
    return score

for d in docs[:4]:
    print(lexicon_score(d), d)

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

النماذج اللغوية المدربة مسبقًا

النماذج المبنية على BERT تقرأ الكلمة في سياقها. ومن النماذج العربية المعروفة CAMeLBERT، الذي نشر بنسخ دربت على الفصحى الحديثة واللهجات والعربية الكلاسيكية ونسخة تمزج بينها، وAraBERT. النموذج الأساسي من أي منهما يحتاج ضبطًا دقيقًا (fine-tuning) على بيانات معلمة قبل استخدامه في التصنيف، لكن توجد نسخ منشورة مضبوطة لتحليل المشاعر، مثل النموذج التالي من CAMeLBERT:

from transformers import pipeline

# Public CAMeLBERT model fine-tuned for sentiment (downloads weights on first run)
sentiment = pipeline("text-classification",
                     model="CAMeL-Lab/bert-base-arabic-camelbert-da-sentiment")

# Feed near-raw text: the model has its own tokenizer
for doc, out in zip(docs[:4], sentiment(docs[:4])):
    print(out["label"], round(out["score"], 2), doc)

يعيد النموذج إحدى ثلاث تسميات: positive أو negative أو neutral. وتذكر بطاقة النموذج أنه ضبط على مجموعات بيانات عامة مأخوذة من منصات التواصل، فلا تفترض أنه سيعمل بالجودة نفسها على شكاوى رسمية أو نصوص قانونية. اختبره على عينة من بياناتك قبل الاعتماد عليه.

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

الطريقة الثانية في الجدول هي نموذج تصنيف عادي، تنطبق عليه قواعد التقسيم والتحقق المتقاطع وتجنب التسرب المشروحة في مقال بناء نموذج تنبؤي وتقييمه بلغة بايثون.

تقييم النتائج

لا تقبل نتيجة تحليل نصي دون مقارنتها بحكم بشري. الخطوات الأساسية: اسحب عينة عشوائية من النصوص، واجعل مرمزين اثنين يصنفانها باستقلال وفق دليل ترميز مكتوب، واحسب الاتفاق بينهما، ثم احسم الخلافات وقارن تنبؤات النموذج بالتسميات النهائية:

from sklearn.metrics import classification_report, cohen_kappa_score

# Two human annotators label the same sample independently
annotator_a = ["neg", "pos", "neg", "neg", "pos", "neg", "neg", "pos", "neg", "neg", "pos", "neg"]
annotator_b = ["neg", "pos", "neg", "neg", "pos", "neg", "neg", "pos", "neu", "neg", "pos", "neg"]
print("kappa:", round(cohen_kappa_score(annotator_a, annotator_b), 2))

gold = annotator_a  # in practice: the adjudicated labels
pred = ["pos" if s > 0 else "neg" if s < 0 else "neu" for s in map(lexicon_score, docs)]
print(classification_report(gold, pred, zero_division=0))

معامل كوهين كابا يقيس الاتفاق بعد استبعاد ما يتوقع بالصدفة، وانخفاضه يعني أن الفئات نفسها غير واضحة، فلا معنى لمطالبة النموذج بما لم يتفق عليه البشر. وفي تقرير التصنيف انظر إلى كل فئة على حدة وإلى متوسط F1 غير الموزون (macro)، لا إلى الدقة الكلية وحدها. ثم حلل الأخطاء: هل تتركز في لهجة معينة، أو قناة معينة، أو نصوص قصيرة جدًا؟ هذا التحليل يخبرك أين تحسن السلسلة.

أخطاء شائعة

  • تطبيق قائمة كلمات توقف إنجليزية الطابع أو غير مطبعة على نص عربي مطبع.
  • حذف أدوات النفي قبل تحليل المشاعر.
  • تطبيع ثقيل وحذف كلمات التوقف قبل إدخال النص إلى نموذج BERT.
  • تقييم المعجم أو النموذج على النصوص نفسها التي بني منها.
  • تفسير موضوعات LDA أو NMF على أنها حقائق لا مخرجات استكشافية تحتاج قراءة.
  • تجاهل اللهجات والنصوص المكتوبة بالحروف اللاتينية، ثم تعميم النتائج على الجميع.
  • الترجمة الآلية إلى الإنجليزية ثم استخدام أدوات إنجليزية دون قياس الخطأ الذي تضيفه الترجمة.

أسئلة شائعة

هل أزيل التشكيل دائمًا؟

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

كيف أتعامل مع اللهجات في البيانات؟

ابدأ بمعرفة نسبة كل لهجة في عينة مقروءة. إذا كانت اللهجة غالبة فاختر نموذجًا تدرب على نصوص لهجية، مثل نسخة اللهجات من CAMeLBERT، ووسع معاجمك بمفرداتها، واعرض أداء النموذج لكل لهجة على حدة.

هل R مناسبة لتحليل النصوص العربية؟

حزم مثل tidytext وquanteda في R تعمل مع النص العربي في العد وTF-IDF والنمذجة الموضوعية. لكن أغلب أدوات المعالجة الصرفية العربية والنماذج اللغوية الحديثة متاحة في بايثون أولًا، والمقارنة الأوسع بين اللغتين في مقال بايثون أم R لتحليل البيانات.

هل تغني النمذجة الموضوعية عن الترميز اليدوي؟

لا. هي تختصر القراءة الأولى وتكشف أنماطًا في آلاف النصوص، لكن تسمية الموضوعات وتفسيرها والتحقق منها عمل بشري. وفي البحث الأكاديمي يجمع كثيرون بين الطريقين: النمذجة للاستكشاف، والترميز اليدوي لعينة للتحقق والتعميق.

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

آخر تحديث:
ESC
اكتب كلمة مفتاحية ثم اضغط Enter — مثل: «منهجية»، «إحصاء»، «اقتباس»، «نشر».