Lewati ke konten utama

Mendeteksi Ulasan Hotel yang Benar dan Menyesatkan menggunakan Machine Learning

Dalam tutorial ini, Anda akan menggunakan algoritma machine learning untuk menerapkan masalah nyata di Python. Anda akan mempelajari cara membaca banyak file teks di python, mengekstrak label, menggunakan dataframe, dan masih banyak lagi!
· 11 mnt Baca

Jelajahi bersama AI

Dalam tutorial ini, Anda akan bekerja dengan dataset teks Deceptive Opinion Spam Corpus sebagai contoh.

Secara singkat, Anda akan membahas topik-topik berikut dalam tutorial hari ini:

  • Pertama, Anda akan mendapat pengantar tentang Hotel Review Dataset lalu mengimpor semua modul yang diperlukan,
  • Kemudian Anda akan mulai memahami struktur data: Mengambil semua file teks dari path data, mengekstrak label darinya, membuat dataframe berisi label dan ulasan, lalu menggabungkan kedua dataframe,
  • Berikutnya Anda akan melakukan prapemrosesan data: Menghapus stopword dari ulasan hotel menggunakan pustaka natural language toolkit dan mengekstrak kelas kata (parts of speech) untuk setiap kata dalam dataset Anda.
  • Setelah data dipraproses, Anda siap menyiapkan pelatihan data: Memisahkan data menjadi data latih dan uji, mempelajari Tfidf, melakukan vektorisasi pada data latih dan uji, mengimplementasikan model support vector machine, menyimpan keduanya: vektorisasi Tfidf untuk data Anda dan modelnya, lalu memuatnya kembali.
  • Terakhir, Anda akan melakukan prediksi pada data uji: Memplot confusion matrix, skor akurasi, dan confusion matrix untuk mengecek efektivitas model, Anda juga akan menguji model dengan memisahkan data latih dan uji menggunakan berbagai random state, dan pada akhirnya menggunakan dua ulasan Yelp daring untuk menguji model Anda.

Memahami Deceptive Opinion Spam Dataset

Sebelum melanjutkan dan memuat data, ada baiknya melihat dengan saksama apa yang akan Anda kerjakan! Deceptive opinion spam dataset adalah korpus yang terdiri dari ulasan hotel yang jujur dan menyesatkan dari 20 hotel di Chicago. Data ini dijelaskan dalam dua makalah berdasarkan sentimen ulasan. Secara khusus, artikel membahas ulasan bersentimen positif dalam 1 dan ulasan bersentimen negatif dalam 2, silakan merujuk ke makalah tersebut untuk pengetahuan yang lebih mendalam.

Korpus ini berisi:

  • 400 ulasan positif yang jujur dari TripAdvisor
  • 400 ulasan positif yang menyesatkan dari Mechanical Turk
  • 400 ulasan negatif yang jujur dari Expedia, Hotels.com, Orbitz, Priceline, TripAdvisor, dan Yelp
  • 400 ulasan negatif yang menyesatkan dari Mechanical Turk

Secara total ada 1600 ulasan, tugas Anda adalah mengklasifikasikan ulasan hotel yang jujur dan menyesatkan menggunakan algoritma machine learning.

Mari kita mulai!

Impor semua modul yang diperlukan

Anda mulai dengan mengimpor semua modul yang diperlukan seperti os, pandas, nltk, regex dan yang terpenting Sklearn karena dalam tutorial hari ini Anda akan menggunakan algoritma machine learning Support Vector Machine yang disediakan oleh pustaka Sklearn!

Anda akan membutuhkan os untuk melakukan iterasi pada folder dan subfolder tempat file teks berada, fnmatch akan berguna untuk memfilter hanya file teks dan mengabaikan yang lainnya di dalam folder, pandas akan membantu Anda menempatkan data dalam bentuk baris dan kolom serta melakukan berbagai manipulasi data. Regex membantu mengekstrak data berdasarkan pola yang Anda tentukan, jadi Anda akan memerlukannya juga! Nltk adalah natural language toolkit yang akan membantu Anda menghapus stopword yang tidak ingin dipelajari oleh model. Lalu yang paling penting Anda akan mengimpor Sklearn yang menyediakan sekumpulan pustaka yang akan Anda gunakan untuk memanipulasi data, melakukan vektorisasi data, mempelajari batas antar titik data menggunakan algoritma machine learning dan akhirnya memplot akurasi.

