تقنيات تمثيل النصوص في معالجة اللغة الطبيعية (بما يشمل البيانات العربية)
مقدمة
لا يمكن لنماذج تعلّم الآلة معالجة بيانات النص الخام مباشرة؛ فهي تحتاج إلى مُدخلات رقمية. وهنا يأتي دور تقنيات تمثيل النصوص (Text Representation). سنستعرض فيما يلي طرقًا متعددة لتحويل البيانات النصية إلى فضاءات سمات رقمية (Numeric Feature Spaces).
التحضير
texts = [
"The quick brown fox jumps over the lazy dog",
"Natural language processing is a subfield of artificial intelligence",
"Machine learning enables computers to learn from data without explicit programming",
"Deep learning is a branch of machine learning focused on neural networks",
"Word embeddings capture semantic relationships between words in a text corpus"
]
test_txt = "Machine learning is awesome"
# Build Vocabulary
vocab = sorted(set(word for sentence in texts for word in sentence.split()))الترميز الأحادي الساخن (One-Hot Encoding)
الترميز الأحادي الساخن هو أسلوب لتمثيل النص رقميًا.
ما هو الترميز الأحادي الساخن؟
- تُمثَّل كل كلمة فريدة بمتجه (Vector) بحجم يساوي حجم المفردات (Vocabulary).
- يُضبط موضع واحد فقط في المتجه على القيمة
1، وبقية المواضع على0.
import numpy as np
word_to_index = {word: idx for idx, word in enumerate(vocab)}
def one_hot_encode(word):
"""Convert a single English word into a one-hot encoded vector."""
one_hot_vector = np.zeros(len(vocab))
if word in word_to_index:
one_hot_vector[word_to_index[word]] = 1 # Set index position to 1
return one_hot_vector
# Example: Encode individual words
example_words = test_txt.split()
one_hot_vectors = {word: one_hot_encode(word) for word in example_words}
# Print One-Hot Encodings
for word, vector in one_hot_vectors.items():
print(f"{word}: {vector}")Machine: [0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
learning: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
is: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
awesome: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]import pandas as pd
import numpy as np
from sklearn.preprocessing import OneHotEncoder
encoder = OneHotEncoder(sparse_output=False,handle_unknown='ignore')
vocab_np = np.array(vocab).reshape(-1, 1)
encoder.fit(vocab_np)
test_txt_words = np.array(test_txt.lower().split()).reshape(-1, 1)
encoded_words = encoder.transform(test_txt_words)
for word, vector in zip(test_txt_words.flatten(), encoded_words):
print(f"{word}: {vector}")machine: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
learning: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
is: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]
awesome: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.
0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]الترميز الثنائي (Binary Encoding) - أبسط صور حقيبة الكلمات (Bag of Words)
ما هو الترميز الثنائي؟
الترميز الثنائي طريقة بسيطة لتمثيل النص رقميًا. وفكرته الأساسية هي:
- بناء مفردات (Vocabulary) من جميع الكلمات الفريدة في مجموعة البيانات.
- إنشاء متجه (Vector) لكل مستند، بحيث يقابل كل موضع فيه كلمة من المفردات.
- إن وُجدت الكلمة في المستند نضع
1، وإلا نضع0.
def binary_transform(text):
"""Convert text into a binary vector."""
output = np.zeros(len(vocab))
words = set(text.split()) # Tokenize the input
for i, v in enumerate(vocab):
output[i] = v in words # Set 1 if the word exists
return output
print(binary_transform(test_txt))[0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1.
0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
vec = CountVectorizer(binary=True)
vec.fit(texts)
df = pd.DataFrame(vec.transform(texts).toarray(), columns=sorted(vec.vocabulary_.keys()))
print(df) artificial between branch brown capture computers corpus data deep \
0 0 0 0 1 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
2 0 0 0 0 0 1 0 1 0
3 0 0 1 0 0 0 0 0 1
4 0 1 0 0 1 0 1 0 0
dog ... quick relationships semantic subfield text the to without \
0 1 ... 1 0 0 0 0 1 0 0
1 0 ... 0 0 0 1 0 0 0 0
2 0 ... 0 0 0 0 0 0 1 1
3 0 ... 0 0 0 0 0 0 0 0
4 0 ... 0 1 1 0 1 0 0 0
word words
0 0 0
1 0 0
2 0 0
3 0 0
4 1 1
[5 rows x 43 columns]print(sorted(vec.vocabulary_.keys()))
print(vec.transform([test_txt]).toarray())['artificial', 'between', 'branch', 'brown', 'capture', 'computers', 'corpus', 'data', 'deep', 'dog', 'embeddings', 'enables', 'explicit', 'focused', 'fox', 'from', 'in', 'intelligence', 'is', 'jumps', 'language', 'lazy', 'learn', 'learning', 'machine', 'natural', 'networks', 'neural', 'of', 'on', 'over', 'processing', 'programming', 'quick', 'relationships', 'semantic', 'subfield', 'text', 'the', 'to', 'without', 'word', 'words']
[[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0]]df = pd.DataFrame(vec.transform([test_txt]).toarray(), columns=sorted(vec.vocabulary_.keys()))
print(df) artificial between branch brown capture computers corpus data deep \
0 0 0 0 0 0 0 0 0 0
dog ... quick relationships semantic subfield text the to without \
0 0 ... 0 0 0 0 0 0 0 0
word words
0 0 0
[1 rows x 43 columns]حقيبة الكلمات (Bag of Words)
ما هي حقيبة الكلمات؟
حقيبة الكلمات (BoW) تشبه الترميز الثنائي، لكنها تسجّل عدد مرات ظهور الكلمة في المستند بدلًا من الاكتفاء بتسجيل وجودها من عدمه (1 أو 0).
from sklearn.feature_extraction.text import CountVectorizer
import pandas as pd
vec = CountVectorizer()
vec.fit(texts)
df = pd.DataFrame(vec.transform(texts).toarray(), columns=sorted(vec.vocabulary_.keys()))
print(df) artificial between branch brown capture computers corpus data deep \
0 0 0 0 1 0 0 0 0 0
1 1 0 0 0 0 0 0 0 0
2 0 0 0 0 0 1 0 1 0
3 0 0 1 0 0 0 0 0 1
4 0 1 0 0 1 0 1 0 0
dog ... quick relationships semantic subfield text the to without \
0 1 ... 1 0 0 0 0 2 0 0
1 0 ... 0 0 0 1 0 0 0 0
2 0 ... 0 0 0 0 0 0 1 1
3 0 ... 0 0 0 0 0 0 0 0
4 0 ... 0 1 1 0 1 0 0 0
word words
0 0 0
1 0 0
2 0 0
3 0 0
4 1 1
[5 rows x 43 columns]TF-IDF (تكرار المصطلح - التكرار العكسي للمستند) - حقيبة كلمات موزونة
لماذا نستخدم TF-IDF؟
- يقلّل من وزن الكلمات الشائعة بينما يزيد من أهمية الكلمات النادرة ذات الدلالة.
- يفيد في مهام مثل تصنيف النصوص ومحركات البحث.
from sklearn.feature_extraction.text import TfidfVectorizer
vec = TfidfVectorizer()
vec.fit(texts)
df = pd.DataFrame(vec.transform(texts).toarray(), columns=sorted(vec.vocabulary_.keys()))
print(df) artificial between branch brown capture computers corpus \
0 0.00000 0.000000 0.000000 0.301511 0.000000 0.000000 0.000000
1 0.37007 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
2 0.00000 0.000000 0.000000 0.000000 0.000000 0.311561 0.000000
3 0.00000 0.000000 0.307781 0.000000 0.000000 0.000000 0.000000
4 0.00000 0.316228 0.000000 0.000000 0.316228 0.000000 0.316228
data deep dog ... quick relationships semantic \
0 0.000000 0.000000 0.301511 ... 0.301511 0.000000 0.000000
1 0.000000 0.000000 0.000000 ... 0.000000 0.000000 0.000000
2 0.311561 0.000000 0.000000 ... 0.000000 0.000000 0.000000
3 0.000000 0.307781 0.000000 ... 0.000000 0.000000 0.000000
4 0.000000 0.000000 0.000000 ... 0.000000 0.316228 0.316228
subfield text the to without word words
0 0.00000 0.000000 0.603023 0.000000 0.000000 0.000000 0.000000
1 0.37007 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
2 0.00000 0.000000 0.000000 0.311561 0.311561 0.000000 0.000000
3 0.00000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000
4 0.00000 0.316228 0.000000 0.000000 0.000000 0.316228 0.316228
[5 rows x 43 columns]df = pd.DataFrame(vec.transform([test_txt]).toarray(), columns=sorted(vec.vocabulary_.keys()))
print(df) artificial between branch brown capture computers corpus data deep \
0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
dog ... quick relationships semantic subfield text the to \
0 0.0 ... 0.0 0.0 0.0 0.0 0.0 0.0 0.0
without word words
0 0.0 0.0 0.0
[1 rows x 43 columns]التضمينات (Embeddings)
تضمينات الشخصية: كيف تكون؟
اقرأ: https://jalammar.github.io/illustrated-word2vec/
"أُهديك الحرباء الصحراوية، التي تكشف قدرتها على الاندماج مع خلفيتها عن كل ما تحتاج معرفته بخصوص جذور علم البيئة وأسس الهوية الشخصية." ~ أبناء الكثبان (Children of Dune)
فهم سمات الشخصية
على مقياس من 0 إلى 100، إلى أي درجة أنت انطوائي أم منفتح؟ (حيث 0 تعني الانطوائية القصوى و100 تعني الانفتاح الأقصى). هل سبق أن خضعت لاختبار شخصية مثل MBTI، أو الأفضل من ذلك، اختبار سمات الشخصية الخمس الكبرى (Big Five)؟
إن لم تكن قد فعلت، فهذه الاختبارات تطرح سلسلة من الأسئلة ثم تمنحك درجة على عدد من المحاور، ويُعدّ محور الانطوائية/الانفتاح أحد هذه المحاور.
مثال على نتيجة اختبار شخصية
يمكن لاختبار سمات الشخصية الخمس الكبرى أن يقدّم رؤى عميقة حول الشخصية، وقد ثبت أنه يتنبأ بالنجاح الأكاديمي والشخصي والمهني. وإليك مثالًا على شكل نتيجته:
Openness: 72/100
Conscientiousness: 85/100
Extraversion: 38/100
Agreeableness: 65/100
Neuroticism: 47/100تصوير درجات الشخصية
لنفترض أنني حصلت على 38/100 على مقياس الانطوائية/الانفتاح. يمكننا تصوير ذلك على النحو التالي:

ولجعله أكثر فائدة للعمليات الرياضية، لنطبّع المدى ليصبح من -1 إلى 1:

إضافة أبعاد أكثر
إلى أي مدى تشعر بأنك تعرف شخصًا اعتمادًا على معلومة واحدة فقط؟ ليس كثيرًا! فالبشر معقّدون. لنُضف سمة أخرى لتمثيل الشخصية في بُعدين اثنين:

وبدلًا من الاكتفاء بـ نقاط، يمكننا تمثيل الشخصية كمتجهات (Vectors). ولماذا؟ لأن المتجهات تتيح لنا قياس التشابه رياضيًا!
مقارنة شخصيتي شخصين
لنفترض أنني بحاجة لأن يحلّ محلي شخص ذو شخصية مشابهة. في الشكل أدناه نقارن بين شخصين آخرين:

أي الشخصين أشبه بي؟
من الطرق الشائعة لقياس التشابه في فضاء المتجهات هي التشابه جيب التمام (Cosine Similarity):

إذا كانت قيمة تشابه جيب التمام قريبة من 1، فإن المتجهات تشير إلى الاتجاه نفسه، أي أنها أكثر تشابهًا.
- الشخص رقم 1 أشبه بي لأن متجهه يشير إلى الاتجاه العام نفسه الذي يشير إليه متجهي.
- الشخص رقم 2 أقل تشابهًا لأن متجهه في ربع مختلف.
التوسّع إلى أبعاد أكثر
بُعدان لا يكفيان لتمثيل الشخصية الإنسانية تمثيلًا كاملًا. وتشير عقود من أبحاث علم النفس إلى أن أفضل وصف للشخصية يكون عبر خمس سمات رئيسية (السمات الخمس الكبرى)، إلى جانب سمات فرعية عديدة.

فما المشكلة إذن؟ لا يمكننا رسم أسهم مرتّبة لخمسة أبعاد! لكن في تعلّم الآلة، غالبًا ما نتعامل مع فضاءات عالية الأبعاد. ولحسن الحظ، يظل التشابه جيب التمام صالحًا لأي عدد من الأبعاد!

أهم الأفكار
في ختام هذا الجزء، ينبغي أن نتذكّر فكرتين أساسيتين:
- يمكننا تمثيل الأشخاص (والأشياء) كمتجهات من الأرقام - وهو أمر رائع بالنسبة للآلات!
- يمكننا بسهولة حساب مدى تشابه هذه المتجهات مع بعضها باستخدام التشابه جيب التمام.

تضمينات الكلمات (Word Embeddings)
Word2Vec (يُدرَّب بالتنبؤ اعتمادًا على السياق)
- CBOW (حقيبة الكلمات المستمرة): يتنبأ بالكلمة انطلاقًا من سياقها.
- Skip-Gram: يتنبأ بكلمات السياق انطلاقًا من كلمة واحدة.
import gensim
word2vec_model = gensim.models.KeyedVectors.load_word2vec_format(
"GoogleNews-vectors-negative300.bin", binary=True
)
print("Word2Vec (King):", word2vec_model["king"][:10]) # First 10 valuesWord2Vec (King): [ 0.12597656 0.02978516 0.00860596 0.13964844 -0.02563477 -0.03613281
0.11181641 -0.19824219 0.05126953 0.36328125]print("Word2Vec (Queen):", word2vec_model["Queen"][:10]) # First 10 valuesWord2Vec (Queen): [-0.22070312 -0.17480469 -0.10498047 0.2578125 0.16210938 -0.13085938
-0.16699219 0.07373047 -0.07226562 0.02404785]GloVe (يُدرَّب باستخدام إحصاءات التوافق اللفظي - Word Co-Occurrence)
- بخلاف Word2Vec، يعتمد GloVe على تحليل المصفوفات (Matrix Factorization) لمصفوفة توافق الكلمات مع بعضها.
- يلتقط العلاقات العامة بين الكلمات (Global Word Relationships).
import numpy as np
# Load GloVe embeddings
glove_embeddings = {}
with open("glove.6B.100d.txt", "r", encoding="utf-8") as f:
for line in f:
values = line.split()
word = values[0]
vector = np.asarray(values[1:], dtype="float32")
glove_embeddings[word] = vector
print("GloVe 'king':", glove_embeddings["king"][:10]) # Show first 10 valuesGloVe 'king': [-0.32307 -0.87616 0.21977 0.25268 0.22976 0.7388 -0.37954 -0.35307
-0.84369 -1.1113 ]