الخطوة 3: إعداد بياناتك

قبل إدخال بياناتنا في أي نموذج، يجب تحويلها إلى تنسيق يمكن أن يفهمه النموذج.

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

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

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

  1. الترميز: قسّم النصوص إلى كلمات أو نصوص فرعية أصغر، ما يتيح تعميمًا جيدًا للعلاقة بين النصوص والتصنيفات. ويحدد هذا "مفردات" مجموعة البيانات (مجموعة من الرموز المميزة الفريدة المتوفرة في البيانات).

  2. الاتجاه: حدد مقياسًا رقميًا جيدًا لوصف هذه النصوص.

دعونا نرى كيفية إجراء هاتين الخطوتين لكل من المتجهات n-g والمتجهات التسلسلية، بالإضافة إلى كيفية تحسين تمثيلات المتجهات باستخدام تقنيات تحديد الخصائص والتسوية.

متجهات N-gram [الخيار A]

في الفقرات اللاحقة، سنرى كيفية عمل الترميز والتوجيه لنماذج n-gram. وسوف نتناول أيضًا كيف يمكننا تحسين تمثيل ن جرام باستخدام أساليب تحديد الخصائص والتسوية.

في متجه n g، يتم تمثيل النص كمجموعة من n-grams الفريدة: مجموعات من الرموز المميزة بـ n المجاورة (عادة، الكلمات). ضع في الاعتبار النص The mouse ran up the clock. يمكنك هنا:

  • كلمة unigrams (n = 1) هي ['the', 'mouse', 'ran', 'up', 'clock'].
  • كلمة bigrams (n = 2) هي ['the mouse', 'mouse ran', 'ran up', 'up the', 'the clock']
  • وما إلى ذلك.

إنشاء رمز مميّز

وقد وجدنا أن الترميز إلى كلمات يونيغرام + بيجرامات يوفر دقة جيدة مع تقليل وقت الحوسبة.

المتّجهات

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

Texts: 'The mouse ran up the clock' and 'The mouse ran down'
Index assigned for every token: {'the': 7, 'mouse': 2, 'ran': 4, 'up': 10,
  'clock': 0, 'the mouse': 9, 'mouse ran': 3, 'ran up': 6, 'up the': 11, 'the
clock': 8, 'down': 1, 'ran down': 5}

بمجرد تعيين الفهارس لمخططات n، نتجه عادةً باستخدام أحد الخيارات التالية.

ترميز واحد فعال: يتم تمثيل كل عيّنة من النص كمتّجه يشير إلى توفُّر رمز مميّز أو عدم توفّره في النص.

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1]

ترميز العد: يتم تمثيل كل نموذج نص كمتجه يشير إلى عدد الرمز المميز في النص. يُرجى العِلم أنّ العنصر المقابل لليونيغرام "الـ" يتم تمثيله الآن كـ 2 لأنّ كلمة "ال" تظهر مرّتين في النص.

'The mouse ran up the clock' = [1, 0, 1, 1, 1, 0, 1, 2, 1, 1, 1, 1]

ترميز Tf-idf: تكمن المشكلة في الأسلوبَين أعلاه في أنّه لن يتم فرض عقوبات على الكلمات الشائعة التي تظهر بتكرارات متشابهة في جميع المستندات (أي الكلمات التي ليست فريدة بشكل خاص لعينات النص في مجموعة البيانات). على سبيل المثال، ستظهر كلمات مثل "a" بشكل متكرر جدًا في جميع النصوص. لذا فإن ارتفاع عدد الرموز المميزة لكلمة "the" أعلى من عدد الكلمات الأخرى الأكثر فائدة ليس مفيدًا للغاية.

'The mouse ran up the clock' = [0.33, 0, 0.23, 0.23, 0.23, 0, 0.33, 0.47, 0.33, 0.23, 0.33, 0.33]

(راجع مكتبة ساي كيت ليرن TفيدfTransformer)

هناك العديد من تمثيلات المتجه الأخرى، لكن الثلاثة السابقة هي الأكثر استخدامًا.

لاحظنا أن ترميز tf-idf أفضل بشكل طفيف من الاثنين الآخرين في ما يتعلق بالدقة (في المتوسط: أعلى بنسبة من 0.25 إلى 15%)، وننصحك باستخدام هذه الطريقة لتحويل وحدات n غرام. ومع ذلك، ضع في اعتبارك أنها تشغل ذاكرة أكبر (لأنها تستخدم تمثيل النقطة العائمة) وتستغرق وقتًا أطول في حسابها، خاصة لمجموعات البيانات الكبيرة (قد تستغرق ضعف المدة في بعض الحالات).

اختيار الميزات

عندما نحول جميع النصوص في مجموعة البيانات إلى رموز يوني+bigram، فقد ننتهي بعشرات الآلاف من الرموز المميزة. لا تساهم كل هذه الرموز/الميزات في توقع التسمية. لذلك يمكننا إسقاط بعض الرموز المميزة، على سبيل المثال التي تحدث نادرًا جدًا عبر مجموعة البيانات. ويمكننا أيضًا قياس أهمية الميزة (مدى مساهمة كل رمز مميّز في توقّعات التصنيفات) وتضمين الرموز المميّزة الأكثر إفادة فقط.

