Sentiment Analysis Data Twitter menggunakan Machine Learning

Salah satu pengaplikasisan machine learning yang paling populer adalah untuk melakukan analisis sentimen. Dengan analisis sentimen, dapat diketahui apakah suatu teks, seperti tweet, ulasan produk, atau komentar, memiliki sentimen seperti positif atau negatif. Hal ini sangat berguna bagi suatu perusahaan ataupun instansi pemerintah untuk memahami opini publik terhadap layanan ataupun produk yang mereka tawarkan, pemonitoran terhadap suatu brand bisa lebih efektif yang pada akhirnya akan berdampak pada meningkatnya kepuasan pelanggan.

Pada artikel ini, kita akan mencoba setiap tahapan langkah demi langkah bagaimana melakukan analisis sentimen sederhana menggunakan dataset Sentiment140. Adapun model machine learning yang akan kita gunakan antara lain: Naive Bayes, SVM (Support Vector Machine), dan Logistic Regression. Pada artikel ini kita tidak akan membahas bagaimana detail masing-masing algoritma tersebut bekerja. Fokus pada artikel ini adalah untuk mencoba bagaimana mempersiapkan data, melatih model, dan mengevaluasi model untuk melakukan sentiment analysis.

Mempersiapkan Environment

Pertama-tama, pastikan kita sudah menginstal package-package yang diperlukan untuk mengikuti artikel ini yaitu:

pip install pandas nltk scikit-learn joblib

Kemudian, unduh stopwords dari NLTK:

import nltk
nltk.download('stopwords')

Memuat dan Mempersiapkan Data

import pandas as pd

# Memuat dataset
data = pd.read_csv('data/sentiment140.csv', encoding='latin-1', header=None)
data.columns = ['target', 'ids', 'date', 'flag', 'user', 'text']

# Menghapus kolom yang tidak diperlukan
data = data.drop(columns=['ids', 'date', 'flag', 'user'])

# Mengonversi target menjadi biner (0: Negatif, 1: Positif)
data['target'] = data['target'].apply(lambda x: 1 if x == 4 else 0)

# Membuat subset seimbang dari 10% data
positive_samples = data[data['target'] == 1].sample(frac=0.05, random_state=42)
negative_samples = data[data['target'] == 0].sample(frac=0.05, random_state=42)

five_percent_data = pd.concat([positive_samples, negative_samples])

Langkah pertama yang kita lakukan adalah memuat dataset yang akan digunakan. Dalam hal ini, kita menggunakan dataset Sentiment140 yang berisi data tweet dengan sentimen posifit dan negatif. Dataset ini dimuat menggunakan pustaka pandas dengan perintah pd.read_csv, di mana kita menetapkan parameter encoding='latin-1' untuk memastikan karakter non-ASCII ditangani dengan benar. Dataset ini secara default tidak memiliki header, sehingga kita perlu memasukkannya secara manual untuk memudahkan pengolahan data selanjutnya, penamaan ['target', 'ids', 'date', 'flag', 'user', 'text'] disesuaikan dengan dokumentasi pada dataset Sentiment140. Setelah itu, kita menghapus kolom-kolom yang tidak diperlukan dalam analisis ini, yaitu 'ids', 'date', 'flag', dan 'user', sehingga kita hanya menyisakan kolom 'target' dan 'text'. Kolom 'target' berisikan sentiment yang akan diprediksi sedangkan 'text' adalah teks yang akan dilatih.

Langkah selanjutnya adalah melakukan konversi pada target. Pada dokumentasi dataset, disebutkan bahwa tweet yang memiliki sentimen positif diberi label 4, tweet netral diberi label 2 dan yang memiliki sentimen negatif diberikan label 0. Namun setelah dieksplorasi, nilai yang ada pada target hanya 0 dan 4 (tidak ada 2 / netral).

Oleh karen itu, untuk memudahkan kita ubah kolom 'target', yang memiliki nilai 4 menjadi 1 dan nilai lainnya menjadi 0. Selanjutnya, untuk mempercepat proses kita hanya akan mengambil subset sebanyak 10% dari data asli. Kita mengambil 5% sampel acak dari data positif dan 5% sampel acak dari data negatif menggunakan fungsi sample dengan parameter frac=0.05 dan random_state=42 untuk memastikan reprodusibilitas. Dengan demikian, kita bisa melakukan pelatihan menggunakan perangkat dengan spesifikasi lebih rendah.

Pra-Pemrosesan Data Teks

import re
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer

def preprocess_text(text):
    text = re.sub(r'http\S+', '', text)  # Menghapus URL
    text = re.sub(r'[^a-zA-Z\s]', '', text)  # Menghapus tanda baca
    text = text.lower()  # Mengonversi ke huruf kecil
    text = text.split()  # Membagi teks menjadi kata-kata
    ps = PorterStemmer()
    text = [ps.stem(word) for word in text if not word in set(stopwords.words('english'))]  # Menghapus stopwords dan melakukan stemming
    text = ' '.join(text)
    return text

five_percent_data['text'] = five_percent_data['text'].apply(preprocess_text)

Agar teks siap digunakan dalam model machine learning, kita perlu melakukan beberapa langkah pra-pemrosesan. Pada blok kode ini, fungsi preprocess_text digunakan untuk membersihkan dan mengolah teks. Pertama, kita menghapus URL dari teks menggunakan fungsi re.sub(r'http\S+', '', text), yang mencari dan menghilangkan semua pola URL. Langkah berikutnya adalah menghapus semua tanda baca dan karakter non-alfabet menggunakan re.sub(r'[^a-zA-Z\s]', '', text), sehingga hanya menyisakan huruf dan spasi. Setelah itu, teks dikonversi menjadi huruf kecil dengan text.lower(), dan dibagi menjadi kata-kata individu dengan text.split().

Setelah teks dipecah menjadi kata-kata, kita menggunakan Porter Stemmer dari pustaka NLTK untuk melakukan stemming, yaitu proses mengubah kata ke bentuk dasarnya. Sebelum stemming, kita juga menghapus stopwords (kata-kata umum yang sering muncul tetapi tidak banyak berkontribusi pada makna, seperti "and", "the", "is", dll.) menggunakan daftar stopwords bahasa Inggris dari NLTK. Setiap kata dalam teks yang bukan stopword kemudian di-stem menggunakan ps.stem(word). Kata-kata yang telah di-stem ini kemudian digabung kembali menjadi satu string dengan ' '.join(text). Fungsi preprocess_text ini kemudian diterapkan pada kolom 'text' dari dataset five_percent_data menggunakan apply(preprocess_text), sehingga setiap teks dalam dataset diproses dan dibersihkan sebelum digunakan dalam model pembelajaran mesin.Membagi Dataset dan Memvektorisasi Data Teks. Langkah selanjutnya adalah kita akan membagi data menjadi set pelatihan dan pengujian, lalu memvektorisasi teks menggunakan TF-IDF:

from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.model_selection import train_test_split

X = five_percent_data['text']
y = five_percent_data['target']

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

vectorizer = TfidfVectorizer(max_features=5000)
X_train_vect = vectorizer.fit_transform(X_train)
X_test_vect = vectorizer.transform(X_test)

# Menyimpan vektorizer
import joblib
joblib.dump(vectorizer, 'model/tfidf_vectorizer.pkl')

Tahap selanjutnya adalah mengubah teks mentah menjadi bentuk numerik yang dapat diproses oleh algoritma. Terlebih dahulu kita perlu memisahkan data menjadi fitur (X) dan target (y) dari dataset. Fitur berupa teks disimpan dalam X, sementara target atau label (positif atau negatif) disimpan dalam y. Selanjutnya, kita membagi dataset menjadi data latih dan data uji, sejumlah 20% data disisihkan untuk pengujian (test_size=0.2) dan sisanya untuk pelatihan, kita juga memastikan pemilahan data yang acak namun konsisten dengan seed random_state=42.

Untuk mengubah teks menjadi bentuk numerik, kita menggunakan TfidfVectorizer dari scikit-learn. Vectorizer ini mengubah teks menjadi representasi vektor berdasarkan frekuensi kata dan kepentingannya dalam dokumen (TF-IDF). Kita membatasi jumlah fitur maksimum yang akan dihasilkan menjadi 5000 untuk menjaga efisiensi komputasi. TfidfVectorizer pertama-tama di-fit ke data pelatihan X_train dan mentransformasikan teks pelatihan menjadi matriks vektor X_train_vect. Selanjutnya, vectorizer yang telah dilatih digunakan untuk mentransformasikan teks uji X_test menjadi matriks vektor X_test_vect. Setelah itu, kita menyimpan model vectorizer yang telah dilatih menggunakan joblib.dump sehingga bisa digunakan kembali nanti tanpa perlu melatih ulang, dan menyimpannya dalam file model/tfidf_vectorizer.pkl.

Melatih dan Menyimpan Model

