מארז מילים (BoW) הוא טכניקה בעיבוד שפה טבעית (NLP). הוא משמש באופן נפוץ להמיר נתוני טקסט לפורמט שניתן לקריאה על ידי מכונות, באופן ספציפי ערכים מספריים, ללא התחשבות בגרמטיקה וסדר המילים. הבנת BoW חשובה לכל מי שעובד עם נתוני טקסט. פייתון מספקת כלים וספריות מרובות ליישום מארז מילים באופן יעיל.
בטוטוריאל זה, נצלול לתוך BoW, נציג את המושגים שלו, נכסה את שימושיו, ונעבור דרך השקפה מפורטת של יישום בפייתון. עד סוף הטוטוריאל, תוכלו ליישם את מודל מארז המילים לבעיות עולם אמיתי. אם אתם חדשים לNLP, בדקו את מסלול הכישורים של עיבוד שפה טבעית בפייתון כדי ללמוד יותר.
מהו מארז מילים?
מזוודת מילים היא טכניקה להוצאת מאפיינים מנתוני טקסט למשימות למידה מכונה, כמו סיווג טקסט וניתוח רגשות. זה חשוב כי אלגוריתמי למידה מכונה לא יכולים לעבד נתוני טקסט. תהליך המרת הטקסט למספרים נקרא הוצאת מאפיינים או קידוד מאפיינים.
מזוודת מילים מבוססת על הופעת המילים במסמך. התהליך מתחיל במציאת האוצר המילים בטקסט ומדידת הופעתן. זה נקרא מזוודה כי הסדר והמבנה של המילים אינם נחשבים, רק הופעתן.
מודל מזוודת המילים שונה ממודל המזוודה המתמשכת של מילים (CBOW), אשר לומד טמיעת מילים צפופה על ידי שימוש במילים המקיפות כדי לחזות מילה יעד, תוך תפיסת יחסים סמנטיים בין מילים. CBOW דורש אימון על קורפוס גדול ומייצר וקטורים דו-ממדיים שהם יקרים ליישומי NLP מורכבים שבהם ההקשר של המילה חשוב.
היבט |
BOW |
CBOW |
מטרה |
סופר את מספר הופעות של כל מילה |
מנבא מילה מטרה על פי ההקשר |
סוג היציאה |
וקטור גבוה-מימדי, דליל |
וקטור נמוך-מימדי, צפוף |
שוקל את ההקשר |
לא (מתעלם מסדר המילים) |
כן (משתמש במילים סובבות) |
ייצוג |
וקטור תכיפות דליל |
וקטור צפוף המתאר סמנטיקה |
מורכבות |
נמוך (לא דרוש אימון) |
גבוה (דרוש אימון על מאגר גדול) |
יישומים טיפוסיים |
תיקון טקסט, ניתוח מצב רוח |
מיפוי מילים, משימות פיתוח שפה חיה דורשות הקשר |
למה להשתמש בשק של מילים?
שק של מילים יעיל ברבות משימות פיתוח שפה חיה, כמה סיבות לשימוש בו כוללות:
- הוצאת מאפיינים: היא הופכת נתוני טקסט לא מאורגנים לנתונים מאורגנים, שיכולים לשמש כאינפוט לאלגוריתמים שונים של למידת מכונה.
- פשטות ויעילות: BoW קל ליישום מבחינה מחשובית, ועובד טוב לקורפוסים קטנים עד בינוניים.
- דמיון בין מסמכים: ניתן להשתמש בו לחישוב דמיון בין מסמכי טקסט באמצעות טכניקות כמו דמיון קוסינוס.
- תיאור טקסט: כאשר משלבים טכניקות כמו Naive Bayes, BoW יעיל למשימות קליפות טקסט כמו קליפת דואר זבל, וניתוח רגשות.
אולם, יש גם חסרונות, כמו שלא נוקט בחשבון סמנטיקה, מבנה מילה או סדר המילים.
שלבים ליישום שקלול מילים ב Python
ליצירת מודל של תיק-מילים, אנחנו לוקחים את כל המילים במאגר ויוצרים עמודה עם כל מילה. שורות המטריצה מייצגות את המשפטים. אם מילה מסוימת קיימת במשפט, היא מיוצגת על ידי 1, ואם המילה לא קיימת, היא מיוצגת על ידי 0. כל מילה בעמודה מייצגת מאפיין יחיד.
בסופו של דבר, אנחנו מקבלים מטריצה דלילה. מטריצה דלילה היא מטריצה עם הרבה אפסים.
טיפול מוקדם בנתונים
ליצירת מודל תיק-מילים בפיתון, אנחנו צריכים לבצע כמה שלבים של טיפול מוקדם. שלבים אלה כוללים טוקניזציה והסרת מילות חוזרניות.
התהליך של טוקניזציה הוא פירוק חלק טקסט ליחידות קטנות יותר, בדרך כלל מילים. אתה יכול לבצע טוקניזציה באמצעות NLTK.
מילות עצירה הן מילים נפוצות באנגלית, כמו "the," "that," ו"אנחנו," שלא תורמות לקול המשפט.
import nltk from nltk.corpus import stopwords from nltk.tokenize import word_tokenize # הוריד תוואי דיברים ומפועלן אם עדיין לא עשית זאת nltk.download("punkt") nltk.download("stopwords") # משפט דוגמה sentence = "This is an example showing how to remove stop words from a sentence." # חלק את המשפט למילים words = word_tokenize(sentence) # השג את רשימת מילות התוואי באנגלית stop_words = set(stopwords.words("english")) # הסר מילות תוואי מהמשפט filtered_sentence = [word for word in words if word.lower() not in stop_words] # אחד את המילים חזרה למשפט filtered_sentence = " ".join(filtered_sentence) print(filtered_sentence)
יציאה:
example showing remove stop words sentence.
יצירת אוצר מילים
אוצר מילים הוא אוסף של מילים יחידות שנמצאו במערכת טקסט. בניית אוצר מילים כוללת איסוף כל המילים היחידות מהמערכת וספירת תדירותן. אוצר המילים הזה מועיל למשימות שונות של יחסי-גומלין שפה כמו מודלים של שפה, הטמעות מילים ותיקון טקסט.
הקוד הבא יוצר פיזור תדירות פשוט של מילים במערכת, שימושי למשימות בסיסיות של יחסי-גומלין שפה כמו בניית אוצר מילים או הבנת תוכן טקסט:
- המשתנה corpus מכיל כמה משפטי דוגמה. ביישומים אמיתיים, זה יכיל נתוני טקסט גדולים יותר ומגוונים יותר.
- vocab =
defaultdict(int)
מפשט את ספירת תדירות המילים, על ידי התחלת כל מילה חדשה עם מספר 0 אוטומטית, ומאפשר הגדלה ישירה בלי צורך בבדיקות. - כל משפט מומר למקרה קטן ומופקיע באמצעות ביטויים רגולריים.
\b\w+\b
התבנית התאימה מזהה מילים המכילות רק תווים אלפביתיים-מספריים, ומתעלמת מפיסוק וסימנים אחרים. - הספירה של כל מילה מועדכנת במילון vocab.
- האוצר ממוקם לפי תדירות בסדר יורד, כך שניתן לראות בקלות את המילים הנפוצות ביותר בראש, ומוצג להתייחסות.
import re לייבא את מודול ביטויים רגילים כדי לעזור בעיבוד טקסט from collections import ( defaultdict, ) לייבא defaultdict כדי לטפל בקלות בספירת תדירות מילים מאגר דוגמה של טקסט - קבוצת גדולה של משפטים לניתוח corpus = [ "Tokenization is the process of breaking text into words.", "Vocabulary is the collection of unique words.", "The process of tokenizing is essential in NLP.", ] לאתחל defaultdict עם ערכי מספרים כדי לאחסן תדירויות מילים defaultdict(int) מאתחל כל מפתח חדש עם ערך מספרי ברירת מחדל של 0 vocab = defaultdict(int) להיכנס ללולאה דרך כל משפט במאגר כדי למפות ולנרמל for sentence in corpus: להמיר את המשפט לאותיות קטנות כדי להבטיח התאמה בספירה (למשל, 'Tokenization' ו-'tokenization' נחשבות כאותה מילה) להשתמש בביטויים רגילים למציאת מילים המורכבות מתוואי אלפביתיים בלבד words = re.findall(r"\b\w+\b", sentence.lower()) לכל מילה שנמצאה, להעלות את הספירה שלה במילון vocab for word in words: vocab[word] += 1 להמיר את הvocab defaultdict למילון רגיל כדי לטפל בו בקלות ולסורט אותו לסורט את המילון לפי תדירות מילים בסדר יורד ולהמיר אותו למילון חדש sorted_vocab = dict(sorted(vocab.items(), key=lambda x: x[1], reverse=True)) להציג את המילון המסורט בכל מילה ותדירות ספירתה print("Vocabulary with Frequencies:", sorted_vocab)
הוצאה:
Vocabulary with Frequencies: {'is': 3, 'the': 3, 'of': 3, 'process': 2, 'words': 2, 'tokenization': 1, 'breaking': 1, 'text': 1, 'into': 1, 'vocabulary': 1, 'collection': 1, 'unique': 1, 'tokenizing': 1, 'essential': 1, 'in': 1, 'nlp': 1}
בניית אוצר מילים באופן ידני יכולה להיות דורשת זמן, במיוחד לתחזיות גדולות. CountVectorizer של Scikit-learn ממכ"ל את התהליך הזה ומאפשר עיבוד טקסט יותר גמיש, כפי שנראה מאוחר יותר.
יישום Bag of Words באמצעות Python (מאפס)
בואו נתחיל עם יישום פשוט של Bag of Words מאפס בPython. זה יעזור לך להבין את חלקי הבנייה והמכניקה של איך הוא עובד מתחת למכסה.
יישום ידני
שלב 1: עיבוד מקדים של נתוני טקסט
נתחיל בהגדרת פונקציה פשוטה לעיבוד טקסט, כולל תיוג, המרה לאותיות קטנות והסרת סימני פיסוק.
from collections import defaultdict import string # דוגמת נתוני טקסט: משפטים corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # פונקציה לעיבוד מקדים של טקסט def preprocess(text): # המרה לאותיות קטנות text = text.lower() # הסרת סימני פיסוק text = text.translate(str.maketrans("", "", string.punctuation)) # תיוג: פיצול הטקסט למילים tokens = text.split() return tokens # החלת עיבוד מקדים על הקורפוס הדוגמתי processed_corpus = [preprocess(sentence) for sentence in corpus] print(processed_corpus)
פלט:
[['python', 'is', 'amazing', 'and', 'fun'], ['python', 'is', 'not', 'just', 'fun', 'but', 'also', 'powerful'], ['learning', 'python', 'is', 'fun']]
שלב 2: בניית אוצר מילים
כעת, עלינו לסרוק את כל המסמכים ולבנות רשימה מלאה של מילים ייחודיות, זהו אוצר המילים שלנו.
להתחיל קבוצה ריקה עבור המילון vocabulary = set() לבנות את המילון for sentence in processed_corpus: vocabulary.update(sentence) להמיר לרשימה ממוינת vocabulary = sorted(list(vocabulary)) print("Vocabulary:", vocabulary)
שלב 3: לחשב תדירות מילים ולווקטוריזם
עכשיו נחשב את תדירות כל מילה במילון עבור כל מסמך במאגר המעובד.
def create_bow_vector(sentence, vocab): vector = [0] * len(vocab) להתחיל וקטור של אפסים for word in sentence: if word in vocab: idx = vocab.index(word) למצוא את האינדקס של המילה במילון vector[idx] += 1 להגדיל את הספירה באינדקס הזה return vector
בשלב זה, תצרו ייצוג של "שקית מילים" (Bag of Words) עבור כל מסמך במאגר שלכם.
ליצור וקטור BoW עבור כל משפט במאגר המעובד bow_vectors = [create_bow_vector(sentence, vocabulary) for sentence in processed_corpus] print("Bag of Words Vectors:") for vector in bow_vectors: print(vector)
יצוא:
Bag of Words Vectors: [0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1] [1, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1] [0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1]
שימוש ב-CountVectorizer של Scikit-learn
בניית מודל 'תיק מילים' (Bag of Words) באופן ידני טוב ללימוד, אך לשימוש בייצור, תרצו להשתמש בספריות יעילות ומותאמות לכדי, כמו Scikit-learn.
הפונקציה של פייתון שאנו משתמשים בה לקיטוע היא CountVectorizer, שמיובאת מה sklearn.feature_extraction.text
. אחת מהתכונות של CountVectorizer
היא max_features
, שמייצגת את מספר המילים המרבי שהייתם רוצים להחזיק במודל שק המילים. במקרה זה, אנו משתמשים ב None, מה שאומר שכל התכונות ישמשו.
לאחר יצירת מופע של CountVectorizer
, השתמשו בשיטה .fit_transform(
) כדי ליצור את מודל שק המילים. לאחר מכן, השתמשו ב .toarray()
כדי להמיר את מודל שק המילים למערכי numpy שניתן להזין למודל למידה חישובית.
ברגע שמותקן, CountVectorizer בנה מילון של מקומות תכונות. ערך המקום של מילה באוצר המילים קשור לתדירות שלה בכל מאגר האימון.
from sklearn.feature_extraction.text import CountVectorizer # מאגר מקורי corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # יצירת אובייקט CountVectorizer vectorizer = CountVectorizer() # התאמה ושינוי פורמט המאגר X = vectorizer.fit_transform(corpus) # הדפסת אוצר המילים שנוצר print("Vocabulary:", vectorizer.get_feature_names_out()) # הדפסת מטריצת מילולי-שקלים print("BoW Representation:") print(X.toarray())
תוצאה:
markdownVocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] BoW Representation: [[0 1 1 0 1 1 0 0 0 0 1] [1 0 0 1 1 1 1 0 1 1 1] [0 0 0 0 1 1 0 1 0 0 1]]
דוגמה: החלת מודל מילולי-שקלים
בואו כעת נחלה את מודל הBoW על מאגר טקסט קטן הכולל שלוש ביקורות סרטים כדי להדגים את כל התהליך.
נשתמש ב CountVectorizer של Scikit-learn כדי לחלות את מודל הBoW על מאגר הטקסט הקטן הזה.
אלו הם השלבים שנבצע:
CountVectorizer
מפריד את הטקסט, מסיר נקודות פיסוק, ומשנה את המילים לאותיות קטנות אוטומטית..fit_transform(corpus)
הופך את המקור למטריצת תיעוד-מונחים, שבה כל שורה מייצגת מסמך וכל עמודה מייצגת מילה מהמילון.X_dense
היא המטריצה הצפופה שמייצגת את תדירות כל מילה בכל מסמך.
from sklearn.feature_extraction.text import CountVectorizer # מקור דוגמה של ביקורות סרטים corpus = [ "I loved the movie, it was fantastic!", "The movie was okay, but not great.", "I hated the movie, it was terrible.", ] # להתחיל את CountVectorizer vectorizer = CountVectorizer() # להתאים ולהמיר את המקור למטריצת תיעוד-מונחים X = vectorizer.fit_transform(corpus) # להמיר את מטריצת תיעוד-מונחים לפורמט צפוף (אופציוני להצגה ויזואלית) X_dense = X.toarray() # לקבל את המילון (מיפוי של מילים למיקומי אינדקס) vocab = vectorizer.get_feature_names_out() # להדפיס את המילון ומטריצת תיעוד-מונחים print("Vocabulary:", vocab) print("Document-Term Matrix:\n", X_dense)
יציאה:
Vocabulary: ['but' 'fantastic' 'great' 'hated' 'it' 'loved' 'movie' 'not' 'okay' 'terrible' 'the' 'was'] Document-Term Matrix: [[0 1 0 0 1 1 1 0 0 0 1 1] # ביקורת ראשונה: "אהבתי את הסרט, הוא היה מעולה!" [1 0 1 0 1 0 1 1 1 0 1 1] # ביקורת שנייה: "הסרט היה בסדר, אבל לא גדול." [0 0 0 1 1 0 1 0 0 1 1 1]] # ביקורת שלישית: "שנאתי את הסרט, הוא היה נוראי."
כך אנחנו יכולים לפרש את התצוגה המוצגת לעיל:
- כל מילה יחודית במאגר מוקצית למקום, והמילים ממויינות אלפביתית. למשל, "אבל" נמצא במקום 0, "מעולה" נמצא במקום 1, "סרט" נמצא במקום 6, וכך הלאה.
- כל שורה במטריצה של המסמכים מייצגת ביקורת על סרט, וכל עמודה מתאימה למילה מהמילון. הערכים במטריצה מייצגים את תדירות המילה במסמך המסוים.
- ביקורת ראשונה: [0 1 0 0 1 1 1 0 0 0 1 1] מראה ש:
- המילה "מעולה" מופיעה פעם אחת (1 במקום 1),
- המילה "אהבתי" מופיעה פעם אחת (1 במקום 5),
- המילה "סרט" מופיעה פעם אחת (1 במקום 6),
- המילה "היה" מופיעה פעם אחת (1 במקום 4),
- וכך הלאה.
וקטור BoW יכול להיפרש כך:
- כל מסמך הוא וקטור של מספרים המייצגים מספרי מילים. המימדים של הוקטור שווים לגודל של המילון. במקרה זה, למילון יש 12 מילים, אז כל ביקורת הופכת לווקטור 12-מימדי.
- רוב המילים בכל שורה הן אפסים מכיוון שלא כל מסמך מכיל את כל המילים מהמילון. לכן, מודלי BoW הם לרוב דלילים, כלומר, יש להם הרבה אפסים.
יתרונות ומגבלות של מודל תיק המילים
בואו נסקור כעת כמה מהיתרונות והמגבלות של מודל תיק המילים.
יתרונות
- קל ליישם ולהבין: מודל תיק המילים הוא אחד משיטות הייצוג הטקסטואלי הפשוטים ביותר, ומתאים במיוחד למתחילים. פשטותו מאפשרת יישום מהיר ללא צורך בתיפול מורכב או במודלים מיוחדים.
- קל לשימוש למשימות סיווג טקסט: תיק המילים מתאים היטב למשימות בסיסיות כמו סיווג טקסט, ניתוח רגשות וזיהוי ספאם. משימות אלו לרוב לא דורשות מודלים שפות מורכבים, כך שייצוג BOW הוא מספיק ויעיל.
מגבלות
- גודל מילון משפיע על דחיסות הייצוגים: ככל שגודל המילון גדול יותר, הייצוג הופך ליותר דחוס ומרובה-מימדים. דחיסות זו יכולה להקשות על המודלים ללמוד אפקטיבית ודורשת כוונון זהיר של גודל המילון כדי להימנע מעלויות מחשוביות גבוהות.
- יוצר מטריצות דחוסות שהן יקרות על המחשב: מאחר וכל דוקומנט מיוצג על ידי תדירות כל מילה במילון פוטנציאלית גדול, המטריצות התוצאתיות הן לרוב ברובן אפסים, מה שיכול להיות לא יעיל לאחסן ולעבד בערוצי למידה ממוכנת. מטריצות דחוסות צורכות זיכרון ניכר ולעיתים דורשות כלים וספריות מיוחדים לאחסון יעיל וחישוב, במיוחד עם מערכות נתונים גדולות.
- אובדן משמעות והקשר: BOW מתעלם מסדר המילים וממבנה המשפט, מה שגורם לאובדן יחסים דקדוקיים ומשמעות. מגבלה זו הופכת אותו פחות מתאים למשימות שבהן חשיבות להקשר, ניואנסים וסדר המילים, כמו תרגום או זיהוי רגשות במשפטים מורכבים.
האסטרטגיות הבאות יכולות להיות משמשות להקטנת גודל אוצר המילים בשיטת Bag of Words:
- התעלמות מרישיון.
- הסרת סימני פונקציה.
- הסרת מילות נפילה, כלומר מילים נפוצות כמו "ה" ו"א".
- וודאי שכל המילים מונחות נכון.
- שימוש בטכניקות צמיחה (stemming) כדי להוריד מילים לצורתן השורשית.
שלבים הבאים: מעבר לשיטת Bag of Words
אחת המגבלות של מודל Bag of Words היא שהוא מתייחס לכל המילים באופן שווה. למרבה הצער, זה יכול להוביל לבעיות בהן כמה מילים ניתנות יותר חשיבות רק בגלל שהן מופיעות לעיתים קרובות.
TF-IDF (שכיחות מונח-הפוך תדירות תיעוד) היא פתרון לבעיה זו, מכיוון שהיא מאזנת את משקל המילים על פי תדירות הופעתן בכל המסמכים.
TF-IDF: הרחבה של Bag of Words
שכיחות מונח (TF) מייצגת את תדירות הופעת המונח במסמך. הפוך תדירות תיעוד (IDF) מוריד את ההשפעה של מילים המופיעות לעיתים קרובות במסמכים רבים. התוצאה של TF-IDF נחשבת על ידי הכפלה של שתי המטריקות.
לשקול מסמך המכיל 200 מילים, שבו המילה "אהבה" מופיעה 5 פעמים. TF ל"אהבה" היא (5 / 200) = 0.025. נניח שיש לנו מיליון מסמכים והמילה "אהבה" מופיעה באלף מתוכם, IDF (רווח התיעוב ההפוך) נחשב כך: log(1000000 / 1000) = 3. משקל TF-IDF הוא המכפל של שתי המשתנים: 0.025 * 3 = 0.075.
בScikit-learn, זה די קל לחשב זאת באמצעות כלי TfidfVectorizer.
from sklearn.feature_extraction.text import TfidfVectorizer # דוגמה של מאגר corpus = [ "Python is amazing and fun.", "Python is not just fun but also powerful.", "Learning Python is fun!", ] # יצירת וקטוריזר TF-IDF tfidf_vectorizer = TfidfVectorizer() # התאמה ושינוי פורמט המאגר X_tfidf = tfidf_vectorizer.fit_transform(corpus) # הצגת אוצר המילים print("Vocabulary:", tfidf_vectorizer.get_feature_names_out()) # הצגת מטריצת TF-IDF print("TF-IDF Representation:") print(X_tfidf.toarray())
תוצאה:
Vocabulary: ['also' 'amazing' 'and' 'but' 'fun' 'is' 'just' 'learning' 'not' 'powerful' 'python'] TF-IDF Representation: [[0. 0.57292883 0.57292883 0. 0.338381 0.338381 0. 0. 0. 0. 0.338381 ] [0.40667606 0. 0. 0.40667606 0.24018943 0.24018943 0.40667606 0. 0.40667606 0.40667606 0.24018943] [0. 0. 0. 0. 0.41285857 0.41285857 0. 0.69903033 0. 0. 0.41285857]]
מטריצת TF-IDF שמומשה למעלה נותן לך מדד משוקל במקום תדירויות גולמיות.
בעוד שמודל תיק המילים (Bag of Words) יש לו מגבלות, במיוחד לרשתות גדולות ומורכבות יותר, הוא עדיין אבן יסוד חשובה ביותר ביישומי פיתוח שפה טבעית (NLP) רבים. הבנתו יעזור לך כאשר תחקר מודלים מתקדמים יותר כמו מיפוי מילים וטרנספורמרים.
מכאן, אתה יכול להתנסות עם BoW במיזמים שלך, כולל זיהוי ספאם, אנליזת רגשות, קלסטריזציה של מסמכים ועוד.
אם אתה רוצה שיפור נוסף מעבר לתיק המילים, אתה יכול לחקור שיטות כמו וורד2וק וגלוב, או מודלים של למידה עמוקה כמו BERT.
מחשבות סופיות
טכניקת 'תיק המילים' היא טכניקה בסיסית המשמשת בעיבוד שפה טבעית. היא משמשת כדרך פשוטה אך יעילה להמיר טקסט לא מאורגן לתכונות מספריות הניתנות לשימוש על ידי אלגוריתמים של למידה מכונית. במדריך זה, כיסו הנושאים הבאים:
- מהי מודל 'תיק המילים' (BoW)?
- יתרונות של מודל תיק המילים בבניית מודלים של למידה מכונית.
- איך ליישם את מודל תיק המילים בפייתון.
- יתרונות ומגבלות של תיק המילים.
- תיאוריה ומוטיבציה מאחורי מודל תיק המילים.
- הצגת TF-IDF כשיפור על מודל תיק המילים המסורתי.
בדוק את מסלול המיומנויות של עיבוד שפה טבעית בפייתון, כדי ללכת עמוק לתוך עיבוד שפה טבעית.
Source:
https://www.datacamp.com/tutorial/python-bag-of-words-model