هناك العديد من الدوال الإحصائية التي تتخذ الميزات والتسميات المقابلة وتخرج درجة أهمية الميزة. هناك دالتان شائعتان الاستخدام هما f_classif وchi2. وتوضح تجاربنا أن كلتا الدالتين تؤديان أداءً جيدًا بنفس القدر.

والأهم من ذلك، لاحظنا أنّ الدقة تبلغ ذروتها عند حوالي 20,000 ميزة للعديد من مجموعات البيانات (راجِع الشكل 6). وتساهم إضافة المزيد من الميزات التي تتجاوز هذا الحدّ في استخدام قليل جدًا، وأحيانًا ما يؤدي إلى فرط التخصيص وخفض مستوى الأداء.

أعلى K مقابل الدقة

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

التسوية

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

تضع التعليمة البرمجية التالية كل الخطوات المذكورة أعلاه معًا:

  • إنشاء رموز مميّزة لعينات النص في كلمات uni+bigram
  • أيهما يتجه باستخدام ترميز tf-idf،
  • حدد فقط أهم 20000 ميزة من متجه الرموز المميزة عن طريق تجاهل الرموز المميزة التي تظهر أقل من مرتين واستخدام f_classif لحساب أهمية الميزة.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.feature_selection import SelectKBest
from sklearn.feature_selection import f_classif

# Vectorization parameters
# Range (inclusive) of n-gram sizes for tokenizing text.
NGRAM_RANGE = (1, 2)

# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Whether text should be split into word or character n-grams.
# One of 'word', 'char'.
TOKEN_MODE = 'word'

# Minimum document/corpus frequency below which a token will be discarded.
MIN_DOCUMENT_FREQUENCY = 2

def ngram_vectorize(train_texts, train_labels, val_texts):
    """Vectorizes texts as n-gram vectors.

    1 text = 1 tf-idf vector the length of vocabulary of unigrams + bigrams.

    # Arguments
        train_texts: list, training text strings.
        train_labels: np.ndarray, training labels.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val: vectorized training and validation texts
    """
    # Create keyword arguments to pass to the 'tf-idf' vectorizer.
    kwargs = {
            'ngram_range': NGRAM_RANGE,  # Use 1-grams + 2-grams.
            'dtype': 'int32',
            'strip_accents': 'unicode',
            'decode_error': 'replace',
            'analyzer': TOKEN_MODE,  # Split text into word tokens.
            'min_df': MIN_DOCUMENT_FREQUENCY,
    }
    vectorizer = TfidfVectorizer(**kwargs)

    # Learn vocabulary from training texts and vectorize training texts.
    x_train = vectorizer.fit_transform(train_texts)

    # Vectorize validation texts.
    x_val = vectorizer.transform(val_texts)

    # Select top 'k' of the vectorized features.
    selector = SelectKBest(f_classif, k=min(TOP_K, x_train.shape[1]))
    selector.fit(x_train, train_labels)
    x_train = selector.transform(x_train).astype('float32')
    x_val = selector.transform(x_val).astype('float32')
    return x_train, x_val

باستخدام تمثيل متجه الغرام، نتجاهل الكثير من المعلومات حول ترتيب الكلمات والقواعد النحوية (في أحسن الأحوال، يمكننا الاحتفاظ ببعض معلومات الترتيب الجزئية عندما تكون n > 1). وهذا ما يسمى نهج حزمة الكلمات. ويتم استخدام هذا التمثيل مع النماذج التي لا تراعي الترتيب، مثل الانحدار اللوجستي والمؤشرات الطبقات متعددة الطبقات وآلات تعزيز التدرج وآلات متجه الدعم.

متّجهات التسلسل [الخيار ب]

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

بالنسبة لبعض نماذج النصوص، يُعد ترتيب الكلمات أمرًا بالغ الأهمية لمعنى النص. على سبيل المثال، كانت الجمل، "كنت أكره رحلتي. تغيرت دراجتي الجديدة ذلك تمامًا" لا يمكن فهمها إلا عند القراءة بالترتيب. يمكن لنماذج مثل CNN/RNN أن تستنتج المعنى من ترتيب الكلمات في العينة. بالنسبة لهذه النماذج، نقدم النص على أنه تسلسل من الرموز المميزة للحفاظ على الترتيب.

إنشاء رمز مميّز

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

المتّجهات

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

Texts: 'The mouse ran up the clock' and 'The mouse ran down'

تم تخصيص فهرس لكل رمز مميّز:

{'clock': 5, 'ran': 3, 'up': 4, 'down': 6, 'the': 1, 'mouse': 2}

ملاحظة: يتم استخدام كلمة "the" في أغلب الأحيان، ولذلك يتم تعيين قيمة الفهرس 1 لها. تحتفظ بعض المكتبات بالفهرس 0 للرموز المميزة غير المعروفة، كما هو الحال هنا.

