کوله‌ی کلمات یا bag of words چیست؟ پیش پردازش متون چطور انجام میشه؟

bag of words چیست

فهرست مطالب

در بخش اول آموزش پردازش طبیعی، مراحل پیش پردازش متون را یاد گرفتیم و با عبارات منظم در پایتون آشنا شدیم. در ادامه آموزش‌ها درباره تبدیل متن به بردار صحبت می‌کنیم و می‌گوییم bag of words چیست.

آشنایی با مفهوم بردارسازی و تبدیل متن به بردار (Text Vectorization)

در حوزه زبان‌شناسی (Linguistics)، سعی شده که قواعد کلی و عام که در مورد تمامی زبان‌ها صدق می‌کند، استخراج شود اما مشکلی که وجود دارد این است که همیشه یک عبارت یا اصطلاح عامیانه و یا حتی یک لهجه مخصوصی وجود دارد که باعث ایجاد حالت استثنا می‌شود.

از طرفی دیگر در حوزه پردازش زبان طبیعی، از یادگیری ماشین برای تجزیه (parse)، تحلیل (analyze)، پیش‌بینی (predict)، دسته‌بندی (classify)، تصحیح (correct)، ترجمه (translate) یا تولید (generate) متن، استفاده می‌شود.

همه این کارها بر اساس متن و داده‌ی متنی انجام می‌شوند اما یک سؤال …

در مدل‌های یادگیری ماشین، از اعداد استفاده می‌‌شود یا حروف؟

قطعاً از اعداد استفاده می‌شود! بنابراین، پیش از انجام هر پروژه‌ای باید داده‌های متنی خود را به عدد تبدیل کنیم. به این فرایند، بردارسازی (Vectorization) گفته می‌شود. زیرا ماشین درکی از کلمه و جملات ندارد و فقط عدد می‌شناسد. تبریک می‌گویم، این مهم‌ترین مطلبی بود که باید یاد می‌گرفتید.

بردارسازی، فرایندی است که در آن مجموعه‌ای از داده‌های متنی (text document) به بردارهای ویژگی عددی (numerical feature vectors) تبدیل می‌‌شود تا بتوان از آن‌ها برای مدل‌سازی الگوریتم‌های یادگیری ماشین استفاده کرد.

به زبان خودمانی‌تر: ماشین و هوش مصنوعی از درک کلمه، جمله، تصویر و ویدئو عاجز هست و باید همه‌ی این موارد به بردار عددی تبدیل شود، زیرا ماشین فقط عدد می‌فهمد.

وقتی یک پیکره متنی (corpus) را vectorize می‌کنیم، هر کلمه یا token آن را به آرایه‌ای از اعداد تبدیل می‌کنیم. این آرایه، در واقع یک نمایش برداری از آن کلمه یا token است یعنی به‌جای یک جمله 5 کلمه‌ای، یک بردار عددی 5تایی خواهیم داشت که هر کلمه به یک عدد تبدیل شده است.

برای آشنایی بیشتر با انواع یادگیری ماشین، آموزش رایگان یادگیری ماشین را در کانال یوتیوب دیتاهاب ببینید.

منظور از corpus چیست؟

پیکره متنی (corpus)، مجموعه‌ای از داده‌های متنی یا documentها است.

یک document، عبارت است از هر متن مجزایی که از نظر اندازه (size)، شکل (format) یا ساختار (structure) متفاوت است و می‌تواند شامل جمله‌ها، پاراگراف‌ها، توییت‌ها، پیامک‌ها، نظرات، بازخوردها، مقالات و کتاب‌ها باشد. پس وقتی روی یک مجموعه‌داده متنی مثل توییت‌های فارسی کار می‌کنید به کل داده‌ها یعنی همه توییت‌ها، corpus گفته و به هر توییت، یک document گفته می‌شود.

در این مقاله، ما با یکی از تکنیک‌های ساده و رایج تبدیل متن به بردار به نام bag of word آشنا شده و آن را در یک پروژه دسته‌بندی متن (text classification) به کار می‌بریم.

تکنیک Bag of Words چیست؟

Bag of Words(BOW)، یک رویکردی ساده اما قدرتمند برای تبدیل متن به بردار عددی است.

