spaCy در پایتون – پردازش زبان طبیعی به صورت آسان


پردازش زبان طبیعی (NLP) یکی از حوزههای اصلی هوش مصنوعی محسوب میشود. NLP نقشی اساسی در بسیاری از کاربردهای هوشمند مانند رباتهای گفتگوی خودکار (chatbot) دارد. در این نوشته به بررسی ترجمه چند زبانی و شناسایی نظرات از روی دادهها خواهیم پرداخت. همه شرکتهایی که از NLP برای معنیدار ساختن دادههای متنی ساخت نیافته استفاده میکنند، نه تنها به دنبال افزایش دقت هستند؛ بلکه میخواهند این کسب نتایج، سریع نیز باشد.
پردازش زبان طبیعی یک حوزه وسیع است. برخی از وظایفی که در NLP انجام مییابند، شامل طبقهبندی متن، شناسایی گزارهها، ترجمه ماشینی، پاسخ به سؤالها و شناسایی مفاهیم است. ابزارها و کامپوننتهای مختلفی وجود دارند که در پیادهسازی NLP استفاده میشوند. بسیاری از این کامپوننتها با استفاده از کتابخانه معتبر NLTK (کیت ابزار زبان طبیعی) توصیف شدهاند.
در این نوشته به بررسی یکی از قدرتمندترین و پیشرفتهترین کتابخانههای مورد استفاده برای پیادهسازی NLP به نام spaCy میپردازیم.
1. توضیح و نصب spaCy
1.1. توضیح
spaCy به زبان cython (بسط C از زبان پایتون که برای ارائه عملکردی مشابه C برای برنامههای پایتون طراحی شده) نوشته شده است. از این رو کتابخانه بسیار سریعی است. spaCy یک API فشرده برای دسترسی به روشها و خصوصیات تعیین شده از سوی ماشین آموزشدیده و مدلهای یادگیری (عمیق) ارائه میکند.
2.1. نصب
کامپوننت spaCy و دادهها و مدلهای آن را میتوان به راحتی با استفاده از ایندکس بسته پایتون (pip) و ابزارهای آن نصب کرد. با استفاده از دستور زیر میتوان spaCy را بر روی سیستم نصب کرد:
sudo pip install spacy
اگر از پایتون استفاده میکنید باید به جای pip در دستور بالا از pip3 استفاده کنید. همچنین میتوانید کد منبع آن را از اینجا دانلود کرده و پس از خروج از حالت فشرده با پیروی از دستور زیر نصب کنید:
python setup.py install
برای دانلود همه دادهها و مدلها، دستور زیر را پس از نصب برنامه اجرا کنید:
python -m spacy.en.download all
اینک آماده هستید که spacy را بررسی و استفاده کنید.
2. pipeline و خصوصیات SpaCy
پیادهسازی spacy و دسترسی به خصوصیات مختلف آن از طریق ایجاد pipeline میسر میشود. این pipeline با بارگذاری مدلها ایجاد میشود. انواع مختلفی از مدلها وجود دارند که در بسته گنجانده شدهاند و شامل اطلاعاتی در مورد زبان، لغات، بردارهای آموزشدیده، دستور زبان و گزارهها هستند.
مدل پیشفرض را که english-core-web نام دارد بارگذاری میکنیم:
import spacy nlp = spacy.load(“en”)
شیء NLP برای ایجاد اسناد، دسترسی به حاشیهنویسی (annotation) های زبانی و خصوصیات مختلف NLP استفاده میشود. اینک یک داده متنی را در pipeline خود بارگذاری میکنیم. از نظرات بررسی هتلها که از وبسایت tripadvisor استخراج شده است، استفاده کردهایم. فایل دادهها را میتوانید از این لینک دانلود کنید.
document = unicode(open(filename).read().decode('utf8')) document = nlp(document)
این سند اینک بخشی از کلاس مدل spacy.english است و با چند خصوصیت مرتبط شده است. خصوصیات یک سند (یا توکنهای آن) را میتوان با استفاده از دستور زیر فهرست کرد:
dir(document) >> ['doc', 'ents', … 'mem']
این کد طیف وسیعی از خصوصیات اسناد مانند توکنها، اندیس ارجاع توکنها، تگهای اجزای زبانی، گزارهها، بردارها، احساسها، واژگان و موارد دیگر را در خروجی ارائه میکند. برخی از این خصوصیات را با هم مرور میکنیم.
1.2. توکنسازی
هر سند spaCy به صورت جملههایی توکنسازی شده است. همچنین میتوان این سند را به توکنهایی تقسیم کرد که با تکرار رویهها روی سند به آنها دست یافت:
# نخستین توکن سند document[0] >> Nice # آخرین توکن سند document[len(document)-5] >> boston # فهرست جمله های سند list(document.sents) >> [Nice place Better than some reviews give it credit for., Overall, the rooms were a bit small but nice., ... Everything was clean, the view was wonderful and it is very well located (the Prudential Center makes shopping and eating easy and the T is nearby for jaunts out and about the city).]
2.2. تگ گذاری اجزای زبانی (Part of Speech)
تگهای اجزای زبانی، خصوصیات کلمات هستند که به وسیله استفاده از آن در جمله با دستور زبان صحیح تعریف میشوند. این تگها را میتوان به عنوان ویژگیهای کلمه در زمان فیلتر کردن اطلاعات، مدلهای احتمالاتی و تجزیه بر مبنای قواعد مورد استفاده قرار داد.
همه تگهای اجزای زبانی سند خود را بررسی میکنیم.
# دریافت همه تگها all_tags = {w.pos: w.pos_ for w in document} >> {97: u'SYM', 98: u'VERB', 99: u'X', 101: u'SPACE', 82: u'ADJ', 83: u'ADP', 84: u'ADV', 87: u'CCONJ', 88: u'DET', 89: u'INTJ', 90: u'NOUN', 91: u'NUM', 92: u'PART', 93: u'PRON', 94: u'PROPN', 95: u'PUNCT'} # دریافت همه تگهای اولین جمله سند for word in list(document.sents)[0]: print word, word.tag_ >> (Nice, u'JJ') (place, u'NN') (Better, u'NNP') (than, u'IN') (some, u'DT') (reviews, u'NNS') (give, u'VBP') (it, u'PRP') (creit, u'NN') (for, u'IN') (., u'.')
اینک برخی از یونیگرامهای سند را بررسی میکنیم. یک تابع پردازش اولیه و پاکسازی متنی ایجاد شده است.
#تعریف کردن برخی خصوصیات noisy_pos_tags = [“PROP”] min_token_length = 2 #تابعی برای بررسی این که یک توکن نویز است یا نه؟ def isNoise(token): is_noise = False if token.pos_ in noisy_pos_tags: is_noise = True elif token.is_stop == True: is_noise = True elif len(token.string) <= min_token_length: is_noise = True return is_noise def cleanup(token, lower = True): if lower: token = token.lower() return token.strip() # یونیگرامهای بیشتر استفاده در بررسیها from collections import Counter cleaned_list = [cleanup(word.string) for word in document if not isNoise(word)] Counter(cleaned_list).most_common(5) >> [(u'hotel', 683), (u'room', 652), (u'great', 300), (u'sheraton', 285), (u'location', 271)]

