Skip to main content
يصنّف القاموس naive_bayes (NAIVE_BAYES) النصوص باستخدام نموذج Naive Bayes متعدد الحدود، وهو نموذج الأحداث القياسي للنصوص: إذ يقيّم كل فئة بناءً على مدى تكرار ظهور n-gram counts الخاصة بالمدخل فيها. وتزوّده بجدول يحتوي على n-gram counts لكل فئة، فيُجمِّعها في نموذج مرة واحدة عند وقت التحميل، ثم يستخدمه لتصنيف أي نص تمرّره إليه. وهو مناسب لتصنيف النصوص بسرعة وبأسلوب خفيف، مثل تحليل المشاعر، ووضع تسميات للموضوعات أو الرسائل غير المرغوب فيها، واكتشاف اللغة أو برنامج نصي. يمكنك query القاموس باستخدام إحدى الدوال الثلاث التالية: يمكن أيضًا لـ dictGet العادية إجراء التصنيف (راجع الملاحظات). وهناك دالة أخرى، هي naiveBayesNgrams، لا تُجري التصنيف، بل تقسّم النص إلى n-grams بالطريقة نفسها التي يستخدمها القاموس، بحيث يمكنك بناء بيانات التدريب من raw text (راجع بناء بيانات التدريب من raw text).

البدء السريع

نبني هنا نموذج unigram (n = 1) بوضع token لتحليل المشاعر. 1. أنشئ جدول مصدر لإحصاءات تكرار n-gram لكل فئة:
2. أدخِل بيانات التدريب — الكلمات المفردة (unigrams) وعدد مرات ظهور كل كلمة منها في الفئة الإيجابية (1) والفئة السلبية (0):
3. أنشئ القاموس باستخدام تخطيط NAIVE_BAYES:
يجعل PRIMARY KEY ngram العمود ngram هو المفتاح — ولكن في قاموس NAIVE_BAYES يكون هذا “المفتاح” هو النص الذي تمرّره للتصنيف، لا قيمةً مخزّنة تبحث عنها (راجع بنية القاموس). ويُهيّئ LAYOUT النموذج: إذ تحدد class_attribute 'class_id' أن class_id هو تسمية الفئة (لذا تكون السمة الأخرى، count، هي عدد مرات الظهور لكل فئة)، ويستخدم n 1 أحاديات، بينما يقسم mode 'token' النص إلى كلمات تفصل بينها مسافات بيضاء (راجع معلمات التخطيط). 4. صنِّف — تُرجع naiveBayesClassifier معرّف الفئة:
1 يقابل الفئة الإيجابية، استنادًا إلى بيانات التدريب التي أدرجناها في الخطوة 2.
وبالمثل، يشير 0 إلى الفئة السلبية. النتيجة نفسها باستخدام dictGet:
احصل على احتمال التنبؤ، أو احتمال كل فئة:
الفئة المتوقعة هي 0 (سلبية) باحتمال 0.64.
تعيد naiveBayesClassifierWithAllProbs جميع الفئات مرتبة من الأعلى إلى الأدنى احتمالًا، مع احتمالات مجموعها 1.0 — وهنا 0.64 للفئة السلبية و0.36 للفئة الإيجابية.

كيف يعمل

التدريب (وقت التحميل). يمثّل كل صف في المصدر ملاحظة بالشكل (n-gram, class, count). وعند تحميل القاموس، تُصرَّف الصفوف مرةً واحدة إلى النموذج. وتُجمع الصفوف المكررة من الشكل (n-gram, class)، بينما تُتجاهل الصفوف التي فيها count = 0. التصنيف (وقت الاستعلام). لتصنيف سلسلة نصية، يقوم النموذج بما يلي:
  1. يقسّمها إلى n-grams وفقًا لـ mode وn (راجع أوضاع التقسيم إلى رموز).
  2. يحسب درجة لكل فئة من خلال الجمع بين الاحتمال القبلي للفئة ومدى تكرار ظهور n-grams الخاصة بالإدخال ضمن تلك الفئة.
  3. يرتّب الفئات حسب الدرجة. وتكون الفئة ذات أعلى درجة هي التنبؤ الذي تعيده naiveBayesClassifier؛ كما تعيد naiveBayesClassifierWithProb وnaiveBayesClassifierWithAllProbs أيضًا احتمالات — لتلك الفئة أو لجميع الفئات.