همان‌طور که ممکن است از نام آن مشخص باشد، تکنیک bag of words به جایگاه کلمات در متن یا document توجه نمی‌کند (مهم نیست کلمه اول جمله آمده یا آخر آن) و ایده اصلی آن این است که تعداد تکرار کلمات، یعنی تعداد دفعاتی که یک کلمه در هر document استفاده شده است را بشمارد. ممکن است که از نظر شما، این رویکرد خیلی بچه‌گانه و پیش‌پاافتاده به نظر برسد، زیرا بدون درنظرگرفتن ترتیب کلمات، هیچ متنی برای ما انسان‌ها قابل‌فهم نیست. اما همین موضوع، از مزایای تکنیک bag of words است: ساده است، اما جواب می‌دهد!

به زبان خودمانی‌تر: قطعاً توجه به جایگاه هر کلمه در جمله، فاکتور مهم و اثرگذاری است که بهتر است لحاظ شود ولی Bow از این موضوع محروم بوده ولی بااین‌وجود روش به‌دردنخوری نیست و جاهایی برای تبدیل متن به بردار کاربرد دارد.

در جدول زیر سه جمله از آهنگ Surfin’ Bird و تعداد دفعاتی که هر کلمه در هر جمله تکرار شده، نوشته شده است.

چیست bow

استفاده از تکنیک BOW بر روی سه جمله از آهنگ Surfin’ Bird

برای تبدیل متن به بردار باتوجه‌به این جدول، هر کلمه ستونی از اعداد دارد که نشان‌دهنده بردار عددی آن کلمه است که این ستون شامل تعداد تکرارهای آن کلمه در داکیومنت است.

بردار کلمات

هر کلمه بردار عددی خاص خود را دارد.

در این مثال ساده، بردارهای عددی را تنها برای سه جمله محاسبه کردیم اما می‌توانیم همین روش را برای تعداد جملات یا داکیومنت‌های بیشتر و corpusهای مختلف نیز به کار ببریم و به‌راحتی یک متن به بردار عددی تبدیل می‌شود. هر سطر از جدول نشان‌دهنده یک داکیومنت و هر ستون نشان‌دهنده یک توکن است. به ماتریس به‌دست‌آمده، ماتریس document-term گفته می‌شود. در این ماتریس، فراوانی هر توکن در داکیومنت‌های مختلف حساب شده و به‌عنوان ورودی به مدل‌های یادگیری ماشین، داده می‌شود.

ساختن ماتریس Document-Term

حال که فهمیدیم bag of words چیست، کاربرد آن برای پروژه‌های text classification را بررسی می‌کنیم. در چنین پروژه‌هایی، تبدیل متن به بردار انجام شده و هر کلمه و بردار عددی مربوط به آن، به‌عنوان یکی از ویژگی‌ها (features)، برای آموزش مدل classifier استفاده می‌شود.

جملات زیر را در نظر بگیرید. دو جمله اول بخشی از دستور پخت غذا و سه جمله آخر در مورد کامپیوتر هستند:

				
					    Take 2 cups of flour.
    Mix the flour with the eggs.
    Replace your keyboard in 2 minutes.
    Do you prefer Windows or Mac?
    The Mac book pro has such a noisy keyboard.
				
			

برای به‌دست‌آوردن ماتریس document-term می‌توانیم از CountVectorizer که کتابخانه scikit-learn آن را ارائه داده، استفاده کنیم (برای اطلاعات بیشتر به صفحه documentation آن مراجعه کنید):

				
					from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
corpus = [
    '2 cups of flour',
    'replace the flour',
    'replace the keyboard in 2 minutes',
    'do you prefer Windows or Mac',
    'the Mac has the most noisy keyboard',
]
X = vectorizer.fit_transform(corpus)
X.todense()

				
			

به زبان خودمانی‌تر: در فرایند تبدیل متن به بردار، از یک داده متنی با یکسری عملیات به ماتریس ویژگی‌ها رسیدیم، همان دیتافریم دوست‌داشتنی و رایج.

برای به‌دست‌آوردن سایز ماتریس document-term به این صورت عمل می‌کنیم:

تعداد کل واژگان * تعداد documentهای متن