3.2. شناسایی گزارهها
spaCy یک مدل شناسایی سریع گزارهها ارائه کرده است که قابلیت شناسایی عبارتهای گزارهای را در سند دارد. گزارهها میتوانند انواع مختلفی داشته باشند، مانند شخص، مکان، سازمان، تاریخها، اعداد و غیره. به این گزارهها میتوان از طریق خصوصیت «.ents» دسترسی داشت.
همه انواع گزارههای نامگذاری سند کنونیمان را میتوانیم ببینیم.
labels = set([w.label_ for w in document.ents]) for label in labels: entities = [cleanup(e.string, lower=False) for e in document.ents if label==e.label_] entities = list(set(entities)) print label,entities
4.2. تجزیه وابستگی
یکی از قویترین ویژگیهای spaCy تجزیهکننده بسیار سریع و دقیق وابستگی آن است که میتوان از طریق یک API سبک به آن دسترسی یافت. این تجزیهکننده همچنین میتواند برای شناسایی کرانهای جمله و خرد کردن عبارتها استفاده شود. از طریق دستورهای «.children»، «.root» و «ancestor» میتوان به روابط دسترسی داشت.
# استخراج همه جملههای بررسیها که شامل واژه هتل هستند hotel = [sent for sent in document.sents if 'hotel' in sent.string.lower()] # ایجاد درخت وابستگی sentence = hotel[2] for word in sentence: print word, ': ', str(list(word.children)) >> A: [] cab: [A, from] from: [airport, to] the: [] airport: [the] to: [hotel] the: [] hotel: [the] can: [] be: [cab, can, cheaper,.] cheaper: [than] than: [shuttles] the: [] shuttles: [the, depending] depending: [time] what: [] time: [what, of] of: [day] the: [] day: [the, go] you: [] go: [you] .: []
برای مثال همه درختهای وابستگی جملههایی که شامل واژه hotel است را تجزیه میکنیم و توکنهای وصفی استفاده شده برای واژه hotel را بررسی میکنیم. یک تابع سفارشی ایجاد شده است که درخت وابستگی را تجزیه میکند و تگهای اجزای زبانی مرتبط را استخراج میکند.
# بررسی همه صفتهای مورد استفاده برای یک کلمه def pos_words (sentence, token, ptag): sentences = [sent for sent in sentence.sents if token in sent.string] pwrds = [] for sent in sentences: for word in sent: if character in word.string: pwrds.extend([child.string.strip() for child in word.children if child.pos_ == ptag]) return Counter(pwrds).most_common(10) pos_words(document, 'hotel', “ADJ”) >> [(u'other', 20), (u'great', 10), (u'good', 7), (u'better', 6), (u'nice', 6), (u'different', 5), (u'many', 5), (u'best', 4), (u'my', 4), (u'wonderful', 3)]
5.2. عبارتهای اسمی
درخت وابستگی میتواند برای تولید عبارتهای اسمی نیز استفاده شود:
Generate Noun Phrases doc = nlp(u'I love data science on analytics vidhya') for np in doc.noun_chunks: print np.text, np.root.dep_, np.root.head.text >> I nsubj love data science dobj love analytics pobj on