import os
import fnmatch
from textblob import TextBlob
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer
from nltk.corpus import stopwords
from nltk import pos_tag,pos_tag_sents
import regex as re
import operator
from sklearn.svm import SVC, LinearSVC
from sklearn.metrics import classification_report, accuracy_score, confusion_matrix
from sklearn.cross_validation import train_test_split  
from sklearn import metrics
from sklearn import svm
from sklearn.grid_search import GridSearchCV
import pickle
from nltk.corpus import stopwords

Ambil semua file teks dari path, ekstrak labelnya, dan buat dataframe label

structure of the data
Gambar: Struktur Data


Setelah mengimpor pustaka, tugas berikutnya adalah mengekstrak label dari data. Label akan membantu model membedakan antara ulasan, apakah suatu ulasan termasuk kelas yang jujur atau menyesatkan.

Pertama, Anda akan melakukan iterasi pada semua file teks dan mendapatkan path absolut dari semua file teks yang kemudian akan digunakan untuk mengekstrak label yang sesuai.

path = 'op_spam_train/'

label = []

configfiles = [os.path.join(subdir,f)
for subdir, dirs, files in os.walk(path)
    for f in fnmatch.filter(files, '*.txt')]

Seharusnya ada 1600 path yang masing-masing merepresentasikan satu file teks baru. Mari kita verifikasi cepat!

len(configfiles)
1600

Mari juga cetak salah satu path file teks.

configfiles[1]
'op_spam_train/negative_polarity/deceptive_from_MTurk/fold4/d_swissotel_14.txt'

Dari keluaran di atas, Anda dapat melihat bahwa untuk mengekstrak label kita membutuhkan semacam filter. Untuk itu, Anda akan menggunakan Regex atau regular expression.

for f in configfiles:
    c = re.search('(trut|deceptiv)\w',f)
    label.append(c.group())

Setelah label diekstrak dalam sebuah list bernama label, mari buat dataframe dari list tersebut.

labels = pd.DataFrame(label, columns = ['Labels'])

Mari cetak lima baris pertama dari dataframe labels.

labels.head(5)
 Labels
0deceptive
1deceptive
2deceptive
3deceptive
4deceptive

Ambil semua ulasan dan tambahkan ke dalam list

Setelah Anda mengekstrak semua label, saatnya mengekstrak ulasan dari file teks!

review = []
directory =os.path.join("op_spam_train")
for subdir,dirs ,files in os.walk(directory):
   # print (subdir)
    for file in files:
        if fnmatch.filter(files, '*.txt'):
            f=open(os.path.join(subdir, file),'r')
            a = f.read()
            review.append(a)

Seperti sebelumnya, sekarang Anda akan membuat dataframe dari list review.

reviews = pd.DataFrame(review, columns = ['HotelReviews'])

Mari cetak lima baris pertama dari dataframe reviews.

reviews.head(5)
 HotelReviews
0Grant it, this hotel seems very nice, but I wa...
1I recently stayed at the Swissotel Chicago wit...
2I was sorely disappointed with the Sheraton Ch...
3My family and I stayed at the Sheraton Chicago...
4I recently stayed at the Homewood Suites by Hi...

Bagus! Sampai sini cukup intuitif, bukan?

Sekarang mari gabungkan dataframe labels dan reviews!

Gabungkan dataframe ulasan dan dataframe label

result = pd.merge(reviews, labels,right_index=True,left_index = True)


result['HotelReviews'] = result['HotelReviews'].map(lambda x: x.lower())

Setelah digabung, Anda memiliki dataframe baru bernama result. Mari juga cetak beberapa baris dari dataframe baru ini.

