تشخیص موجودیت های اسمی یا نامدار (NER) | مثال پردازش متن با Spacy

تشخیص موجودیت های اسمی

فهرست مطالب

آشنایی بیشتر با کتابخانه SpaCy

در مقاله های قبلی، قابلیت هایی از کتابخانه spaCy مانند lemmatization و word embeddings بررسی کردیم. اما توانایی های spaCy به همین جا ختم نمی شود! در ادامه دو مورد از مهم‌ترین قابلیت‌هایی که قطعا روزی به کارتان می‌آیند،یعنی تشخیص نقش دستوری کلمات (POS) و تشخیص موجودیت های اسمی (NER) را بررسی می‌کنیم.

تشخیص نقش دستوری کلمات (Part Of Speech (POS) Tagging)

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

				
					If you don’t know where you are going any road can take you there.
				
			

و کد زیر را برای آن اجرا ‌کنیم:

				
					import spacy
nlp = spacy.load("en_core_web_sm")
doc = nlp("If you don’t know where you are going any road can take you there.")

for token in doc:
    print(f"{token.text}\t {token.pos_} ")

				
			

خروجی آن به این صورت خواهد بود:

				
					If     SCONJ
you    PRON
do     AUX
n’t    PART
know   VERB
where  ADV
you    PRON
are    AUX
going  VERB
any    DET
road   NOUN
can    VERB
take   VERB
you    PRON
there  ADV
.      PUNCT
				
			

این خروجی شامل کلماتی با نقش‌های زیر است:

verb یا فعل:  know،  going، take

noun یا اسم: road

pronoun یا ضمیر: you

punctuation sign یا علامت نگارشی: .

adverb یا قید: there

auxiliary verb یا فعل کمکی: do، are ، can

determiner یا معرف اسم: any

conditional term یا عبارت شرطی: If

لیست تگ‌های POS به صورت بالقوه به خود کتابخانه و نوع tagging مورد استفاده، بستگی دارد. معمولا علاوه بر 9 نقش دستوری و اصلی که در مدرسه یاد می‌گیریم (noun، verb، article (حرف تعریف)، adjective (صفت)، preposition (حرف اضافه)، pronoun، adverb، conjunction (حرف ربط)، interjection (حرف ندا))، نقش‌های بیشتری نیز داریم.
به عنوان مثال، spaCy برای تشخیص نقش دستوری کلمات از فریمورک Universal Dependencies یا همان UD استفاده می‌کند که شامل 14 نقش دستوری است. NLTK نیز با انواع مختلفی از tagging و برچسب‌گذاری‌ها کار می‌کند.

اما یکی از پیچیدگی‌هایی که ممکن است داشته باشیم این است که کلمات polymorphism باشند، یعنی کلمات دارای ظاهری یکسان اما با چند معنای متفاوت باشند. به‌این‌ترتیب نقش‌های مختلفی نیز خواهند داشت.

به این نقل‌قول از شکسپیر توجه کنید:

				
					Grace me no grace, nor uncle me no uncle
				
			

کلمه grace و uncle، هرکدام دومرتبه به کار رفته‌اند که بار اول، نقش دستوری فعل و بار دوم، نقش دستوری اسم را دارند. خوشبختانه spaCy می‌تواند این نقش‌ها را به‌درستی و بدون هیچ مشکلی تشخیص دهد:

				
					doc = nlp("Grace me no grace, nor uncle me no uncle")
for t in doc: print(t, t.pos_)

				
			

که خروجی آن، به این صورت است:

				
					Grace VERB
...
grace NOUN
...
uncle VERB
...
uncle NOUN

				
			

اما اگر از NLTK (NLTK universal tagger) استفاده کنیم، خروجی نادرست و غلطی می‌گیریم:

				
					import nltk
nltk.download('universal_tagset')
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')

text = nltk.word_tokenize("Grace me no grace, nor uncle me no uncle")
nltk.pos_tag(text, tagset='universal')

> [('Grace', 'NOUN'), ..., ('grace', 'NOUN'), ..., ('uncle', 'ADP'), ..., ('uncle', 'NOUN')]
# ADP here is an Adposition (it's complicated)

				
			

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

کاربرد Part Of Speech (POS) Tagging