هناك عاملان يؤثران في درجة كل فئة. الأول هو alpha، ويُستخدم للتنعيم. ويمنع التنعيم النموذج من إعطاء فئة درجة صفر لمجرد أن n-gram واحدة لم تظهر في تلك الفئة أثناء التدريب. تجعل قيمة alpha الأصغر النموذج يعتمد أكثر على بيانات التدريب، لذلك قد تحصل إحدى الفئات على درجة أعلى بكثير من غيرها، لكنها قد تجعل النموذج أيضًا مفرط الحساسية عندما تكون بيانات التدريب قليلة أو غير متوازنة. أما قيمة alpha الأكبر فتجعل أعداد n-grams أقل تأثيرًا، فتغدو درجات الفئات المختلفة أكثر تقاربًا. وإذا كانت alpha كبيرة جدًا، تكاد معلومات n-gram ألا تؤثر، وتصبح الدرجة معتمدةً في الغالب على الاحتمال القبلي للفئة (الموصوف لاحقًا). أما العامل الثاني فهو الاحتمال القبلي للفئة — أي ما يفترضه النموذج بشأن مدى احتمال كل فئة قبل النظر إلى النص. ويعمل هذا كدرجة ابتدائية تحصل عليها كل فئة قبل أخذ أي n-grams في الحسبان، لذا فإن الاحتمال القبلي الأعلى يجعل التنبؤ بتلك الفئة أكثر ترجيحًا. وتعتمد طريقة ضبطه على priors_mode. افتراضيًا (proportional)، تبدأ الفئة التي لها إجمالي أكبر من عدد n-grams في بيانات التدريب بدرجة أعلى. ومع uniform، تبدأ جميع الفئات على قدم المساواة، بحيث تكون n-grams وحدها هي التي تحسم. ومع explicit، يمكنك تحديد نقطة البداية لكل فئة بنفسك. راجع أوضاع الاحتمال القبلي. وأي n-gram لم تظهر مطلقًا في أي موضع ضمن بيانات التدريب تُتجاهل: فهي ليست جزءًا من مفردات النموذج، لذلك لا تفيد أي فئة ولا تضرها. تتبع الخوارزمية نموذج Naive Bayes متعدد الحدود لتصنيف النصوص؛ راجع Manning, Raghavan & Schütze, Introduction to Information Retrieval, ch. 13 (Text Classification and Naive Bayes).

بنية القاموس

لقاموس NAIVE_BAYES بنية ثابتة:
  • يتكوّن PRIMARY KEY من عمود واحد من النوع String — وهو n-gram. في وقت تنفيذ الاستعلام، يكون هذا “المفتاح” هو النص الذي تمرّره للتصنيف، وليس مفتاح بحث مخزّنًا.
  • إلى جانبه، عرّف سِمتين فقط من نوع عدد صحيح غير موقّع: وسم الفئة وعدد مرات الظهور. تستخدم معرّفات الفئات دائمًا UInt32 داخليًا، لذلك يجب أن تتسع قيمة وسم الفئة ضمن UInt32 (بحد أقصى 4294967295) حتى إذا أعلنت سِمته على أنها UInt64. وتُرفض أي قيمة أكبر عند تحميل القاموس، لا عند إنشائه. وينطبق الأمر نفسه على الأنواع المعلنة: فإذا كان معرّف فئة المصدر أو العدد لا يتّسع لنوع السمة المعلن، يفشل التحميل بدلًا من اقتطاعه بصمت.
  • تحدد مَعلمة التخطيط class_attribute أي سمة تمثل وسم الفئة، وتُعدّ السمة الأخرى تلقائيًا العدد. ويمكن تعريف السمتين بأي ترتيب.
يحتوي الجدول المصدر على counts مجمّعة مسبقًا: صف واحد لكل (n-gram, class) مع عدد مرات ظهور ذلك الـ n-gram في تلك الفئة. وتُنتج هذه counts عبر تقسيم corpus إلى tokens وتجميع النتيجة، إمّا ضمن pipeline التدريب الخاصة بك أو في ClickHouse انطلاقًا من raw text موسوم (راجع Build training data from raw text). ولا يستهلك القاموس سوى هذه counts. تحديث النموذج. لأن النموذج عبارة عن قاموس يستند إلى table، فأعِد تدريبه بتحديث table ثم إعادة تحميله:

معلمات البنية

يمكنك تعريف القاموس باستخدام DDL ‏CREATE DICTIONARY (كما في الدليل التمهيدي أعلاه) أو في ملف تكوين XML؛ راجع بُنى القواميس لمعرفة مكان هذا الملف. يضبط المثال أدناه كل خيارات البنية حتى تتمكن من رؤيتها جميعًا — ولا يُطلب سوى class_attribute و n و mode، بينما يوضح الجدول أعلاه القيم الافتراضية للباقي. في ملف التكوين، تُكتب الاحتمالات القبلية كعناصر prior متكررة (عنصر واحد لكل فئة، كما هو موضح أدناه)، وتكون رموز الحشو لـ byte و codepoint أرقامًا (لأن ملف التكوين لا يمكنه حمل بايتات خام)، وتكون القيمة الحرفية token مُفلَتة في XML عند الحاجة، لذا تتحول <s> إلى &lt;s&gt;.

أوضاع التقسيم إلى رموز

يحدِّد mode ما يُعدّ “رمزًا”، وبالتالي شكل سلاسل n-grams. ويجب أن تكون سلاسل n-grams المصدر قد أُنتجت باستخدام mode وn نفسهما.
  • byte — كل رمز عبارة عن بايت واحد؛ ولا يُفترض استخدام UTF-8. عند n = 2، تنتج 'abc' البيغرامات البايتية 'ab' و'bc'. مناسب لـ اكتشاف اللغة أو الترميز في تسلسلات بايتية عشوائية، وأي بيانات تكون فيها الإشارات دون مستوى المحرف مهمة. وعادةً ما يُستخدم مع n >= 2.
  • codepoint — كل رمز هو نقطة ترميز Unicode واحدة؛ ويُفسَّر الإدخال على أنه UTF-8. عند n = 1، تنتج 'café' نقاط الترميز 'c' و'a' و'f' و'é'. مناسب لـ اكتشاف نظام الكتابة واللغة، وللنصوص القصيرة أو نصوص CJK حيث لا يمكن الاعتماد على حدود الكلمات القائمة على المسافات. (يجب أن تكون سلاسل n-grams المصدر بترميز UTF-8 صالح؛ وتُفك شيفرة مدخلات الاستعلام بتسامح — راجع الملاحظات.)
  • token — كل رمز هو كلمة تفصل بينها محارف ASCII البيضاء (المسافة، وعلامة الجدولة، والسطر الجديد، وعودة العربة، وتغذية النموذج، وعلامة الجدولة العمودية؛ وتُختزل التتابعات إلى فاصل واحد). أما محارف Unicode البيضاء غير التابعة لـ ASCII مثل U+00A0 (مسافة غير قابلة للفصل) أو U+2003 (مسافة em) فهي ليست فاصلًا وتبقى داخل الرمز. والمحارف البيضاء هي الشيء الوحيد الذي يسبّب التقسيم — فلا يُحوَّل أي شيء إلى أحرف صغيرة ولا يُزال أي شيء — لذا تصبح 'Hello, World!' الرمزين 'Hello,' و'World!' (وتُحفَظ الفاصلة و! والأحرف الكبيرة جميعًا)، ومع n = 2 تُشكّل البيغرام الوحيد 'Hello, World!'. مناسب لـ التصنيف على مستوى الكلمات في اللغات التي تفصل كلماتها بمسافات — مثل تحليل المشاعر، والموضوع، والبريد المزعج، ولغة الجملة.

أوضاع prior