تسلسل فهارس الرموز المميّزة:

'The mouse ran up the clock' = [1, 2, 3, 4, 1, 5]

هناك خياران متاحان لتوجيه تسلسلات الرموز المميّزة:

ترميز واحد فعال: يتم تمثيل التسلسلات باستخدام متّجهات الكلمات في مساحة n ذات أبعاد n حيث يكون n = حجم المفردات. هذا التمثيل ممتاز عندما ننشئ رموزًا مميّزة كأحرف، وبالتالي تكون المفردات صغيرة. فعندما نعمل على ترميز الكلمات، سيكون للمفردات عادةً عشرات الآلاف من الرموز المميزة، ما يجعل المتجهات التي لها أول استجابة متكافئة وغير فعالة للغاية. مثال:

'The mouse ran up the clock' = [
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 1, 0, 0, 0, 0],
  [0, 0, 0, 1, 0, 0, 0],
  [0, 0, 0, 0, 1, 0, 0],
  [0, 1, 0, 0, 0, 0, 0],
  [0, 0, 0, 0, 0, 1, 0]
]

تضمين الكلمات: للكلمات التي تحمل معانٍ مرتبطة بها. ونتيجةً لذلك، يمكننا تمثيل رموز الكلمات المميزة في مساحة متجهة كثيفة (حوالي مئات الأرقام الحقيقية)، حيث يشير الموقع والمسافة بين الكلمات إلى مدى تشابهها دلاليًا (راجِع الشكل 7). ويُطلق على هذا التمثيل تضمين كلمات.

تضمين الكلمات

الشكل 7: تضمين الكلمات

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

طبقة التضمين

الشكل 8: طبقة التضمين

اختيار الميزات

لا تساهم كل الكلمات الواردة في بياناتنا في التنبؤ بالتصنيفات. يمكننا تحسين عملية التعلُّم من خلال التخلص من الكلمات النادرة أو غير ذات الصلة من مفرداتنا. في الواقع، نلاحظ أنّ استخدام 20,000 ميزة الأكثر تكرارًا يكون كافيًا بشكل عام. وينطبق ذلك على نماذج الغرام أيضًا (راجع الشكل 6).

لنضع كل الخطوات المذكورة أعلاه في متجه التسلسل معًا. تؤدي التعليمة البرمجية التالية المهام التالية:

  • تحويل النص إلى رموز مميّزة
  • يتعلّم المفردات باستخدام أفضل 20,000 رمز مميّز
  • تحويل الرموز المميزة إلى متجهات متتابعة
  • توزيع التسلسلات على طول تسلسل ثابت
from tensorflow.python.keras.preprocessing import sequence
from tensorflow.python.keras.preprocessing import text

# Vectorization parameters
# Limit on the number of features. We use the top 20K features.
TOP_K = 20000

# Limit on the length of text sequences. Sequences longer than this
# will be truncated.
MAX_SEQUENCE_LENGTH = 500

def sequence_vectorize(train_texts, val_texts):
    """Vectorizes texts as sequence vectors.

    1 text = 1 sequence vector with fixed length.

    # Arguments
        train_texts: list, training text strings.
        val_texts: list, validation text strings.

    # Returns
        x_train, x_val, word_index: vectorized training and validation
            texts and word index dictionary.
    """
    # Create vocabulary with training texts.
    tokenizer = text.Tokenizer(num_words=TOP_K)
    tokenizer.fit_on_texts(train_texts)

    # Vectorize training and validation texts.
    x_train = tokenizer.texts_to_sequences(train_texts)
    x_val = tokenizer.texts_to_sequences(val_texts)

    # Get max sequence length.
    max_length = len(max(x_train, key=len))
    if max_length > MAX_SEQUENCE_LENGTH:
        max_length = MAX_SEQUENCE_LENGTH

    # Fix sequence length to max value. Sequences shorter than the length are
    # padded in the beginning and sequences longer are truncated
    # at the beginning.
    x_train = sequence.pad_sequences(x_train, maxlen=max_length)
    x_val = sequence.pad_sequences(x_val, maxlen=max_length)
    return x_train, x_val, tokenizer.word_index

اتجاه التصنيف

تناولنا كيفية تحويل عينة من البيانات النصية إلى متجهات رقمية. يجب تطبيق عملية مماثلة على التسميات. يمكننا ببساطة تحويل التصنيفات إلى قيم في النطاق [0, num_classes - 1]. على سبيل المثال، إذا كانت هناك 3 فئات يمكننا فقط استخدام القيم 0 و1 و2 لتمثيلها. داخليًا، ستستخدم الشبكة متجهات أحادية الاتجاه لتمثيل هذه القيم (تجنب استنتاج علاقة غير صحيحة بين التسميات). ويعتمد هذا التمثيل على دالة الفقدان ووظيفة تفعيل الطبقة الأخيرة التي نستخدمها في الشبكة العصبية. سنتعلم المزيد حول هذه في القسم التالي.