اندازه بردار هر توکن برابر است با تعداد داکیومنت موجود در مجموعه‌داده متنی؛ بنابراین، مجموعه‌داده‌های بزرگ، بردارهای عددی بزرگ دارند و بالعکس، پیکره‌های متنی کوچک نیز بردارهای عددی کوچکی دارند (مانند مثال آهنگ Surfin’ Bird که در جدول بالا نوشته شده، هر بردار آن تنها سه عدد دارد).

به زبان خودمانی‌تر: یکی از بدترین معایب استفاده از Bow برای تبدیل متن به بردار، بزرگ‌شدن ابعاد ماتریس ویژگی‌ها است. در دنیای واقعی هم جملات معمولاً بلند بوده و بردار ویژگی‌ها بزرگ می‌شود و هم تعداد داکیومنت‌ها زیاد است، پس با حجم بزرگی از داده‌ها روبرو هستیم که Ram قوی نیاز دارد.

برای آشنایی کامل و پروژه محور با مفاهیم پردازش زبان طبیعی دوره آموزش پردازش زبان طبیعی مقدماتی را ببینید.

باتوجه‌به کد بالا، ماتریس document-term زیر به دست می‌آید:

document term matrix CountVect

ماتریس Document-Term محاسبه شده با استفاده از CountVectorizer

هر سطر، نمایانگر یکی از جمله‌ها و هر ستون نمایانگر، یکی از کلمه‌های مربوط به پیکره متنی است. به‌عنوان‌مثال، کلمه the در پنج جمله به‌کار رفته: 1 بار در جمله دوم، 1 بار در جمله سوم و 2 بار در جمله پنجم. همچنین کلمه flour در دو جمله به‌کار رفته: 1 بار در جمله اول و 1 بار در جمله دوم. فهرست واژگان (vocabulary) یک متن، تا حد زیادی به جمله‌های آن وابسته است:

به‌عنوان‌مثال، کلمه flour تنها در دو جمله مربوط به دستور پخت، استفاده شده و از طرفی دیگر کلمه the که معنای خاصی ندارد در اکثر جملات به‌کار رفته است (در سه جمله از پنج جمله که با موضوع جملات نیز ارتباطی ندارد).

به زبان خودمانی‌تر: همان‌طور که در شکل قبلی دیدیم، در روش Bow برای تبدیل تبدیل متن به بردار، وقتی ماتریس ویژگی‌ها ساخته می‌شود با صفرهای بی‌خاصیت روبرو می‌شویم. درصد زیادی از مقادیر صفر بوده که هیچ کمکی به درک و حل مسئله ندارند و فضای الکی پر می‌کنند. (کجا را سراغ دارید این‌قدر تجربی و تحلیلی مباحث بیان کنند؟!!)

مدیریت‌کردن ماتریس بزرگ (Large Matrix) در پردازش متن

به مجموعه‌ توکن‌های منحصربه‌فرد که در یک corpus به‌کاررفته، فهرست واژگان (vocabulary) گفته می‌شود که تعداد و اندازه آن به طور مستقیم بر ابعاد ماتریس document-term تأثیر می‌گذارد. یعنی در کل مجموعه‌داده‌ها، چه تعداد کلمه یکتا وجود دارد.

به زبان خودمانی‌تر: مثل وقتی که داخل ظرف آجیل چک کنیم چند نوع مغزه وجود دارد (فارغ از وزن و تعداد مغزه‌ها)، مثلاً در ظرف آجیل فقط پسته، فندق و بادام هست و تعداد واژگان سه می‌شود.

کاهش اندازه vocabulary، برای کم‌کردن پیچیدگی‌های مربوط به محاسبات ماتریس‌های بزرگ مهم است. هرچقدر تعداد واژگان کمتر باشد زمان اجرای مدل‌ها کمتر شده و میزان محاسبات cpu کاهش می‌یابد.

اگرچه حذف کردن ایست‌ واژه‌ (stop words) و ریشه‌یابی (lemmatization) که با کتابخانه spacy انجام می‌شود، باعث کاهش اندازه vocabulary می‌شوند، اما متأسفانه کافی نیستند.