يمثل prior اعتقاد النموذج بشأن كل صنف قبل أن ينظر إلى النص. ويحدد priors_mode كيفية تعيينه.
  • proportional (الافتراضي) — يكون prior لكل صنف متناسبًا مع إجمالي عدد n-gram الخاصة به في بيانات التدريب — أي مجموع عمود count لذلك الصنف، وليس عدد الصفوف أو مستندات التدريب — لذا تبدأ الأصناف الأكثر ظهورًا باحتمال أعلى. اختره عندما تتوافق نسب الأصناف في التدريب (بحسب إجمالي عدد n-gram) مع التكرارات التي تتوقعها وقت الاستعلام. لا حاجة إلى تمرير أي شيء — إذ يُستمد من الأعداد في المصدر.
  • uniform — تكون جميع الأصناف متساوية الاحتمال في البداية، لذلك لا يحصل أي صنف على أفضلية أولية، ويعتمد التنبؤ بالكامل على n-grams الموجودة في المُدخل. اختره عندما تكون الأصناف متوازنة، أو عندما لا تعكس تكرارات التدريب مدى ظهور كل صنف وقت الاستعلام. لا حاجة إلى تمرير أي شيء.
  • explicit — توفّر أنت قيم prior باستخدام priors [(0, 0.6), (1, 0.4)]: زوج واحد من (class, probability) لكل صنف، بحيث تكون كل قيمة احتمال أكبر من 0 وبحد أقصى 1، ويكون مجموعها معًا 1.0. اختره عندما تعرف المعدلات الأساسية الحقيقية وتختلف عن التدريب — مثلًا، قد لا تتجاوز الرسائل المزعجة 1% من حركة المرور في بيئة الإنتاج رغم أن مجموعة التدريب كانت متوازنة. احسبها من الحصة الفعلية المتوقعة لكل صنف.

الرموز الحدّية (الحشو)

يكون الحشو معطّلًا افتراضيًا، ولا يكون مهمًا إلا عندما تكون n > 1، إذ يمكنه تحسين الدقة عبر تمكين النموذج من استخدام إشارات عند بداية النص ونهايته. لماذا يساعد ذلك؟ عندما تكون n > 1، تحصل n-grams في وسط النص على سياق كامل من اليسار واليمين، لكن أول token وآخره لا يحظيان بذلك. تؤدي إضافة الرموز الحدّية إلى إنشاء n-grams تشير إلى “بداية النص” و”نهاية النص”، بحيث يتمكن النموذج من تعلّم الأنماط المرتبطة بالموضع — مثل كلمة تكون مميّزة عندما تبدأ رسالة، أو حرف يكون شائعًا في نهاية كلمة. ما الذي يجب عليك فعله:
  1. حدّد كل جانب على حدة. إن start_token وend_token مستقلان — اضبط أحدهما أو كليهما أو اتركهما معًا دون ضبط. وتعني القيمة الفارغة أن هذا الجانب لا يُحشّى.
  2. اختر قيمًا نادرة لا تتصادم مع البيانات الفعلية، مثل 0x01 / 0xFF لـ byte، وU+10FFFE / U+10FFFF لـ codepoint، أو <s> / </s> لـ token.
  3. أنشئ n-grams الخاصة بالتدريب باستخدام الحشو نفسه. يقوم القاموس بحشو مدخل query فقط، ولا يحشو المصدر مطلقًا، لذا يجب أن تكون الرموز الحدّية مضمنة مسبقًا في n-grams التي تحمّلها. وأسهل طريقة لضمان التطابق هي إنشاء المصدر باستخدام naiveBayesNgrams، مع تمرير start_token وend_token نفسيهما (إلى جانب n وmode) اللذين تمرّرهما إلى layout — إذ يُنتج بالضبط n-grams المحشّاة التي ينشئها القاموس في query time.
يعتمد تنسيق رمز الحشو على الوضع:
  • byte — رقم لقيمة البايت، بالنظام العشري أو الست عشري 0x (لذا فإن '1' و'0x01' متماثلان):
  • codepoint — رقم لنقطة ترميز UTF-8، بالنظام العشري أو الست عشري 0x (لذا فإن '1114110' و'0x10FFFE' متماثلان):
  • token — سلسلة الـ token الحرفية:

أنشئ بيانات التدريب من النص الخام