result.head()
 HotelReviewsLabels
0grant it, this hotel seems very nice, but i wa...deceptive
1i recently stayed at the swissotel chicago wit...deceptive
2i was sorely disappointed with the sheraton ch...deceptive
3my family and i stayed at the sheraton chicago...deceptive
4i recently stayed at the homewood suites by hi...deceptive

Hapus stopword dari kolom Hotel Reviews

Saat menangani data teks, sangat penting untuk menghapus stopword. Stopword tidak bermakna dan tidak memberikan informasi yang dapat membantu model mempelajari pola dalam data.

Anda akan membuat kolom baru dalam dataframe bernama review_without_stopwords. Fungsi lambda akan memproses semua baris pada kolom HotelReviews. Anda akan menggunakan list comprehension dan hanya menyimpan kata-kata yang tidak ada dalam variabel stop ke kolom baru.

import ntlk
nltk.download('stopwords')

Catatan: Untuk menjalankan sel di bawah ini, Anda mungkin perlu mengeksekusi baris-baris kode di atas pada terminal Anda.

stop = stopwords.words('english')

result['review_without_stopwords'] = result['HotelReviews'].apply(lambda x: ' '.join([word for word in x.split() if word not in (stop)]))

Mari cepat cetak dataframe tanpa stopword!

result.head()
 HotelReviewsLabelsreview_without_stopwords
0grant it, this hotel seems very nice, but i wa...deceptivegrant it, hotel seems nice, pleased stay here....
1i recently stayed at the swissotel chicago wit...deceptiverecently stayed swissotel chicago husband two ...
2i was sorely disappointed with the sheraton ch...deceptivesorely disappointed sheraton chicago. outside ...
3my family and i stayed at the sheraton chicago...deceptivefamily stayed sheraton chicago hotel towers be...
4i recently stayed at the homewood suites by hi...deceptiverecently stayed homewood suites hilton chicago...

Ekstrak kelas kata (parts of speech) dari ulasan hotel yang akan dijadikan masukan fitur untuk model

Menurut 1 yang menyarankan bahwa opini yang jujur dan menyesatkan masing-masing dapat diklasifikasikan ke dalam genre informatif dan imajinatif. Terdapat perbedaan distribusional yang kuat antara tulisan informatif dan imajinatif, yaitu yang pertama biasanya terdiri dari lebih banyak nomina, adjektiva, preposisi, determinator, dan konjungsi koordinatif, sedangkan yang terakhir mencakup lebih banyak verba, adverbia, pronomina, dan predeterminator. Namun, bahwa opini menyesatkan mengandung lebih banyak superlatif bukanlah hal yang mengejutkan karena tulisan menyesatkan (meski tidak selalu tulisan imajinatif pada umumnya) seringkali berisi bahasa yang berlebihan.

Jadi, sekarang untuk setiap kata dalam baris dataframe mari kita ekstrak kelas katanya masing-masing dan Anda kemudian akan memasukkannya sebagai vektor fitur ke dalam model.

Untuk pelabelan pos, Anda akan menggunakan TextBlob, yaitu pustaka Python untuk memproses data tekstual. Pustaka ini menyediakan API sederhana untuk menyelami tugas-tugas pemrosesan bahasa alami (NLP) umum seperti penandaan kelas kata, ekstraksi frasa nomina, analisis sentimen, klasifikasi, penerjemahan, dan lainnya.

Catatan: Untuk menjalankan sel fungsi pos, Anda mungkin perlu menjalankan baris-baris kode berikut di jendela terminal Anda.

import nltk
nltk.download('punkt')
nltk.download('averaged_perceptron_tagger')
def pos(review_without_stopwords):
    return TextBlob(review_without_stopwords).tags
os = result.review_without_stopwords.apply(pos)
os1 = pd.DataFrame(os)

Setiap baris dataframe os1 akan berisi sebuah daftar kata beserta kelas katanya masing-masing. Anda tidak dapat memvektorkan sebuah daftar untuk dimasukkan ke dalam model. Jadi, Anda harus mengonversi baris-baris berupa daftar ini menjadi string.