فرض کنید یک corpus که شامل 10000 مقاله است، داریم و پس از lemmatization و حذف ایست‌واژه‌ها، اندازه کل vocabulary آن به 10000 کلمه می‌رسد؛ بنابراین ابعاد ماتریس document-term آن، 10 هزار در 10 هزار خواهد بود. این ابعاد خیلی بزرگ است! استفاده از چنین ماتریسی برای آموزش یک مدل classification هم از لحاظ زمانی (طولانی شدن زمان آموزش) و هم از لحاظ سخت‌افزاری (مصرف حافظه) به‌صرفه نخواهد بود.

بنابراین، کاهش اندازه vocabulary بسیار مهم است. باید تا جایی که ممکن است بدون ازدست‌دادن اطلاعات (information)، کلمه‌های غیر مهم را حذف کنیم. البته این کار کاملاً به متن و محتوای آن وابسته است. یک استراتژی می‌تواند این باشد که کلماتی که در متن بسیار پرکاربرد بوده‌اند یا بسیار کم استفاده شده‌اند را حذف کنیم. یا یک استراتژی دیگر این باشد که از PCA که یک تکنیک کاهش ابعاد (dimension reduction) است، برای کاهش ابعاد ماتریس document-term استفاده کنیم.

به زبان خودمانی‌تر: کاهش ابعاد در عمل و در این مدل مسائل کمک خاصی نمی‌کند چون ذات ماتریس ویژگی صفر هست و ما صرفاً یکسری صفر را فشرده می‌کنیم.

خروجی تکنیک bag of words چیست؟

خروجی Bow در تبدیل متن به بردار، یک ماتریس document-term است که اکثر درایه‌های آن با مقدار صفر پر شده است. به چنین ماتریسی، ماتریس خلوت (sparse matrix) گفته می‌شود. زیرا، بیشتر کلمات فقط در تعداد کم و محدودی از documentها وجود دارند؛ بنابراین به نظر می‌رسد که فضای زیادی را بیهوده هدر می‌دهیم. این‌طور نیست؟

در بخش سوم از مجموعه مقالات آموزشی، درباره word embeddings چیست صحبت می‌کنیم که تکنیک دیگر تبدیل متن به بردار است و در آن پس از بردارسازی، ماتریس document-term، دیگر یک ماتریس خلوت نخواهد بود.

دوست دارید پروژه‌هایی برای پردازش متن یاد بگیرید که در کارهای دنیای واقعی استفاده می‌شوند؟ صفحه آموزش متن کاوی فارسی با شبکه‌های عصبی را ببینید.

ساختن یک مدل Classifier با استفاده از تکنیک Bag of Words

اکنون که با نحوه ساختن ماتریس document-term آشنا شدیم، می‌توانیم از آن در پروژه text classification استفاده کنیم!

حالا مراحل انجام یک پروژه یادگیری ماشین، برای ساختن یک مدل classifier ساده را با هم مرور می‌کنیم:

  1. استخراج ویژگی یا Feature Extraction (به‌دست‌آوردن بردارهای عددی پیکره متنی موردنظر)
  2. برای پیش‌بینی درست‌ مدل بر روی داده‌هایی که تابه‌حال ندیده، دیتاست خود را به دو دیتاست آموزشی (train set) 70% و دیتاست آزمایشی (test set) 30% تقسیم می‌کنیم.
  3. مدل خود را بر روی training set آموزش می‌دهیم. برای این کار، می‌توانیم با استفاده از کتابخانه scikit-learn ، تابع ()fit را فراخوانی کنیم.
  4. در پایان می‌توانیم عملکرد مدل خود را روی test set با استفاده از معیارهایی مانند accuracy، recall، AUC (area under a curve) و یا بررسی confusion matrix، ارزیابی کنیم.

در این مقاله، ما در مورد مرحله اول یعنی Feature Extraction صحبت می‌کنیم. در حوزه NLP، استخراج ویژگی به معنای به‌دست‌آوردن بردارهای عددی یک corpus است. هدفمان این است که یک مدل classifier ساده و مناسب، با شمارش تعداد تکرار کلمات در هر document ایجاد کنیم.