می‌توانیم از Part-of-speech tagging برای تسک‌ها و پروژه‌های مختلفی استفاده کنیم. پروژه‌هایی مانند:

  • تحلیل عواطف (sentiment analysis)
  • تشخیص موجودیت های اسمی
  • ابهام‌زدایی کلمات دارای چند معنی (word-sense disambiguation)

وظیفه Word-sense disambiguation، تشخیص درست معنای کلماتی است که دارای ظاهر و املایی یکسان هستند. معنای این کلمات، باتوجه‌به context و کاربردی که در جمله دارند، مشخص می‌شود. به‌عنوان‌مثال، کلمه bass هم می‌تواند معنی fish (ماهی) داشته باشد و هم اینکه به‌عنوان ساز موسیقی، به کار رود. هر دوی آن‌ها را می‌توانید در جملات زیر ببینید:

  • fish: I went fishing for some sea bass
  • musical instrument: The bass line in that song grooves

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

اینجاست که Named Entity Recognition یا تشخیص موجودیت های نامدار به کار ما می‌آید.

تشخیص موجودیت های اسمی (Named Entity Recognition)

NER چیست و چکار می‌کند؟ وظیفۀ تشخیص موجودیت های اسمی شناسایی اشیا دنیای واقعی و دسته‌بندی یا classify کردن آن‌ها به یک سری دسته‌های از پیش تعریف شده است.

برای تشخیص موجودیت های اسمی مدل‌های NER کتابخانه spaCy می‌تواند اسامی و عبارات مربوط به این categories و دسته‌بندی‌ها را شناسایی کند:

  • PERSON: افراد، موجودات واقعی و خیالی
  • LOC :locations یا موقعیت‌های مکانی
  • ORG : organizations یا سازمان‌هایی مانند شرکت‌ها، آژانس‌ها و مؤسسات
  • GPE: کشورها، استان‌ها و شهرها
  • تاریخ و زمان
  • Percentages: درصدها
  • پول، رویدادها، آثار هنری و زبان‌ها

لیست جامع مدل‌های تشخیص موجودیت های اسمی را می‌توانید در این لینک ببینید.

علاوه بر این مدل‌ها، اگر داده کافی داشته باشیم، می‌توانیم مدل‌های تشخیص موجودیت های اسمی را برای شناسایی انواع موجودیت (entity) و اطلاعات خاص مانند پروتئین‌ها، حیوانات و ... آموزش دهیم.

هرگاه که یک مدل را (با دستور doc = nlp(text)) بر روی یک متن به کار ببریم، spaCy مدل NER را که پیش‌ از این (با دستور nlp = spacy.load(model))، load شده است، به کار می‌برد تا تمام entityهای موجود در متن را پیدا کند. برای دسترسی به این اطلاعات می‌توانیم از doc.ents استفاده کنیم.

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

کاربرد Named Entity Recognition

برای مثال می‌توانیم از مدل تشخیص موجودیت های اسمی برای پیداکردن پرکاربردترین شخصیت‌های آلیس در سرزمین عجایب استفاده کنیم. اگر داستان آن را بدانید، انتظار دارید که Alice (آلیس)، Queen (ملکه) و البته Rabbit (خرگوش) بیشترین کاربرد را داشته باشند. این‌طور نیست؟

برای پاسخ به این سؤال، ابتدا از Project Gutenberg متن آن را به طور مستقیم load می‌کنیم و خروجی 12 کلمۀ پرکاربرد را به ترتیب تکرارشان می‌بینیم:

				
					import requests
import spacy
from collections import Counter

nlp = spacy.load("en_core_web_sm")
r = requests.get('http://www.gutenberg.org/files/11/11-0.txt')
doc = nlp(r.text.split("*** END")[0])
# collect all the entities that are tagged PERSON
persons = [ent.text for ent in doc.ents if ent.label_ == 'PERSON']
# and list the 12 most common ones
Counter(persons).most_common(12)

				
			

خروجی 12 کلمه پرکاربرد:

				
					[('Alice', 311),
 ('Gryphon', 52),
 ('Queen', 43),
 ('Duchess', 27),
 ('Hatter', 17),
 ('the Mock Turtle', 16),
 ('Cat', 15),
 ('Mouse', 13),
 ('Dinah', 10),
 ('Bill', 8),
 ('Majesty', 8),
 ('Rabbit', 7)]

				
			