3. یکپارچهسازی کلمه به بردار
spaCy یکپارچهسازی درونی برای استفاده از بردارهای چگال و با ارزش واقعی دارد که اطلاعات مشابهت توزیع یافته را نمایش میدهد. این کامپوننت از بردارهای GloVe برای تولید بردارها استفاده میکند. GloVe یک الگوریتم یادگیری نظارتنشده برای به دست آوردن نمایش برداری کلمات است.
اینک برخی از بردارهای کلمات را ایجاد و بعضی عملیاتهای موردنظر را بر روی آنها اجرا میکنیم.
from numpy import dot from numpy.linalg import norm from spacy.en import English parser = English() #ایجاد بردار کلمهای برای کلمه سیب apple = parser.vocab[u'apple'] #تابع مشابهت عموزاده cosine = lambda v1, v2: dot(v1, v2) / (norm(v1) * norm(v2)) others = list({w for w in parser.vocab if w.has_vector and w.orth_.islower() and w.lower_!= unicode("apple")}) # دستهبندی بر اساس رتبه مشابهت others.sort(key=lambda w: cosine(w.vector, apple.vector)) others.reverse() print "top most similar words to apple:" for word in others[:10]: print word.orth_ >> apples iphone f ruit juice cherry lemon banana pie mac orange
4. یادگیری ماشینی برای متن با استفاده از Spacy
ادغام spaCy در مدل یادگیری ماشینی بسیار آسان و سرراست است.
ابتدا یک طبقهبندی کننده سفارشی متن با استفاده از sklearn میسازیم. یک pipeline از نوع sklearn با استفاده از کامپوننتهای زیر میسازیم:
cleaner, tokenizer, vectorizer, classifier
سپس برای اجزای توکنساز و بردارساز، ماژولهای سفارشی با استفاده از spacy میسازیم.
from sklearn.feature_extraction.stop_words import ENGLISH_STOP_WORDS as stopwords from sklearn.feature_extraction.text import CountVectorizer from sklearn.metrics import accuracy_score from sklearn.base import TransformerMixin from sklearn.pipeline import Pipeline from sklearn.svm import LinearSVC import string punctuations = string.punctuation from spacy.en import English parser = English() #تبدیل سفارشی class predictors(TransformerMixin): def transform(self, X, **transform_params): return [clean_text(text) for text in X] def fit(self, X, y=None, **fit_params): return self def get_params(self, deep=True): return {} # تابع خاص برای پاکسازی نوشته def clean_text(text): return text.strip().lower()
اینک یک تابع توکنساز سفارشی با استفاده از تجزیهکننده spacy و مقداری پاکسازی اولیه ایجاد میکنیم. یک نکته که در این مرحله باید به آن توجه کرد، این است که ویژگیهای متن باید با بردارهای کلمهای جایگزین شوند (به طور خاص در مدلهای یادگیری عمیق مناسب است)
#ایجاد توکنساز که جمله را تجزیه کرده و توکن ایجاد میکند #این توکنها را می توان با بردار نیز جایگزین کرد def spacy_tokenizer(sentence): tokens = parser(sentence) tokens = [tok.lemma_.lower().strip() if tok.lemma_!= "-PRON-" else tok.lower_ for tok in tokens] tokens = [tok for tok in tokens if (tok not in stopwords and tok not in punctuations)] return tokens #ایجاد شی بردارساز برای تولید بردارهای ویژگی، ما از توکنساز سفارشی استفاده کردیم vectorizer = CountVectorizer(tokenizer = spacy_tokenizer, ngram_range=(1,1)) classifier = LinearSVC()
اینک آماده هستیم که pipeline را ایجاد کنیم، دادهها را بارگذاری کنیم و مدل طبقهبندی کننده را اجرا نماییم.
# Create the pipeline to clean, tokenize, vectorize, and classify pipe = Pipeline([("cleaner", predictors()), ('vectorizer', vectorizer), ('classifier', classifier)]) # بارگذاری دادههای نمونه train = [('I love this sandwich.', 'pos'), ('this is an amazing place!', 'pos'), ('I feel very good about these beers.', 'pos'), ('this is my best work.', 'pos'), ("what an awesome view", 'pos'), ('I do not like this restaurant', 'neg'), ('I am tired of this stuff.', 'neg'), ("I can't deal with this", 'neg'), ('he is my sworn enemy!', 'neg'), ('my boss is horrible.', 'neg')] test = [('the beer was good.', 'pos'), ('I do not enjoy my job', 'neg'), ("I ain't feelin dandy today.", 'neg'), ("I feel amazing!", 'pos'), ('Gary is a good friend of mine.', 'pos'), ("I can't believe I'm doing this.", 'neg')] # ایجاد مدل و اندازهگیری دقت pipe.fit([x[0] for x in train], [x[1] for x in train]) pred_data = pipe.predict([x[0] for x in test]) for (sample, pred) in zip(test, pred_data): print sample, pred print "Accuracy:", accuracy_score([x[1] for x in test], pred_data) >> ('the beer was good.', 'pos') pos ('I do not enjoy my job', 'neg') neg ("I ain't feelin dandy today.", 'neg') neg ('I feel amazing!', 'pos') pos ('Gary is a good friend of mine.', 'pos') pos ("I can't believe I'm doing this.", 'neg') neg Accuracy: 1.0
5. مقایسه spaCy با کتابخانههای دیگر
spacy یک بسته قدرتمند و با استحکام عملی برای تقریباً همه وظایف پردازش زبان طبیعی محسوب میشود. در ادامه spacy را با برخی از ابزارهای مشهور برای پیادهسازی NLP به نام CoreNLP و NLTK مقایسه میکنیم.
ویژگیهای مختلف
[table id=2 /]
سرعت: کارکردهای اصلی- توکنساز، تگکننده و تجزیهکننده
[table id=3 /]
دقت: استخراج گزارهها
[table id=4 /]
سخن پایانی
در این نوشته spacy را که یک بسته کامل برای پیادهسازی وظایف NLP در پایتون است، بررسی کردیم. مثالهای مختلف را برای نمایش امکانهای مفید spacy و سرعت و دقت آن معرفی کردیم. در نهایت این بسته را با برخی دیگر از کتابخانههای مشهور NLP مقایسه کردیم.
زمانی که بتوانید مفاهیم مطرح شده در این نوشته را درک کنید، میتوانید مسائل واقعاً چالشبرانگیز بهرهبرداری از دادههای متنی پردازش زبان طبیعی را حل کنید. امیدواریم از این نوشته استفاده کرده باشید. لطفاً هرگونه نظر یا پیشنهادی که دارید، در بخش نظرات در ادامه مطرح کنید تا در حد توان پاسخگوی سؤالهای شما باشیم. اگر این نوشته برای شما مفید بوده است، احتمالاً مطالب زیر نیز مورد توجه شما واقع خواهند شد:
==
با تشکر از مطالب خوبتون . اگر در مورد پردازش زبان فارسی مثلا همین حوزه خبری هم مطلب بذارید عالیه.