Kita akan melatih tiga model: Naive Bayes, SVM, dan Logistic Regression. Setelah melatih model, kita akan menyimpan setiap model untuk digunakan nanti:

from sklearn.naive_bayes import MultinomialNB
from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression

# Melatih dan menyimpan model Naive Bayes
nb_model = MultinomialNB()
nb_model.fit(X_train_vect, y_train)
joblib.dump(nb_model, 'model/naive_bayes_model.pkl')

# Melatih dan menyimpan model SVM
svm_model = SVC(probability=True)
svm_model.fit(X_train_vect, y_train)
joblib.dump(svm_model, 'model/svm_model.pkl')

# Melatih dan menyimpan model Logistic Regression
lr_model = LogisticRegression(max_iter=1000)
lr_model.fit(X_train_vect, y_train)
joblib.dump(lr_model, 'model/logistic_regression_model.pkl')

Setelah mengubah teks menjadi representasi numerik, langkah selanjutnya adalah melatih beberapa model pembelajaran mesin untuk analisis sentimen. Di sini kita menggunakan tiga model berbeda: Naive Bayes, SVM (Support Vector Machine), dan Logistic Regression.

Pertama, kita melatih model Naive Bayes dengan menggunakan MultinomialNB, yang merupakan varian dari Naive Bayes yang cocok untuk data teks. Model ini dilatih dengan data pelatihan yang telah diubah menjadi vektor, dan kemudian model yang telah dilatih disimpan dalam file naive_bayes_model.pkl menggunakan joblib.dump. Selanjutnya, kita melatih model SVM dengan menggunakan SVC, yang juga menerima parameter probability=True untuk memungkinkan estimasi probabilitas. Setelah pelatihan, model SVM yang telah dilatih disimpan dalam file svm_model.pkl. Terakhir, kita melatih model Logistic Regression menggunakan LogisticRegression dengan batas iterasi maksimum 1000 untuk memastikan konvergensi. Setelah pelatihan, model Logistic Regression yang telah dilatih disimpan dalam file logistic_regression_model.pkl. Dengan menyimpan model-model ini, kita dapat dengan mudah memuatnya kembali dan menggunakannya untuk prediksi tanpa perlu melatih ulang, menghemat waktu dan sumber daya komputasi.

Mengevaluasi Model

from sklearn.metrics import accuracy_score, classification_report

y_pred_nb = nb_model.predict(X_test_vect)
y_pred_svm = svm_model.predict(X_test_vect)
y_pred_lr = lr_model.predict(X_test_vect)

print("Naive Bayes Model")
print("Accuracy:", accuracy_score(y_test, y_pred_nb))
print("Classification Report:\n", classification_report(y_test, y_pred_nb))

print("SVM Model")
print("Accuracy:", accuracy_score(y_test, y_pred_svm))
print("Classification Report:\n", classification_report(y_test, y_pred_svm))

print("Logistic Regression Model")
print("Accuracy:", accuracy_score(y_test, y_pred_lr))
print("Classification Report:\n", classification_report(y_test, y_pred_lr))

Untuk mengevaluasi kinerja dari model yang sudah dibuat, kita lakukan prediksi menggunakan masing-masing model: Naive Bayes, SVM, dan Logistic Regression, pada data uji yang telah diubah menjadi vektor (X_test_vect). Hasil prediksi ini kemudian dibandingkan dengan label sebenarnya (y_test) untuk menghitung akurasi dan menghasilkan laporan klasifikasi.

Untuk setiap model, kode ini mencetak akurasi dan laporan klasifikasi yang berisi metrik-metrik penting seperti precision, recall, dan F1-score. Akurasi dihitung menggunakan fungsi accuracy_score dari sklearn.metrics, yang memberikan persentase prediksi yang benar dari total prediksi. Laporan klasifikasi dihasilkan menggunakan fungsi classification_report, yang memberikan rincian kinerja model untuk setiap kelas (positif dan negatif) dalam hal precision (ketepatan), recall (kelengkapan), dan F1-score (harmonik rata-rata dari precision dan recall). Dengan membandingkan metrik-metrik ini, kita bisa mendapatkan gambaran yang lebih lengkap tentang kinerja masing-masing model dalam tugas analisis sentimen.

Melakukan Prediksi pada Data Baru

Untuk mengetesnya pada data baru seperti teks yang kita buat sendiri, kita bisa membuat file baru dan menuliskan kode di bawah ini

import joblib
import re
import nltk
from nltk.corpus import stopwords
from nltk.stem import PorterStemmer
import argparse

nltk.download('stopwords')

