Doğal Dil İşleme (NLP) - Model Eğitim İşlemleri
Yelp Veri Seti Eğitimi
ABD'de bulunan Yelp şirketi üzerinden yapılan restorant yorumlarını içeren ve yorum karşılığında kullanıcıların vermiş olduğu yıldızları içeren "yelp.csv" veri seti kullanılacaktır.
Amaç: Yeni bir yorum yapıldığında verilecek yıldız değerinin kaç olacağını tahmin eden bir NLP projesi oluşturmak.
Örnek proje üzerinde çalışmaya başlamadan önce NLP projelerinde kullanacağımız çalışma sıralamasını listeleyelim.
- Veri setine Keşifsel Veri Analizi (EDA) yapılır.
- Bütün cümleler küçük harfe çevirilir.
- Noktalama işaretleri kaldırılır.
- Sayısal işaretler kaldırılır.
- Fazla boşluklar kaldırılır.
- Stop words (gereksiz kelimeler) kaldırılır.
- Tokenize işlemi yapılarak sonrasında Lemma veya stemma (ekleri kaldırıp kökleri bulma) işlemi uygulanır.
- Verilerde en çok kullanılan kelimeleri görselleştirme işlemi.
- Metinsel verilere vektörleştirme işlemi uygulanır.
- Makine öğrenmesi kullanılarak model eğitme ve kaydetme işlemi yapılır.
#Gerekli kütüphaneler içe aktarılır.
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from xgboost import XGBClassifier
from sklearn.metrics import accuracy_score,precision_score,recall_score,f1_score
from sklearn.metrics import confusion_matrix,classification_report
from nltk.tokenize import word_tokenize
from langdetect import detect
from nltk.corpus import stopwords
import stylecloud as sc
from IPython.display import Image
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from nltk.stem import SnowballStemmer,WordNetLemmatizer
#Veri seti okunur
df=pd.read_csv("yelp.csv")
Keşifsel Veri Analizi (EDA)
#Veri seti üzerinden "stars" ve "text" sütünları kullanılacağından "df" değerini bu 2 sütuna indirelim.
df=df[["stars","text"]]
#İlk 5 satır değerleri
df.head()
Çıktı:
#Son 5 satır değerleri
df.tail()
Çıktı:
#Veri seti hakkında genel bilgilendirme
df.info()
Çıktı:
<class 'pandas.core.frame.DataFrame'> RangeIndex: 10000 entries, 0 to 9999 Data columns (total 2 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 stars 10000 non-null int64 1 text 10000 non-null object dtypes: int64(1), object(1) memory usage: 156.4+ KB
#Veri setinde boş değer kontrolü
df.isnull().sum()
Çıktı:
stars 0 text 0 dtype: int64
#Stars değerlerinin dağılım grafiği
sns.countplot(df.stars)
Çıktı:
#Yıldız değerlerinden 1(çok kötü yorum) ve 5(çok iyi yorum) değerleri ile çalışalım.
df=df[(df["stars"]==1) | (df["stars"]==5)]
NLP İşlemleri
#Bütün cümleler küçük harfe çevirilir.
df["text"]=df["text"].str.lower()
#Noktalama işaretleri kaldırılır.
df["text"]=df["text"].str.replace("[^\w\s]","")
#Sayısal işaretler kaldırılır.
df["text"]=df["text"].str.replace("\d+","")
#Fazla boşluklar kaldırılır.
df["text"]=df["text"].str.replace("\n","").replace("\r","")
#"text" sütunundaki verilerin hangi dilde oldukları bulunur.
df["lang"]=df["text"].apply(detect)
#Yeni oluşturulan lang sütunu(text içinde hangi dillerin olduğu) veri dağılımı.
df["lang"].value_counts()
Çıktı:
en 4056 nl 5 af 4 fr 3 ca 3 da 3 sl 2 no 2 it 2 so 2 ro 2 cy 1 tr 1 Name: lang, dtype: int64
#Farklı dillerde olan "text" değerlerini veri setinden kaldıralım
df=df[df["lang"]=="en"].reset_index(drop=True)
#Son durumda sadece ingilizce cümleler kalmış oldu.
#"lang" sütunu ile işimiz kalmadığından onu da kaldırabiliriz.
del df["lang"]
#Stop words (gereksiz kelimeler) ingilizce kelimeler kaldırılır.
stopwords_list=stopwords.words("english")
df['text']=df['text'].apply(lambda x:" ".join([i for i in word_tokenize(x) if i not in stopwords_list]))
#Tokenize işlemi yapılarak sonrasında Lemma veya stemma (ekleri kaldırıp kökleri bulma) işlemi uygulanır.
#Kesin sonuç almak için ve veri seti çok büyük olmadığından Lemmatizer uygulanabilir.
WNL=WordNetLemmatizer()
df['text']=df['text'].apply(lambda x:" ".join([WNL.lemmatize(x) for x in word_tokenize(x)]))
En çok Geçen Kelimeler Görseli Oluşturma
#Tüm yorumlar tek bir string ifadede toplanır
all_bad_comments=""
all_good_comments=""
#1 yıldızlı yorumlar
for i in df[df["stars"]==1]["text"]:
all_bad_comments+=i
#5 yıldızlı yorumlar
for i in df[df["stars"]==5]["text"]:
all_good_comments+=i
#Kötü yorumlarda en çok geçen ilk 1000 kelime
sc.gen_stylecloud(
text=all_bad_comments,
size=500,
max_words=1000,
icon_name="fas fa-heart-broken",
output_name="bad_comments.png",
)
Image(filename="bad_comments.png")
Çıktı:
#Güzel yorumlarda en çok geçen ilk 1000 kelime
sc.gen_stylecloud(
text=all_good_comments,
size=500,
max_words=1000,
icon_name="fas fa-heart",
output_name="all_good_comments.png",
)
Image(filename="all_good_comments.png")
Çıktı:
Model Hazırlık ve Eğitme İşlemi
#Metinsel verilere vektörleştirme işlemi uygulanır.
x=df["text"]
y=df["stars"]
#train ve test verileri ayrılır.
x_train,x_test,y_train,y_test=train_test_split(x,y,random_state=13,test_size=.2)
#CountVectorizer tanımlanır.
vect=CountVectorizer()
#x_train ve x_test verilerine vektörel dönüşüm uygulayalım
x_train_dtm=vect.fit_transform(x_train)
#x_test_dtm verilerindeki sütun sayısı x_train_dtm ile aynı olması için fit_transfor değil transform kullanılır.
x_test_dtm=vect.transform(x_test)
#Boyutlarını inceleyelim
x_train_dtm.shape,x_test_dtm.shape
Çıktı:
((3244, 19709), (812, 19709))
#x_train_dtm tablo halinde görüntüleme
pd.DataFrame(data=x_train_dtm.toarray(),columns=vect.get_feature_names()).sample(5)
Çıktı:
#x_test_dtm tablo halinde görüntüleme
pd.DataFrame(data=x_test_dtm.toarray(),columns=vect.get_feature_names()).sample(5)
Çıktı:
#MultinomialNB ataması yapılır
M=MultinomialNB()
#Model Öğrenme işlemi yapılır
M.fit(x_train_dtm,y_train)
#Model test etme işlemi yapılır.
predict_M=M.predict(x_test_dtm)
#confusion_matrix incelemesi
confusion_matrix(y_test,predict_M)
Çıktı:
array([[ 91, 61], [ 7, 653]], dtype=int64)
#Sınıflandırma raporu
print(classification_report(y_test,predict_M))
Çıktı:
precision recall f1-score support 1 0.93 0.60 0.73 152 5 0.91 0.99 0.95 660 accuracy 0.92 812 macro avg 0.92 0.79 0.84 812 weighted avg 0.92 0.92 0.91 812
Sınıflandırma raporunda da görüldüğü gibi MultinominalNB sınıflandırma algoritması ile kişinin girdiği yoruma karşılık 1 yıldız mı 5 yıldız mı değer vereceği konusununda doğru tahmin etme yüzdesi accuracy değeri göz önüne alınırsa %92 olarak tahmin edilmiş oldu.
Aynı verisetine farklı bir algoritma olan XGBClassifier ile tekrar modelleme işlemi yaparak doğruluk değerini gözlemleyelim.
#XGBClassifier ataması yapılır
XGBC=XGBClassifier()
#Model Öğrenme işlemi yapılır
XGBC.fit(x_train_dtm,y_train)
#Model test etme işlemi yapılır.
predict_XGBC=XGBC.predict(x_test_dtm)
#confusion_matrix incelemesi
confusion_matrix(y_test,predict_XGBC)
Çıktı:
array([[102, 50], [ 13, 647]], dtype=int64)
#Sınıflandırma raporu
print(classification_report(y_test,predict_XGBC))
Çıktı:
precision recall f1-score support 1 0.89 0.67 0.76 152 5 0.93 0.98 0.95 660 accuracy 0.92 812 macro avg 0.91 0.83 0.86 812 weighted avg 0.92 0.92 0.92 812
Sınıflandırma raporunda da görüldüğü gibi XGBClassifier sınıflandırma algoritması ile kişinin girdiği yoruma karşılık 1 yıldız mı 5 yıldız mı değer vereceği konusununda doğru tahmin etme yüzdesi accuracy değeri göz önüne alınırsa %92 olarak tahmin edilmiş oldu. Farklı sınıflandırma algoritmaları girilerek doğruluk yüzdesi artırılabilir.
Modeli Kaydetme ve Kullanma İşlemi
import pickle
#MultinomialNB modeli kaydedildi
pickle.dump(M, open('Yelp.pkl', 'wb'))
#CountVectorizer sonucunda oluşan sütun sayısını korumak için kelimelerinde kaydedilmesi gerekir.
vocab = vect.vocabulary_
pickle.dump(vocab, open('Vocab.pkl', 'wb'))
#Kaydedilen model okundu.
loaded_model=pickle.load(open(r"Yelp.pkl","rb"))
#Kaydedilen kelimeler okundu
loaded_vocab=pickle.load(open("Vocab.pkl","rb"))
def comment_prediction(comment):
import re
import googletrans
#yorum dili ingilizce haricinde bir dilse ingilizceye çevir
lang=detect(comment)
if lang!="en":
comment=googletrans.Translator().translate(comment).text
#yorum küçük harfe dönüştürüldü
comment=comment.lower()
#yorum noktalama işaretleri kaldırıldı
comment=re.sub("[^\w\s]","",comment)
#yorum sayısal ifadeler kaldırıldı
comment=re.sub("\d","",comment)
#yorum fazla boşluklar kaldırıldı
comment=comment.replace("\n","").replace("\r","")
#stopword listesi oluşturuldu ve yorumdan kaldırıldı
stopwords_list=stopwords.words("english")
comment=" ".join([i for i in word_tokenize(comment) if i not in stopwords_list])
#yoruma lemmatize yapıldı
comment=" ".join([WNL.lemmatize(x) for x in word_tokenize(comment)])
#yoruma modele uygun vektörleştirme işlemi uygulandı
vect_predict=CountVectorizer(vocabulary=loaded_vocab)
comment_transform=vect_predict.fit_transform([comment])
#tahmin sonucu
predicted=loaded_model.predict(comment_transform)
return "Yorumunuz {} yıldız olarak tahmin edildi.".format(predicted[0])
#Olumsuz bir yorum oluşturuldu.
comment1="It was a very bad purchase, the shipping was terrible."
comment_prediction(comment1)
Çıktı:
'Yorumunuz 1 yıldız olarak tahmin edildi.'
#Olumlu bir yorum oluşturuldu.
comment2="It was a great purchase, I will definitely buy again."
comment_prediction(comment2)
Çıktı:
'Yorumunuz 5 yıldız olarak tahmin edildi.'
#Türkçe olumsuz bir yorum oluşuturuldu
comment3="Çok berbattı, yemek çok soğuktu"
comment_prediction(comment3)
Çıktı:
'Yorumunuz 1 yıldız olarak tahmin edildi.'
#Arapça olumlu bir yorum oluşuturuldu
comment4="أنا بالتأكيد سيشتري ثانية."
comment_prediction(comment4)
Çıktı:
'Yorumunuz 5 yıldız olarak tahmin edildi.'