إذا كنت تبدأ من نص خام موسوم بدلًا من تكرارات مجمّعة مسبقًا، فاستخدم الدالة naiveBayesNgrams لتقسيمه إلى n-grams. أعطِها القيم نفسها لـ n وmode وstart_token وend_token كما في البنية التي تستخدمها، وستنتج n-grams نفسها تمامًا التي يتوقعها القاموس، بحيث تتطابق بيانات التدريب مع ما يراه النموذج عند تنفيذ الاستعلام. إذا كان لديك جدول من الصفوف بالشكل (class_id, text)، فأنشئ المصدر بالشكل (ngram, class_id, count) باستخدام GROUP BY واحد:
يُعدّ training_data الآن مصدرًا صالحًا لقاموس NAIVE_BAYES (هنا أُحاديات token؛ غيّر وسيطَي n وmode ليتوافقا مع layout لديك). يُجزّئ القاموس مُدخلات الاستعلام إلى token تمامًا كما تَرِد، لذا إذا كان نص التدريب مكتوبًا بأحرف صغيرة بينما نص الاستعلام ليس كذلك، فلن تتطابق n-grams بينهما وستتراجع دقة النموذج.
الأوليات وعدد المستنداتتُوزن الأولية proportional (الافتراضية) بحسب إجمالي عدد n-grams لكل فئة، لا بحسب عدد مستنداتها. إذا كنت تريد الأولية الكلاسيكية المعتمدة على تكرار المستندات (documents_in_class / total_documents)، فاحسبها من جدول docs الخام ومرّرها مع priors_mode 'explicit':
بعد ذلك، أنشئ القاموس من training_data مع تمرير الأولية الصريحة المحسوبة أعلاه، ثم صنّف المراجعات الجديدة:
الفئة 1 إيجابية و0 سلبية، لذا صُنِّفت كلتا المراجعتين بشكل صحيح.

أمثلة إضافية

وضع البايت — ثنائيات البايت (n = 2, mode 'byte'; الفئة 0 = سلاسل من الأحرف ad، والفئة 1 = الأحرف xz):
وضع نقطة الترميز — اكتشاف نظام الكتابة على مستوى كل محرف (n = 1, mode 'codepoint'; الفئة 0 = اللاتينية، 1 = السيريلية):
اقرأ بيانات التدريب مجددًا باستخدام store_source:
اكتشاف اللغة من النص الخام — كلمات قصيرة مع حشو عند الحدود (n = 2, mode 'codepoint'; الفئة 0 = الإنجليزية، 1 = الإسبانية). تُبنى مقاطع n-gram التدريبية من الكلمات الخام باستخدام naiveBayesNgrams، وتتيح رموز الحدود — التي تُمرَّر إلى كلٍّ من الدالة والبنية — للنموذج استخدام الحرف الأول والأخير من كل كلمة:

ملاحظات

  • دلالات القاموس الحاسوبي. هذا قاموس حاسوبي: تستعمل الدالة dictGet(dict, '<class_attribute>', text) لتصنيف text (فالمفتاح هنا مُدخل للتصنيف، وليس مفتاحًا مخزّنًا)، ولا يمكن الاستعلام عن سمة العدّ، كما أن dictHas تُرجع دائمًا القيمة 1.
  • التحقق من المصدر عند التحميل. يجب أن يطابق كل n-gram في المصدر القيمتَين n وmode المضبوطة (وفي وضع codepoint يجب أيضًا أن يكون UTF-8 صالحًا)؛ وأي عدم تطابق يؤدي إلى فشل التحميل. ولأن الصفوف ذات العدّ الصفري يتم تجاهلها (راجع كيف يعمل)، فإن المصدر الفارغ أو الذي لا يحتوي إلا على قيم عدّ صفرية لا يوفّر أي بيانات للتدريب، وبالتالي يفشل تحميله.
  • تجزئة الرموز وقت الاستعلام متساهلة. بخلاف التحقق من المصدر، لا يُرفَض مُدخل الاستعلام مطلقًا. في وضع codepoint، تُفكّ البايتات غير الصالحة وفق UTF-8 بأفضل جهد بدلًا من أن تتسبب في فشل الاستعلام؛ وفي وضع token، لا يفصل بين الكلمات إلا محارف المسافات البيضاء من ASCII (أما محارف المسافات البيضاء في Unicode مثل U+00A0 فتبقى داخل الرمز). وحتى مع الإدخال غير السليم، يستمر التصنيف — وغالبًا ما يستند إلى الاحتمالات القبلية، لأن n-grams الخاصة به لن تطابق تلك التي دُرِّب عليها.
آخر تعديل في ٢٣ يوليو ٢٠٢٦