os1.head()
 review_without_stopwords
0[(grant, NN), (it, PRP), (hotel, NN), (seems, ...
1[(recently, RB), (stayed, VBN), (swissotel, NN...
2[(sorely, RB), (disappointed, JJ), (sheraton, ...
3[(family, NN), (stayed, VBD), (sheraton, JJ), ...
4[(recently, RB), (stayed, VBN), (homewood, NN)...

Mari konversi setiap baris menjadi string, di mana setiap kata akan digabungkan dengan pos yang sesuai menggunakan garis miring, dan setiap kata dipisahkan oleh satu spasi.

os1['pos'] = os1['review_without_stopwords'].map(lambda x:" ".join(["".join(x) for x in x ]) )

Terakhir, mari gabungkan kolom pos dengan dataframe utama result dan cetak beberapa baris pertamanya!

result = result = pd.merge(result, os1,right_index=True,left_index = True)
result.head()
first few rows of pos column and the main result df

Fase Pelatihan

Bagi data menjadi dua bagian: 80% latih dan 20% uji

Setelah fitur diekstrak, sekarang saatnya membagi data menjadi pelatihan dan pengujian. Untuk tutorial ini, Anda akan membagi 80% data untuk pelatihan dan 20% sisanya untuk pengujian.

review_train, review_test, label_train, label_test = train_test_split(result['pos'],result['Labels'], test_size=0.2,random_state=13)

Vektorkan data latih dan uji menggunakan TfidfVectorizer

Mari pahami lebih detail tentang TfidfVectorizer

Tfidf memiliki dua bagian:

    • Term Frequency (Tf): Seberapa sering sebuah kata tertentu muncul dalam satu dokumen. Untuk memahaminya lebih baik mari ambil kata: “the”. Kata ini cukup umum dan akan muncul dengan frekuensi tinggi di semua dokumen Anda. Namun jika dipikir, “the” tidak memberikan info tambahan tentang dokumen Anda. Tetapi jika kita berbicara tentang kata “messi”, kata ini memberi konteks. Kita bisa mengatakan dengan tingkat kepastian tertentu bahwa dokumen tersebut mungkin tentang sepak bola. Jadi kita perlu mengurangi bobot “the” dengan cara tertentu. Sekarang Anda mungkin berkata bisa mengambil kebalikan dari frekuensi masing-masing untuk memberi bobot lebih pada “messi”. Hampir benar tapi ada catatan. Mungkin ada kata yang sangat jarang dalam dokumen. Misalnya: “floccinaucinihilipilification”. Ini adalah kata nyata yang berarti: “Tindakan atau kebiasaan menilai sesuatu tidak berharga.” Jika Anda menggunakan kebalikan untuk kata ini, nilainya akan mendekati 1 tetapi lagi-lagi tidak memberi tahu konteks. Jadi, (menggunakan angka sebagai contoh) tf (“the”) = 100 tf(“messi”) = 5 tf(“floccinaucinihilipilification”) = 1
  • Inverse Document Frequency (idf): Masalah kata yang sering dan yang langka di atas diatasi dengan menambahkan istilah ini. Jadi apa itu? Dihitung dengan mengambil log dari {jumlah dokumen dalam korpus dibagi jumlah dokumen yang memuat istilah tersebut}. Jadi untuk “the”, rasionya akan mendekati 1. Karena itu, log akan menjadi 0. idf (“the”) = 0 idf (“messi”) = log(10/3) = 0,52 (karena korpus tentang sepak bola) idf (“floccinaucinihilipilification”) = log(10/1) = 1
  • Langkah terakhir: Sekarang kita ingin bobot yang diberikan pada “messi” lebih tinggi daripada dua kata lainnya. Untuk itu kita mengalikan dua istilah: tfidf = tf x idf "the" = 100 x 0 = 0, "floccinaucinihilipilification" = 1 x 1 = 1, "messi" = 5 x 0,52 = 2,6

Teknik pembobotan ini membantu model machine learning (ML) saat klasifikasi karena kita secara eksplisit memberi tahu kata mana yang berbobot lebih/kurang.

Sekarang setelah Anda memahaminya, mari kita terapkan pada data latih dan uji.

tf_vect = TfidfVectorizer(lowercase = True, use_idf=True, smooth_idf=True, sublinear_tf=False)

X_train_tf = tf_vect.fit_transform(review_train)
X_test_tf = tf_vect.transform(review_test)

Mengimplementasikan Model

Sekarang, Anda akan mengimplementasikan model machine learning yang dikenal sebagai Support Vector Machines (SVM). Untuk memahaminya Anda dapat mengikuti tautan ini.

Untuk memilih hiperparameter terbaik bagi algoritma ML Anda, Anda akan menggunakan GridSearchCV, yang berdasarkan data dan label pelatihan Anda menyarankan nilai hiperparameter terbaik dari nilai-nilai yang Anda tentukan sebagai daftar. Anda akan memilih lima nilai berbeda untuk C dan gamma dan berdasarkan data Anda; Anda akan mendapatkan nilai hiperparameter terbaik.

def svc_param_selection(X, y, nfolds):
    Cs = [0.001, 0.01, 0.1, 1, 10]
    gammas = [0.001, 0.01, 0.1, 1]
    param_grid = {'C': Cs, 'gamma' : gammas}
    grid_search = GridSearchCV(svm.SVC(kernel='linear'), param_grid, cv=nfolds)
    grid_search.fit(X, y)
    return grid_search.best_params_
svc_param_selection(X_train_tf,label_train,5)
{'C': 10, 'gamma': 0.001}
clf = svm.SVC(C=10,gamma=0.001,kernel='linear')
clf.fit(X_train_tf,label_train)
pred = clf.predict(X_test_tf)

Simpan vektorisasi Tfidf dan model ML

Mari simpan model yang baru saja Anda latih bersama dengan vektorisasi Tfidf menggunakan pustaka pickle yang Anda impor di awal, sehingga nanti Anda bisa langsung memuat data, melakukan vektorisasi, dan memprediksi menggunakan model ML.

with open('vectorizer.pickle', 'wb') as fin:
    pickle.dump(tf_vect, fin)
with open('mlmodel.pickle','wb') as f:
    pickle.dump(clf,f)

Muat vektorisasi Tfidf dan model ML

pkl = open('mlmodel.pickle', 'rb')
clf = pickle.load(pkl)   
vec = open('vectorizer.pickle', 'rb')
tf_vect = pickle.load(vec)
/home/naveksha/.local/lib/python3.5/site-packages/sklearn/base.py:311: UserWarning: Trying to unpickle estimator SVC from version pre-0.18 when using version 0.19.1. This might lead to breaking code or invalid results. Use at your own risk.
  UserWarning)
/home/naveksha/.local/lib/python3.5/site-packages/sklearn/base.py:311: UserWarning: Trying to unpickle estimator TfidfTransformer from version pre-0.18 when using version 0.19.1. This might lead to breaking code or invalid results. Use at your own risk.
  UserWarning)
/home/naveksha/.local/lib/python3.5/site-packages/sklearn/base.py:311: UserWarning: Trying to unpickle estimator TfidfVectorizer from version pre-0.18 when using version 0.19.1. This might lead to breaking code or invalid results. Use at your own risk.
  UserWarning)

Prediksi pada Data Uji

X_test_tf = tf_vect.transform(review_test)
pred = clf.predict(X_test_tf)

Plot confusion matrix, skor akurasi, dan classification report untuk menganalisis kinerja model

print(metrics.accuracy_score(label_test, pred))
0.96875
print (confusion_matrix(label_test, pred))
[[149   6]
 [  4 161]]

Confusion matrix di atas adalah matriks 2 x 2, di mana elemen baris pertama kolom pertama adalah True Positive (TP), baris pertama kolom kedua adalah False Negative (FN), baris kedua kolom pertama adalah False Positive (FP) dan baris kedua kolom kedua adalah True Negative (TN).

Dari confusion matrix di atas, Anda dapat menyimpulkan hanya 10 sampel uji dari 320 yang salah klasifikasi.

print (classification_report(label_test, pred))
             precision    recall  f1-score   support

  deceptive       0.97      0.96      0.97       155
      truth       0.96      0.98      0.97       165

avg / total       0.97      0.97      0.97       320

Uji Model menggunakan berbagai Random State

  • Random State 1
review_train, review_test, label_train, label_test = train_test_split(result['pos'],result['Labels'], test_size=0.2,random_state=1)
X_test_tf = tf_vect.transform(review_test)
pred = clf.predict(X_test_tf)
print(metrics.accuracy_score(label_test, pred))
0.978125
print (confusion_matrix(label_test, pred))
[[146   5]
 [  2 167]]
print (classification_report(label_test, pred))
             precision    recall  f1-score   support

  deceptive       0.99      0.97      0.98       151
      truth       0.97      0.99      0.98       169

avg / total       0.98      0.98      0.98       320
  • Random State 10
review_train, review_test, label_train, label_test = train_test_split(result['pos'],result['Labels'], test_size=0.2,random_state=10)
X_test_tf = tf_vect.transform(review_test)
pred = clf.predict(X_test_tf)
print(metrics.accuracy_score(label_test, pred))
0.98125
print (confusion_matrix(label_test, pred))
[[155   5]
 [  1 159]]
print (classification_report(label_test, pred))
             precision    recall  f1-score   support

  deceptive       0.99      0.97      0.98       160
      truth       0.97      0.99      0.98       160

avg / total       0.98      0.98      0.98       320
  • Random State 42
review_train, review_test, label_train, label_test = train_test_split(result['pos'],result['Labels'], test_size=0.2,random_state=42)
X_test_tf = tf_vect.transform(review_test)
pred = clf.predict(X_test_tf)
print(metrics.accuracy_score(label_test, pred))
0.984375
print (confusion_matrix(label_test, pred))
[[165   3]
 [  2 150]]
print (classification_report(label_test, pred))
             precision    recall  f1-score   support

  deceptive       0.99      0.98      0.99       168
      truth       0.98      0.99      0.98       152

avg / total       0.98      0.98      0.98       320

Dari prediksi di atas, Anda dapat melihat bahwa Model bekerja dengan Sangat Baik dan tidak overfitting karena Anda menguji model beberapa kali dengan membagi data secara berbeda setiap kali.

Uji model dengan dua ulasan dari Yelp

def test_string(s):
    X_test_tf = tf_vect.transform([s])
    y_predict = clf.predict(X_test_tf)
    return y_predict
test_string("The hotel was good.The room had a 27-inch Samsung led tv, a microwave.The room had a double bed")
array(['truth'], dtype=object)
test_string("My family and I are huge fans of this place. The staff is super nice, and the food is great. The chicken is very good, and the garlic sauce is perfect. Ice cream topped with fruit is delicious too. Highly recommended!")
array(['deceptive'], dtype=object)

Model memprediksi kedua ulasan di atas dengan benar. Ulasan pertama adalah ulasan yang Jujur sedangkan ulasan kedua adalah ulasan yang menyesatkan!

Catatan

Kinerja model bervariasi saat diimplementasikan pada sistem pemrosesan yang berbeda dengan spesifikasi berbeda, ini adalah perilaku tidak biasa yang diamati. Jika komunitas dapat membantu mencari tahu masalah ini, hal itu akan sangat membantu banyak orang termasuk penulis artikel ini. Yang dimaksud komunitas adalah para pembaca yang akan melalui tutorial ini!

Selamat belajar!

Semoga tutorial ini benar-benar bermanfaat dan menambah nilai pada keterampilan Anda.

Jika Anda ingin mempelajari lebih lanjut tentang Machine Learning, ikuti kursus DataCamp Building Chatbots in Python.

Topik

Terkait

blogs

Tutorial Korelasi di R

blogs

40 Pertanyaan Wawancara DBMS Teratas di 2026