# Preprocess text data
def preprocess_text(text):
    text = re.sub(r'http\S+', '', text)  # Menghapus URL
    text = re.sub(r'[^a-zA-Z\s]', '', text)  # Menghapus tanda baca
    text = text.lower()  # Mengonversi ke huruf kecil
    text = text.split()  # Membagi teks menjadi kata-kata
    ps = PorterStemmer()
    text = [ps.stem(word) for word in text if not word in set(stopwords.words('english'))]  # Menghapus stopwords dan melakukan stemming
    text = ' '.join(text)
    return text

# Memuat vektorizer dan model
vectorizer = joblib.load('model/tfidf_vectorizer.pkl')
nb_model = joblib.load('model/naive_bayes_model.pkl')
svm_model = joblib.load('model/svm_model.pkl')
lr_model = joblib.load('model/logistic_regression_model.pkl')

# Argument parser
parser = argparse.ArgumentParser(description='Predict sentiment of input text.')
parser.add_argument('-t','--text', type=str, help='Text to analyze sentiment')
args = parser.parse_args()

# Memproses teks input
input_text = args.text
input_text_processed = preprocess_text(input_text)
input_text_vect = vectorizer.transform([input_text_processed])

# Prediksi menggunakan Naive Bayes
nb_prediction = nb_model.predict(input_text_vect)[0]
nb_prob = nb_model.predict_proba(input_text_vect)[0]

# Prediksi menggunakan SVM
svm_prediction = svm_model.predict(input_text_vect)[0]

# Prediksi menggunakan Logistic Regression
lr_prediction = lr_model.predict(input_text_vect)[0]
lr_prob = lr_model.predict_proba(input_text_vect)[0]

# Menampilkan prediksi
print(f"Teks Input: {input_text}")
print(f"Naive Bayes: {'Positif' if nb_prediction == 1 else 'Negatif'} (Confidence: {nb_prob[nb_prediction]:.2f})")
print(f"SVM: {'Positif' if svm_prediction == 1 else 'Negatif'}")
print(f"Logistic Regression: {'Positif' if lr_prediction == 1 else 'Negatif'} (Confidence: {lr_prob[lr_prediction]:.2f})")

Di sini kita membuat lagi fungsi preprocess_text digunakan untuk membersihkan dan mempersiapkan teks input. Selanjutnya adalah memuat vektorizer TF-IDF dan model Naive Bayes, SVM, serta Logistic Regression yang telah disimpan sebelumnya menggunakan joblib. Dengan menggunakan argparse, skrip ini akan dapat menerima teks input dari baris perintah, memungkinkan fleksibilitas dalam penggunaannya. Teks input yang diberikan oleh pengguna akan diproses dengan fungsi preprocess_text dan kemudian diubah menjadi vektor menggunakan vektorizer TF-IDF yang sudah dilatih. Prediksi dilakukan dengan masing-masing model, dan hasilnya ditampilkan kepada pengguna. Dengan ini, kita bisa melakukan prediksi sentimen pada teks yang dimasukkan pada terminal. Contohnya python predict.py -t "Manchester United is a great club":

Berikut contoh ketika memberikan input dengan sentimen negatif seperti python predict.py -t "Manchester United is suck":

Penutup

Dalam artikel ini, kita telah melalui berbagai tahapan untuk melakukan analisis sentimen menggunakan dataset Sentiment140. Dimulai dari memuat dan mempersiapkan data, kita melakukan pra-pemrosesan teks untuk membersihkan data sebelum digunakan dalam model machine learning. Selanjutnya, kita membagi data menjadi set pelatihan dan pengujian, serta memvektorisasi teks menggunakan TF-IDF. Tiga model berbeda, yaitu Naive Bayes, SVM, dan Logistic Regression, dilatih dan dievaluasi untuk melihat kinerjanya dalam memprediksi sentimen teks.

Untuk meningkatkan kinerja model dan analisis sentimen yang lebih akurat, beberapa saran yang dapat dipertimbangkan adalah: eksplorasi model lain seperti model berbasis neural network, melakukan tuning hyperparameter untuk setiap model, menggunakan lebih banyak data untuk pelatihan, dan menerapkan teknik pra-pemrosesan yang lebih canggih seperti lemmatization dan embedding word. Selain itu, pemantauan dan pembaruan model secara berkala dengan data baru dapat membantu model tetap relevan dan akurat seiring berjalannya waktu. Terus eksplorasi dan eksperimen adalah kunci untuk mencapai hasil terbaik dalam bidang machine learning. Selamat mencoba!

Source Code: Github