دیتای مورداستفاده ما گلچینی از Brown Corpus است. Brown Corpus اولین مجموعه متون عمومی و الکترونیکی قابل خواندن کامپیوتری (computer-readable) به زبان انگلیسی است که در سال 1961 توسط دانشگاه Brown نوشته شد. متن‌های تشکیل‌دهنده این corpus از 500 منبع جمع‌آوری شده‌ و موضوع آن‌ها بر اساس ژانری که دارند، دسته‌بندی شده‌اند. مانند: اخبار، مقاله، عاشقانه، طنز و …

در ادامه، ما فقط از متن‌های مربوط به دو موضوع طنز و علمی تخیلی استفاده می‌کنیم. می‌توانیم این مجموعه‌داده را در این GitHub Repository پیدا کنیم که شامل دو ستون است: topic و text.

در کانال تلگرام پرشین دیتا، به دیتاست رایگان برای پروژه‌های پردازش زبان طبیعی دسترسی داشته باشید.

Load کردن دیتاست

می‌توانیم دیتاست را به کمک کتابخانه دوست‌داشتنی pandas و در قالب دیتافریم، load کنیم.

				
					import pandas as pd

df = pd.read_csv('brown_corpus_extract_humor_science_fiction.csv')
print(df.shape)
> (2001, 2)

				
			

سپس spaCy را import کرده و یک مدل ساده و مخصوص زبان انگلیسی را load می‌کنیم.

				
					import spacy
nlp = spacy.load("en_core_web_sm")

				
			

پیش‌پردازش داده

پیش‌پردازش داده شامل مراحل مختلفی است که در مقاله‌های قبلی بررسی کردیم:

  • توکن‌سازی (Tokenization)
  • حذف ایست‌واژه‌ها (Removing Stop words)
  • ریشه‌یابی با استفاده از (Lemmatization)

می‌توانیم برای Tokenization و Lemmatization متن‌های مختلف، از کتابخانه spaCy استفاده کنیم. به طور مثال، یک تابع ساده تعریف کنیم که هر متنی را با مدل spaCy پیش‌پردازش کرده و فهرستی از توکن‌های lemmatize شده را برگرداند:

				
					def lemmatize(text):
    doc = nlp(text)
    tokens = [token.lemma_ for token in doc]
    return tokens

				
			

می‌توانیم جمله زیر را به‌عنوان ورودی به تابع بدهیم و خروجی آن را بررسی کنیم:

				
					text = "These are the good times, leave your cares behind."
lemmatize(text)

				
			

به‌این‌ترتیب، لیست زیر بازگردانده می‌شود:

				
					['these', 'be', 'the', 'good', 'time', ',', 'leave', 'your', 'care', 'behind', '.']
				
			

دقت کنید که تا این لحظه، ایست‌واژه‌ها و علائم نگارشی از لیست حذف نشده‌اند! برای حذف ایست‌واژه‌ها می‌توانیم از کتابخانه spaCy استفاده کنیم. این کتابخانه، یک لیست از پیش تعریف شده‌ای که شامل 326 ایست‌واژه است، دارد و با اجرای تابع .is_stop  مشخص می‌کند که آیا کلمه موردنظر، ایست‌واژه است یا خیر (یعنی در این لیست 326تایی وجود دارد یا خیر). اگر در این لیست بود، مقدار true را برمی‌گرداند. البته دقت کنید که ما می‌توانیم این لیست را تغییر دهیم، یعنی ایست‌واژه‌ای دلخواه خود را به آن اضافه کرده و یا از آن کم کنیم.

پس می‌توانیم تابع lemmatize را تغییر دهیم تا توکن‌های زیر را از لیست خروجی آن، حذف کنیم:

  • ایست‌واژه‌ها، با استفاده از is_stop
  • علائم نگارشی، با استفاده از is_punct
				
					def lemmatize(text):
    doc = nlp(text)
    tokens = [token.lemma_ for token in doc if not (token.is_stop or token.is_punct)]
    return tokens

				
			

اگر مجدداً تابع lemmatize را برای جمله

“.These are the good times, leave your cares behind”

فراخوانی کنیم، این لیست خروجی را خواهیم داشت:

				
					['good', 'time', 'leave', 'care']
				
			

به‌این‌ترتیب، نتیجۀ بسیار تمیزتر و درست‎تری به دست آمد!

