Doğal Dil İşleme (NLP) - Model Eğitim İşlemleri

Yelp Veri Seti Eğitimi

Yayın tarihi :09-Şub-22
Bölüm kodlarını ve/veya veri setlerini indir.

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.

#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.'
Paylaş:

Yorum Yap (*Yorumunuza kod eklemek isterseniz Kod Parçacığı Ekle butonuna tıklayarak ekleyebilirsiniz.)

Yorumlar

Henüz hiç yorum yapılmamış, ilk yorum yapan sen ol.