باوجودآنکه می‌دانیم Rabbit یکی از شخصیت‌های اصلی کتاب است، اما تنها 7 بار به‌عنوان person شناسایی شده است. آیا این احتمال وجود دارد که spaCy، شخصیت Rabbit را به‌عنوان entity دیگری شناسایی کرده باشد؟ این حدس را هم می‌توانیم با استفاده از کد، چک کنیم:

				
					rabbit_ner = [(ent.text, ent.label_) for ent in doc.ents if "Rabbit" in ent.text]
Counter(rabbit_ner).most_common(10)

				
			

لیست خروجی:

				
					[(('the White Rabbit', 'ORG'), 11),
 (('Rabbit', 'PERSON'), 7),
 (('Rabbit', 'PRODUCT'), 3),
 (('White Rabbit', 'ORG'), 3),
 (('The Rabbit Sends', 'PRODUCT'), 1),
 (('Rabbit', 'EVENT'), 1),
 (('Rabbit', 'FAC'), 1),
 (('Rabbit', 'ORG'), 1),
 (('the White\r\nRabbit', 'ORG'), 1),
 (('The White Rabbit', 'ORG'), 1)]


				
			

نتایجی بر خلاف انتظاراتمان به‌دست‌آمده!

همان‌طور که مشخص است، spaCy انواع مختلفی از Rabbit را شناسایی کرده است. (یعنی به‌جای کلمه Rabbit، عبارت White Rabbit را به‌عنوان یک کلمه منحصربه‌فرد و unique در نظر گرفته است). البته ناگفته نماند که چندین مورد از Rabbitها را نیز اشتباهی تشخیص داده و آن‌ها را به‌عنوان محصول (Product)، ORG ،FAC (ساختمان) و حتی EVENT (رویداد) دسته‌بندی کرده است.

این مثال نشان می‌دهد که حتی در یک متن کلاسیک، با قالب‌بندی خوب و تمیز نیز، spaCy برای شناسایی درست entityهای ساده، چالش‌ها و مشکلاتی دارد. عمدۀ این چالش‌ها از همان ابتدا، به دلیل ماهیت، تنوع و حجم کم داده‌های مورداستفاده برای آموزش مدل، به وجود می‌آیند. مدل کوچک و کم‌حجم en_core_web_sm (یا حجم 11 مگابایت) که برای تجزیه متن آلیس در سرزمین عجایب و تشخیص موجودیت های نامدار load کردیم، بر اساس OntoNotes، آموزش‌داده‌شده که شامل Corpus (پیکرۀ متنی) تشکیل شده از 1745 هزار متن انگلیسی مبتنی بر وب، بوده است. شاید دقیقاً به دلیل همین حجم کم دیتای آموزشی، نتوانست Rabbit را به‌درستی شناسایی کند! مدل جامع‌تر و بزرگ‌تر en_core_web_lg (با حجم 782 مگابایت) بر اساس OntoNotes و زیرمجموعه‌ای از داده‌های بسیار خوب Common Crawl آموزش‌ داده‌ شده است. انتظار داریم که با استفاده از این مدل بزرگ‌تر، نتایج بهتری را برای تشخیص موجودیت های اسمی داشته باشیم!

سایت‌ها داده‌های زیادی دارند که می‌توانید با وب اسکرپینگ آن‌ها را استخراج کرده و دیتاست خود را بسازید. دوره آموزش پروژه محور وب اسکرپینگ را در کانال یوتیوب دیتاهاب ببینید.

  • Part-of-speech tagging (POS) تسکی است که شامل تشخیص نقش دستوری در جمله است: مانند noun، verb و adjective.
  • وظیفۀ Named-entity recognition (NER)، شناسایی افراد، مکان‌ها و سازمان‌های به‌کاررفته در یک متن است.
  • برای پیاده‌سازی POS و NER می‌توانیم مستقیماً از spaCy استفاده کنیم.
  • POS یکی از بخش‌های اصلی پیاده‌سازی پروژه‌های NLP مانند sentiment analysis ، named-entity recognition و word sense disambiguation است.
  • همان‌طور که در متن آلیس در سرزمین عجایب دیدیم، NER به‌سادگی POS نیست و برای شناسایی درست entityها باید پیش‌پردازش بیشتر و اضافی‌تری داشته باشیم.

بسیار خب! این هم از آخرین مقاله. دیگر این واقعاً آخرین مقاله بود!

امیدواریم که باقدرت در مسیر یادگیری NLP ادامه دهید و در تمامی مراحل موفق باشید.

مطالب بیشتر

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