همان‌طور که می‌بینید خروجی به‌صورت لیستی از توکن‌ها نمایش‌داده‌شده است. اگرچه همیشه می‌توان لیستی از المان‌ها را به‌صورت pandas دیتافریم ذخیره کرد، اما کار با رشته‌ها (Strings) آسان‌تر است.  بنابراین می‌توانیم از یک scikit-learn vectorizer استفاده کنیم که به‌جای کارکردن با لیستی از توکن‌ها، مستقیماً با رشته‌ها یا متن (text) کار کند. به‌این‌ترتیب، تابع lemmatize را برای آخرین بار تغییر می‌دهیم تا همه توکن‌های خروجی را به‌صورت یک‌رشته که با space از هم جدا شده‌اند، بازگرداند:

				
					def lemmatize(text):
    doc = nlp(text)
    tokens = [token.lemma_ for token in doc if not (token.is_stop or token.is_punct)]
    return ' '.join(tokens)

				
			

اگر تابع جدید lemmatize را برای جمله

“.These are the good times, leave your cares behind”

فراخوانی کنیم، خروجی آن به‌صورت یک string خواهد بود:

				
					'good time leave care'
				
			

یک نکته ساده ولی مهم دیگر: متن Brown Corpus شامل یک سری علائم نگارشی مخصوص مانند (` , و ``) است که باید حذف شوند. می‌توانیم هر یک از این علائم را به‌عنوان کاراکتر به لیست ایست‌واژه‌های خود اضافه کنیم:

				
					import spacy
nlp = spacy.load("en_core_web_sm")

nlp.Defaults.stop_words.add("`,")
nlp.Defaults.stop_words.add("``")

				
			

می‌توانیم کد lemmatize را مجدداً اجرا کنیم تا تغییرات ایجاد شده روی کل داده‌ها اعمال شود:

				
					df['processed_text'] = df.text.apply(lambda txt : lemmatize(txt))
				
			

تا اینجای کار، 1053 متن با موضوع طنز و 948 متن با موضوع علمی تخیلی داریم. می‌توانیم چند مرحله اضافی دیگری نیز داشته باشیم. در این Jupyter Notebook می‌توانید این مراحل را بررسی کنید. در نهایت بعد از همه این مراحل، 738 متن طنز و 520 متن علمی تخیلی خواهیم داشت.

بردارسازی داده

اکنون که متن ما tokenized و lemmatized شده و ایست‌واژه‌های آن نیز حذف شده است، مرحله پیش‌پردازش داده به پایان رسیده و نوبت Vectorize کردن داده و تبدیل متن به بردار است!

برای تبدیل متن به بردار عددی کلمات، می‌توانیم از متدهای scikit’s vectorizer استفاده کنیم. کتابخانه Scikit-learn، سه نوع vectorizer دارد:Count  ، tf-idf و hash.

CountVectorizer تعداد تکرار کلمات در هر document را می‌شمارد که این کار را می‌تواند تنها با سه خط کد پایتون زیر انجام دهد:

				
					from sklearn.feature_extraction.text import CountVectorizer
cv = CountVectorizer()
X = cv.fit_transform(df.processed_text)

				
			

X ماتریسی با 1258 سطر و 4749 ستون است. اندازه ستون‌ها برابر با اندازه vocabulary متن است. می‌توانیم از پارامترهای vectorizer مانند max_df و min_df استفاده کنیم تا کلماتی که در متن بسیار پرکاربرد بوده‌اند یا بسیار کم استفاده شده‌اند را شناسایی کنیم.

به زبان خودمانی‌تر: همه‌جا عدالت لزوماً کارساز نیست اینکه در تبدیل متن به بردار بین کلمات تفاوت قائل نشویم و به همه به یک اندازه بها بدهیم، کار درستی نیست. مثلاً بعضی از کلمات به‌شدت پرتکرار بوده و همه‌جا هستند، مثل ایست‌واژه‌ها که بهتر است به آن بها داده نشود و حتی حذف شوند.

به کمک max_df کلماتی که تعداد تکرار زیادی دارند را فیلتر می‌کنیم و یک آستانه تعریف می‌کنیم، یعنی هر کلمه‌ای تعداد تکرار بیشتر از این آستانه داشته باشد فیلتر خواهد شد (همین داستان برای کلمات کم تکرار هم صدق می‌کند و کلمه‌ای که خیلی کم تکرار شده باید فیلتر شود چون احتمالاً غلط املایی بوده است).

ولی اگر بخواهیم به هر کلمه به‌تناسب ارزش آن، بها بدهیم از عهده Bow خارج است و باید به سراغ جلسهٔ بعد (مقاله TF-IDF چیست) برویم و از روش وزن‌دهی (ارزش‌دهی) Tf-idf استفاده کنیم.

آخرین مرحله قبل از train کردن مدل این است که ستون topic دیتافریم را به عدد تبدیل کنیم تا آن را به‌صورت class numbers داشته باشیم. می‌توانیم قرارداد کنیم که عدد 0 را برای موضوع طنز و عدد 1 را برای موضوع علمی تخیلی اختصاص دهیم:

				
					# transform the topic from string to integer
df.loc[df.topic == 'humor', 'topic' ] = 0
df.loc[df.topic == 'science_fiction', 'topic' ] = 1

# define the target variable
y = df.topic

				
			

معمولاً مدل‌های Naive Bayes classifiers برای پروژه‌های text classification به‌خوبی عمل می‌کنند؛ بنابراین از کتابخانه scikit-learn استفاده کرده‌ایم تا یک مدل MultinomialNB بسازیم:

				
					from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import accuracy_score

# 1. Declare the model
clf = MultinomialNB()

# 2. Train the model
Y = y.astype('int')
clf.fit(X, y)

# 3. Make predictions 
yhat = clf.predict(X)

# 4. score
print("Accuracy: ",accuracy_score(y, yhat))

				
			

اگر مدل را ارزیابی کنیم، می‌بینیم که بسیار خوب عمل کرده است زیرا accuracy بالایی دارد:

				
					Accuracy:  0.9390304847576212
				
			

بنابراین، 93% از متن‌ها به‌درستی بین دو موضوع طنز و عملی تخیلی classify شده‌اند.

این نتیجه، می‌تواند نتیجه بسیار خوبی باشد! اما یک نکته‌ای اینجا رعایت نشده، مدل ما بر اساس کل دیتا، train شده است. در این Jupyter Notebook دیتا به دو قسمت train و test تقسیم شده و با ارزیابی مدل بر روی دیتای دیده نشده (unseen data) دقت 74% به‌دست‌آمده است.

توجه: تمامی کدهای داخل مقاله، مجدداً توسط ما اجرا شده (برای مطمئن شدن از بدون خطا بودن کدها) و گاهی نتایج ما با نتایج نویسنده اصلی متفاوت است.

  • بردارسازی (Vectorization)، فرایندی است که در آن مجموعه‌ای از داده‌های متنی به بردارهای ویژگی عددی تبدیل می‌‌شود تا بتوان از آن‌ها برای مدل‌سازی الگوریتم‌های یادگیری ماشین استفاده کرد.
  • Bag of Words (BOW یک رویکردی ساده اما قدرتمند برای تبدیل متن به بردار عددی است. همان‌طور که ممکن است از نام آن مشخص باشد، تکنیک bag of words به نقش کلمات و جایگاه آن در متن یا document توجه نمی‌کند.
  • معمولاً از روش bag-of-words، برای پروژه‌های text classification استفاده می‌کنیم.
  • از ماتریس document-term به‌عنوان ورودی مدل‌های یادگیری ماشین استفاده می‌شود.
  • می‌توانیم از کتابخانه spaCy برای پیش‌پردازش داده‌های متنی استفاده کنیم و مراحل مختلف و مهم پیش‌پردازش داده را با نوشتن تابع‌های کوتاه و ساده جلو ببریم.

در این مقاله فهمیدیم کوله‌ی کلمات bag of words چیست. در مقاله بعدی، با یکی دیگر از تکنیک‌های متداول تبدیل متن به بردار به نام tf-idf که مخفف عبارت term frequency-inverse document frequency است، آشنا می‌شویم و یاد می‌گیریم TF-IDF چیست. البته که این تکنیک، بخشی از همان تکنیک bag of words است اما قدرت و کارایی بیشتری دارد!

مطالب بیشتر

دیدگاهتان را بنویسید