{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "rd9i5ETLBjbw"
},
"source": [
"Import Library"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PcZCXxiMBqbK"
},
"outputs": [],
"source": [
"import pandas as pd\n",
"from googleapiclient.discovery import build"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "00a4167c"
},
"source": [
"**Sel ini mengimpor pustaka yang diperlukan.**\n",
"* `import pandas as pd`: Mengimpor pustaka `pandas` yang sangat berguna untuk manipulasi dan analisis data, terutama dalam bekerja dengan DataFrames (struktur data seperti tabel).\n",
"* `from googleapiclient.discovery import build`: Mengimpor fungsi `build` dari `googleapiclient.discovery`. Fungsi ini digunakan untuk membuat objek layanan yang berinteraksi dengan Google API, dalam kasus ini, YouTube Data API."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Uh6aZRtjCLgs"
},
"source": [
"Fungsi untuk Crawling Komentar"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "PWtT41aaD6mP"
},
"outputs": [],
"source": [
"def video_comments(video_id, max_results=100): #Menambahkan parameter max results\n",
" #empty list for storing reply\n",
" replies = []\n",
"\n",
" # creating youtube resource obiect\n",
" youtube = build('youtube', 'v3', developerKey=api_key)\n",
" #Membuat objek resource YouTube menggunakan googleapiclient.discovery.build,\n",
" #dengan API versi v3. api_key adalah kunci API yang harus didefinisikan agar bisa mengakses data dari YouTube.\n",
"\n",
" # retrieve voutube video results\n",
" video_response = youtube.commentThreads().list(\n",
" part='snippet,replies',\n",
" videoId=video_id,\n",
" maxResults=min(max_results, 100) # Membatasi maxResults menjadi maksimal 100 per request\n",
" ).execute()\n",
"\n",
" #Mengambil komentar utama dari video berdasarkan video_ id, dengan parameter part='snippet, replies'\n",
" #yang menentukan agar data yang diambil mencakup informasi dasar (snippet) dan balasan (replies).\n",
"\n",
" # Counter untuk jumlah komentar yang sudah diambil\n",
" comment_count = 0\n",
"\n",
" # iterate video response\n",
" while video_response and comment_count < max_results:\n",
"\n",
" # extracting required inf\n",
" # fleach result object\n",
" for item in video_response['items']:\n",
"\n",
" # Extracting comments ()\n",
" published = item['snippet']['topLevelComment']['snippet']['publishedAt'] #Waktu komentar dipublikasikan\n",
" user = item['snippet']['topLevelComment']['snippet']['authorDisplayName'] # Nama pengguna yang membuat komentar\n",
"\n",
" # Extracting comments\n",
" comment = item['snippet']['topLevelComment']['snippet']['textDisplay']\n",
" likeCount = item['snippet']['topLevelComment']['snippet']['likeCount'] #Jumlah like pada komentar\n",
"\n",
" replies.append([published, user, comment, likeCount])\n",
" comment_count += 1\n",
"\n",
" # counting number of reply of comment\n",
" replycount = item['snippet']['totalReplyCount']\n",
"\n",
" # if reply is there\n",
" if replycount>0:\n",
"\n",
" # iterate through all reply\n",
" for reply in item['replies']['comments']:\n",
"\n",
" # Extract reply\n",
" published = reply['snippet']['publishedAt']\n",
" user = reply['snippet']['authorDisplayName']\n",
" repl = reply['snippet']['textDisplay']\n",
" likeCount = reply['snippet']['likeCount']\n",
" #Jika komentar memiliki balasan, fungsi ini akan mengulang melalui setiap balasan\n",
"\n",
" # Store reply is list\n",
" #replies.append(reply)\n",
" replies.append([published, user, repl, likeCount])\n",
" comment_count += 1 # Menambahkan counter\n",
" if comment_count >= max_results:\n",
" break # Keluar dari loop jika sudah mencapai batas max_results\n",
"\n",
" if comment_count >= max_results:\n",
" break\n",
"\n",
" # Again repeat\n",
" if 'nextPageToken' in video_response and comment_count < max_results:\n",
" video_response = youtube.commentThreads().list(\n",
" part = 'snippet,replies',\n",
" pageToken = video_response['nextPageToken'],\n",
" videoId = video_id,\n",
" maxResults=min(max_results - comment_count, 100)\n",
" ).execute()\n",
"\n",
" else:\n",
" break\n",
"\n",
" #endwhile\n",
" return replies"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3d796186"
},
"source": [
"**Sel ini mendefinisikan fungsi `video_comments`.**\n",
"\n",
"Fungsi `video_comments` dirancang untuk mengambil komentar dari video YouTube tertentu. Fungsi ini menerima `video_id` (ID unik video YouTube) dan `max_results` (jumlah maksimum komentar yang ingin diambil, defaultnya 100) sebagai parameter.\n",
"\n",
"**Cara kerjanya:**\n",
"1. Ini menginisialisasi objek layanan YouTube menggunakan `api_key` yang diberikan.\n",
"2. Ini secara berulang meminta komentar dan balasan komentar dari video menggunakan metode `commentThreads().list()` dari YouTube Data API.\n",
"3. Ini mengekstrak informasi penting seperti tanggal publikasi, nama pengguna, teks komentar, dan jumlah suka untuk setiap komentar utama dan balasannya.\n",
"4. Data yang diekstrak kemudian disimpan dalam daftar `replies`.\n",
"5. Proses berlanjut hingga `max_results` komentar terkumpul atau tidak ada lagi komentar yang tersedia dari API.\n",
"6. Akhirnya, fungsi ini mengembalikan daftar semua komentar dan balasan yang diambil."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2ZZE0yyiRkPX"
},
"source": [
"Jalankan Proses Crawling"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "aBY9EfqCRonZ",
"outputId": "5620f8a1-b744-4709-95c1-518babfb9074"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Jumlah data tersimpan sebanyak : 733\n"
]
}
],
"source": [
"# isikan dengan api key\n",
"api_key = 'AIzaSyAMI_-dwhG68ig3Xu6FRbOKAbFySTYBemE'\n",
"\n",
"# Enter video id\n",
"# contoh url video = https://youtu.be/2xWpbjWp1Qc?si=JtdpvjKImgsWce7Y\n",
"video_id = \"2xWpbjWp1Qc\" #isikan dengan kode_/ ID video\n",
"\n",
"# Tentukan jumlah data yang akan diambil (misalnya 500)\n",
"jumlah_data = 871\n",
"\n",
"# Call function dengan jumlah data yang ditentukan\n",
"comments= video_comments(video_id, jumlah_data)\n",
"\n",
"# cek data tersimpan\n",
"print(f\"Jumlah data tersimpan sebanyak : {len(comments)}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "93e9e68e"
},
"source": [
"## Cara Mendapatkan YouTube Data API v3 Key\n",
"\n",
"Untuk mendapatkan API Key YouTube Data API v3, ikuti langkah-langkah berikut:\n",
"\n",
"1. **Masuk ke Google Cloud Console**: Buka [Google Cloud Console](https://console.cloud.google.com/) dan masuk dengan akun Google Anda.\n",
"\n",
"2. **Buat Proyek Baru (atau Pilih yang Sudah Ada)**:\n",
" * Di bagian atas halaman, klik pada dropdown pemilihan proyek (biasanya menampilkan nama proyek atau 'My First Project').\n",
" * Klik 'New Project' dan ikuti instruksi untuk membuat proyek baru. Beri nama proyek yang mudah Anda ingat, misalnya 'YouTube API Project'.\n",
" * Jika Anda sudah memiliki proyek, Anda bisa memilihnya.\n",
"\n",
"3. **Aktifkan YouTube Data API v3**:\n",
" * Setelah proyek Anda dipilih, gunakan menu navigasi di sebelah kiri (ikon tiga garis horizontal).\n",
" * Pilih 'APIs & Services' > 'Enabled APIs & Services'.\n",
" * Klik '+ ENABLE APIS AND SERVICES' di bagian atas.\n",
" * Cari 'YouTube Data API v3' di kotak pencarian, klik pada hasilnya, lalu klik tombol 'ENABLE'.\n",
"\n",
"4. **Buat Kredensial API Key**:\n",
" * Setelah API diaktifkan, kembali ke 'APIs & Services' > 'Credentials' dari menu navigasi kiri.\n",
" * Klik '+ CREATE CREDENTIALS' > 'API Key'.\n",
" * Sebuah pop-up akan muncul yang menampilkan API Key Anda. Salin kunci ini.\n",
"\n",
"5. **Batasi API Key (Disarankan)**:\n",
" * **Penting**: Untuk keamanan, sangat disarankan untuk membatasi API Key Anda agar hanya dapat digunakan oleh aplikasi atau situs web tertentu.\n",
" * Di halaman 'Credentials', klik pada API Key yang baru Anda buat.\n",
" * Di bagian 'Application restrictions', pilih 'IP addresses (web servers, cron jobs, etc.)' atau 'HTTP referrers (web sites)' tergantung di mana Anda akan menggunakan kunci ini. Jika ini untuk Colab, membatasi berdasarkan IP tidak praktis. Untuk penggunaan pribadi atau pengujian di Colab, Anda mungkin membiarkannya tidak dibatasi sementara, tetapi **jangan pernah menggunakan API Key yang tidak dibatasi untuk aplikasi produksi**.\n",
" * Di bagian 'API restrictions', pilih 'Restrict key' dan pilih 'YouTube Data API v3' dari daftar dropdown. Ini memastikan kunci hanya bisa digunakan untuk API tersebut.\n",
" * Klik 'SAVE'.\n",
"\n",
"Sekarang memiliki API Key yang dapat digunakan dalam kode Python untuk mengakses YouTube Data API v3. Ganti placeholder `api_key = 'AIzaSyAMI_-dwhG68ig3Xu6FRbOKAbFySTYBemE'` di kode ini dengan API Key yang baru didapatkan."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "18103321"
},
"source": [
"**Sel ini menjalankan proses _crawling_ komentar.**\n",
"\n",
"1. `api_key = 'AIzaSyAMI_-dwhG68ig3Xu6FRbOKAbFySTYBemE'`: Menginisialisasi variabel `api_key` dengan kunci API YouTube Anda. Kunci ini diperlukan untuk mengautentikasi permintaan ke YouTube Data API.\n",
"2. `video_id = \"juDZOuchgR8\"`: Menentukan ID video YouTube yang ingin diambil komentarnya. Anda dapat mengubah nilai ini untuk menargetkan video lain.\n",
"3. `jumlah_data = 61`: Menentukan jumlah komentar maksimum yang ingin diambil.\n",
"4. `comments = video_comments(video_id, jumlah_data)`: Memanggil fungsi `video_comments` yang telah didefinisikan sebelumnya, meneruskan `video_id` dan `jumlah_data` sebagai argumen. Hasil (daftar komentar) disimpan dalam variabel `comments`.\n",
"5. `print(f\"Jumlah data tersimpan sebanyak : {len(comments)}\")`: Mencetak jumlah total komentar yang berhasil diambil dan disimpan dalam daftar `comments`."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "nJCQ-jsISIPM"
},
"source": [
"Ubah Hasil Crawling ke DataFrame"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 597
},
"id": "MK3ib_AYZ2Yh",
"outputId": "650b463c-1847-4750-e5a1-7788e5173c01"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
".. ... ... \n",
"728 2025-05-30T15:41:10Z @Megawator \n",
"729 2025-05-30T15:41:08Z @alghanimuhammadarraafi \n",
"730 2025-05-30T15:41:05Z @ajayfajar-i8f \n",
"731 2025-05-30T15:41:04Z @Aexelj \n",
"732 2025-05-30T15:41:00Z @nauvalakbar2493 \n",
"\n",
" Comment LikeCount \n",
"0 pemerintah buta dan tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 Indonesia itu bangsa yang besar, namun bukan b... 0 \n",
"3 Datang yuk,suasananya cozy banget 🐍💜 R͓̽o͓̽m͓̽... 0 \n",
"4 Cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
".. ... ... \n",
"728 haii 0 \n",
"729 12 dtk 😁 2 \n",
"730 PERTAMA DAPET APA BANG 0 \n",
"731 Woyyy 2 \n",
"732 Orang pertama 1 \n",
"\n",
"[733 rows x 4 columns]"
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta dan tuli
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
Indonesia itu bangsa yang besar, namun bukan b...
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
Datang yuk,suasananya cozy banget 🐍💜 R͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
Cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
\n",
"
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
...
\n",
"
\n",
"
\n",
"
728
\n",
"
2025-05-30T15:41:10Z
\n",
"
@Megawator
\n",
"
haii
\n",
"
0
\n",
"
\n",
"
\n",
"
729
\n",
"
2025-05-30T15:41:08Z
\n",
"
@alghanimuhammadarraafi
\n",
"
12 dtk 😁
\n",
"
2
\n",
"
\n",
"
\n",
"
730
\n",
"
2025-05-30T15:41:05Z
\n",
"
@ajayfajar-i8f
\n",
"
PERTAMA DAPET APA BANG
\n",
"
0
\n",
"
\n",
"
\n",
"
731
\n",
"
2025-05-30T15:41:04Z
\n",
"
@Aexelj
\n",
"
Woyyy
\n",
"
2
\n",
"
\n",
"
\n",
"
732
\n",
"
2025-05-30T15:41:00Z
\n",
"
@nauvalakbar2493
\n",
"
Orang pertama
\n",
"
1
\n",
"
\n",
" \n",
"
\n",
"
733 rows × 4 columns
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
" \n",
" \n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 725,\n \"samples\": [\n \"Out of topic, tapi saya cuma mau bilang kepada kalian yang bekerja di balik channel kok bisa ini selalu semangat ya, jangan berhenti menebarkan ilmu pengetahuan. Saya suka banget sama video video kok bisa, selalu jadi tontonan kalo mau makan atau sebelum tidur, dari dulu saya masih sd pinjem hp mama buat nonton bahkan sampe sekarang saya udah sma. Kontennya asik buat ditonton, dengan animasinya yang simpel tapi bisa bikin penonton lebih paham, penjelasannya enak buat didenger, pokoknya mudah dimengerti deh!! Dan setiap nonton kok bisa saya jadi makin penasaran sama ilmu, memotivasi saya buat mau belajar lebih, penasaran sama hal hal yang bahkan simpel yang ada di sekitar, rasanya kyk bisa mengerti gimana dunia ini bekerja wkwkkw dan ini bikin belajar jadi menyenangkan\\ud83d\\ude01\\ud83d\\ude01\\ud83d\\ude01\\ud83d\\ude01 Intinya saya apresiasi sekali channel ini\\u2764\\u2764\\u2764\",\n \"Baru tau ternyata ada rencana seperti itu\",\n \"Gara2 lu sih gblk karna mengidolakan jokowi\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 8
}
],
"source": [
"df = pd.DataFrame(comments, columns=['Date','UserName', 'Comment', 'LikeCount'])\n",
"df"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "398cc161"
},
"source": [
"**Sel ini mengubah hasil _crawling_ (daftar komentar) menjadi DataFrame pandas.**\n",
"\n",
"1. `df = pd.DataFrame(comments, columns=['Date', 'UserName', 'Comment'])`: Mengonversi daftar `comments` menjadi DataFrame pandas. Daftar `comments` diharapkan berisi sub-daftar untuk setiap komentar, dan kolom-kolomnya diberi nama 'Date', 'UserName', dan 'Comment' secara berurutan.\n",
"2. `df`: Menampilkan DataFrame `df` yang baru dibuat. Ini memungkinkan Anda untuk melihat data komentar dalam format tabel yang terstruktur."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "tqbJrx4fbauX"
},
"source": [
"Simpan Hasil Crawling ke Csv"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "f74895fe",
"outputId": "0ddf5cf1-382b-4636-b9a2-854fc95a6772"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"\n",
" async function download(id, filename, size) {\n",
" if (!google.colab.kernel.accessAllowed) {\n",
" return;\n",
" }\n",
" const div = document.createElement('div');\n",
" const label = document.createElement('label');\n",
" label.textContent = `Downloading \"${filename}\": `;\n",
" div.appendChild(label);\n",
" const progress = document.createElement('progress');\n",
" progress.max = size;\n",
" div.appendChild(progress);\n",
" document.body.appendChild(div);\n",
"\n",
" const buffers = [];\n",
" let downloaded = 0;\n",
"\n",
" const channel = await google.colab.kernel.comms.open(id);\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
"\n",
" for await (const message of channel.messages) {\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
" if (message.buffers) {\n",
" for (const buffer of message.buffers) {\n",
" buffers.push(buffer);\n",
" downloaded += buffer.byteLength;\n",
" progress.value = downloaded;\n",
" }\n",
" }\n",
" }\n",
" const blob = new Blob(buffers, {type: 'application/binary'});\n",
" const a = document.createElement('a');\n",
" a.href = window.URL.createObjectURL(blob);\n",
" a.download = filename;\n",
" div.appendChild(a);\n",
" a.click();\n",
" div.remove();\n",
" }\n",
" "
]
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"download(\"download_2b0baaa9-7dc9-4554-a2f4-9a6c0087a604\", \"youtube-comments-Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?.csv\", 118513)"
]
},
"metadata": {}
}
],
"source": [
"from google.colab import files\n",
"\n",
"# Define the filename to ensure consistency\n",
"csv_filename = 'youtube-comments-Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?.csv'\n",
"\n",
"# Save the DataFrame to a CSV file\n",
"df.to_csv(csv_filename, index=False)\n",
"\n",
"# Download the newly created CSV file\n",
"files.download(csv_filename)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "c2a1a4cb"
},
"source": [
"**Sel ini menyimpan DataFrame hasil _crawling_ ke dalam file CSV.**\n",
"\n",
"* `from google.colab import files`:Mengimpor modul files dari google.colab yang diperlukan untuk fungsionalitas pengunduhan.\n",
"* `csv_filename = 'youtube-comments-LompatanTeknologiInternet5GMenuju 6G,IndonesiaSudahSiap?.csv'`: Mendefinisikan nama file CSV yang akan digunakan untuk memastikan konsistensi antara proses penyimpanan dan pengunduhan.\n",
"* `df.to_csv('youtube-comments-LompatanTeknologiInternet5GMenuju 6G,IndonesiaSudahSiap?.csv', index=False)`: Menyimpan DataFrame `df` ke dalam sebuah file CSV dengan nama `'youtube-comments-LompatanTeknologiInternet5GMenuju 6G,IndonesiaSudahSiap?.csv'`. Argumen `index=False` memastikan bahwa indeks DataFrame tidak ditulis sebagai kolom terpisah dalam file CSV."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "olUVhQ7pufom"
},
"source": [
"PREPROCESSING COMENTAR"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "9deb2e72"
},
"source": [
"Mengubah semua teks komentar dalam DataFrame menjadi huruf kecil (lowercase) untuk memastikan konsistensi dan mempersiapkan data untuk analisis lebih lanjut."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 293
},
"id": "a9ee0d25",
"outputId": "fc8d8510-98c8-4efb-cbf0-abb991032b6a"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \n",
"0 pemerintah buta dan tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia itu bangsa yang besar, namun bukan b... 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta dan tuli
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia itu bangsa yang besar, namun bukan b...
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk dengan pekerjaannya dan lebih sering main hp di banding bersosial makin modern makin banyak orng yg ngalamin masalah mental dampaknya bukan ke lingkungan aja ke kesehatan mental dan fisik juga sama\",\n \"ya gitulah, omongan oposisi memang selalu terdengar keren. \\ud83d\\ude05\",\n \"ga pernah pengen nangis nonton kok bisa, baru ini rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 10
}
],
"source": [
"import pandas as pd\n",
"from googleapiclient.discovery import build\n",
"\n",
"# Define the video_comments function (from cell PWtT41aaD6mP)\n",
"def video_comments(video_id, max_results=100):\n",
" replies = []\n",
" youtube = build('youtube', 'v3', developerKey=api_key)\n",
" video_response = youtube.commentThreads().list(\n",
" part='snippet,replies',\n",
" videoId=video_id,\n",
" maxResults=min(max_results, 100)\n",
" ).execute()\n",
" comment_count = 0\n",
" while video_response and comment_count < max_results:\n",
" for item in video_response['items']:\n",
" published = item['snippet']['topLevelComment']['snippet']['publishedAt']\n",
" user = item['snippet']['topLevelComment']['snippet']['authorDisplayName']\n",
" comment = item['snippet']['topLevelComment']['snippet']['textDisplay']\n",
" likeCount = item['snippet']['topLevelComment']['snippet']['likeCount']\n",
" replies.append([published, user, comment, likeCount])\n",
" comment_count += 1\n",
" replycount = item['snippet']['totalReplyCount']\n",
" if replycount > 0:\n",
" for reply in item['replies']['comments']:\n",
" published = reply['snippet']['publishedAt']\n",
" user = reply['snippet']['authorDisplayName']\n",
" repl = reply['snippet']['textDisplay']\n",
" likeCount = reply['snippet']['likeCount']\n",
" replies.append([published, user, repl, likeCount])\n",
" comment_count += 1\n",
" if comment_count >= max_results:\n",
" break\n",
" if comment_count >= max_results:\n",
" break\n",
" if 'nextPageToken' in video_response and comment_count < max_results:\n",
" video_response = youtube.commentThreads().list(\n",
" part = 'snippet,replies',\n",
" pageToken = video_response['nextPageToken'],\n",
" videoId = video_id,\n",
" maxResults=min(max_results - comment_count, 100)\n",
" ).execute()\n",
" else:\n",
" break\n",
" return replies\n",
"\n",
"# Initialize variables and call the function to get comments (from cell aBY9EfqCRonZ)\n",
"api_key = 'AIzaSyAMI_-dwhG68ig3Xu6FRbOKAbFySTYBemE'\n",
"video_id = \"2xWpbjWp1Qc\"\n",
"jumlah_data = 871\n",
"comments = video_comments(video_id, jumlah_data)\n",
"\n",
"# Create the DataFrame (from cell MK3ib_AYZ2Yh)\n",
"df = pd.DataFrame(comments, columns=['Date','UserName', 'Comment', 'LikeCount'])\n",
"\n",
"# Perform the case folding operation\n",
"df['Comment'] = df['Comment'].str.lower()\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "db9203d0"
},
"source": [
"## Normalisasi Kata\n",
"\n",
"\n",
"Mengidentifikasi dan mengganti kata-kata tidak baku dalam komentar menjadibentuk bakunya sesuai KBBI."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "e5baf35f"
},
"source": [
"Untuk melakukan normalisasi kata, kita akan mengikuti langkah-langkah berikut:\n",
"1. **Membuat Kamus Normalisasi**: Mendefinisikan sebuah kamus Python (`dictionary`) yang berisi pasangan kata tidak baku (sebagai kunci) dan kata bakunya (sebagai nilai).\n",
"2. **Mendefinisikan Fungsi Normalisasi**: Membuat fungsi yang akan memproses teks komentar, memisahkan kata-kata, dan mengganti setiap kata tidak baku yang ditemukan dengan bentuk bakunya dari kamus.\n",
"3. **Menerapkan Fungsi ke DataFrame**: Mengaplikasikan fungsi normalisasi ini ke kolom 'Comment' dalam DataFrame `df` untuk mengubah semua komentar secara inplace."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "20669724",
"outputId": "0875eeac-2545-46ba-f31d-8354432faa7c"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Kamus normalisasi kata tidak baku ke baku telah dibuat.\n"
]
}
],
"source": [
"kata_tidak_baku_ke_baku = {\n",
" 'yg': 'yang',\n",
" 'udah': 'sudah',\n",
" 'ga': 'tidak',\n",
" 'gak': 'tidak',\n",
" 'bgt': 'banget',\n",
" 'bikin': 'membuat',\n",
" 'nggak': 'tidak',\n",
" 'aja': 'saja',\n",
" 'skrg': 'sekarang',\n",
" 'krn': 'karena',\n",
" 'dgn': 'dengan',\n",
" 'spt': 'seperti',\n",
" 'tp': 'tapi',\n",
" 'tau': 'tahu',\n",
" 'udh': 'sudah',\n",
" 'dlm': 'dalam',\n",
" 'jg': 'juga',\n",
" 'dr': 'dari',\n",
" 'jd': 'jadi',\n",
" 'klo': 'kalau',\n",
" 'blm': 'belum',\n",
" 'doang': 'saja'\n",
"}\n",
"\n",
"print(\"Kamus normalisasi kata tidak baku ke baku telah dibuat.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "4393ace7",
"outputId": "cc999529-37e9-451c-b9eb-dfc2e4054333"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fungsi 'normalize_text' telah didefinisikan.\n"
]
}
],
"source": [
"def normalize_text(text):\n",
" words = text.split()\n",
" normalized_words = [kata_tidak_baku_ke_baku.get(word, word) for word in words]\n",
" return ' '.join(normalized_words)\n",
"\n",
"print(\"Fungsi 'normalize_text' telah didefinisikan.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 293
},
"id": "2c3decfa",
"outputId": "f182a857-b472-4239-f4cd-171457cfddef"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \n",
"0 pemerintah buta dan tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia itu bangsa yang besar, namun bukan b... 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta dan tuli
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia itu bangsa yang besar, namun bukan b...
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk dengan pekerjaannya dan lebih sering main hp di banding bersosial makin modern makin banyak orng yang ngalamin masalah mental dampaknya bukan ke lingkungan saja ke kesehatan mental dan fisik juga sama\",\n \"ya gitulah, omongan oposisi memang selalu terdengar keren. \\ud83d\\ude05\",\n \"tidak pernah pengen nangis nonton kok bisa, baru ini rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 13
}
],
"source": [
"df['Comment'] = df['Comment'].apply(normalize_text)\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1892f45b"
},
"source": [
"## Penghapusan Stopword\n",
"\n",
"### Subtask:\n",
"Menghapus kata-kata yang sering muncul namun tidak memiliki nilai informasi yang signifikan (stopwords) dari setiap komentar menggunakan daftar stopword bahasa Indonesia.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7f9da20f",
"outputId": "551a6508-6e13-4642-c1b2-91c9ea814d39"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Daftar stopword bahasa Indonesia telah dibuat.\n"
]
}
],
"source": [
"indonesian_stopwords = set([\n",
" \"yang\", \"untuk\", \"pada\", \"ke\", \"para\", \"namun\", \"menurut\", \"tentang\", \"dengan\", \"dari\",\n",
" \"ini\", \"itu\", \"adalah\", \"akan\", \"atau\", \"dan\", \"dalam\", \"di\", \"bisa\", \"bukan\",\n",
" \"tidak\", \"sebagai\", \"jika\", \"guna\", \"oleh\", \"serta\", \"tanpa\", \"ada\", \"agar\", \"bagi\",\n",
" \"bahwa\", \"belum\", \"bahkan\", \"beberapa\", \"banyak\", \"bila\", \"dahulu\", \"demi\", \"demikian\", \"depan\",\n",
" \"disini\", \"dimana\", \"ia\", \"ialah\", \"ingin\", \"jangan\", \"juga\", \"kali\", \"kami\", \"kamu\",\n",
" \"karena\", \"kapan\", \"kemana\", \"kemarin\", \"kepada\", \"kini\", \"kita\", \"lah\", \"lain\", \"lalu\",\n",
" \"lebih\", \"maka\", \"mana\", \"masih\", \"memang\", \"mereka\", \"musti\", \"nanti\", \"nya\", \"oleh\",\n",
" \"pada\", \"paling\", \"pastilah\", \"perlu\", \"pun\", \"saat\", \"saja\", \"sambil\", \"sana\", \"sangat\",\n",
" \"sekarang\", \"seluruh\", \"semua\", \"sementara\", \"seperti\", \"sudah\", \"sudah\", \"sungguh\", \"tadi\", \"tampak\",\n",
" \"terlalu\", \"tetap\", \"tiap\", \"tunjuk\", \"untuk\", \"walau\", \"waktu\", \"seandainya\", \"sebab\", \"setelah\",\n",
" \"setiap\", \"siapapun\", \"sebagian\", \"sebaliknya\", \"sekalian\", \"sekalipun\", \"sekitar\", \"selama\", \"selesai\", \"semata\",\n",
" \"semula\", \"seolah\", \"sepertinya\", \"sesudah\", \"sesungguhnya\", \"setinggi\", \"setiap\", \"setidaknya\", \"siapa\", \"sudah\",\n",
" \"tadi\", \"tanpa\", \"telah\", \"tentu\", \"terhadap\", \"terdiri\", \"terlalu\", \"tersebut\", \"terutama\", \"tetap\",\n",
" \"tiada\", \"tiap\", \"tua\", \"turut\", \"umumnya\", \"yakni\", \"yaitu\"\n",
"])\n",
"print(\"Daftar stopword bahasa Indonesia telah dibuat.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "1a3638bf",
"outputId": "19c3a99c-4363-48b3-b465-057d4c6ac890"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fungsi 'remove_stopwords' telah didefinisikan.\n"
]
}
],
"source": [
"def remove_stopwords(text):\n",
" words = text.split()\n",
" filtered_words = [word for word in words if word not in indonesian_stopwords]\n",
" return ' '.join(filtered_words)\n",
"\n",
"print(\"Fungsi 'remove_stopwords' telah didefinisikan.\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 293
},
"id": "6aa86fea",
"outputId": "8afe3e05-fe19-43e0-c570-000033b82827"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 16
}
],
"source": [
"df['Comment'] = df['Comment'].apply(remove_stopwords)\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "b0ed8b2c"
},
"source": [
"## Tampilkan Data Setelah Preprocessing\n",
"\n",
"### Subtask:\n",
"Menampilkan sebagian kecil dari DataFrame setelah semua langkah preprocessing (case folding, normalisasi, dan penghapusan stopword) selesai dilakukan untuk memverifikasi perubahan.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 293
},
"id": "9dc4dbc4",
"outputId": "ee5f03b2-469f-489c-fa90-2a5c67349bf6"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 17
}
],
"source": [
"df.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "d4f43b3a",
"outputId": "319cb329-9311-4e33-dfe0-e77ebc7fb7e0"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"\n",
" async function download(id, filename, size) {\n",
" if (!google.colab.kernel.accessAllowed) {\n",
" return;\n",
" }\n",
" const div = document.createElement('div');\n",
" const label = document.createElement('label');\n",
" label.textContent = `Downloading \"${filename}\": `;\n",
" div.appendChild(label);\n",
" const progress = document.createElement('progress');\n",
" progress.max = size;\n",
" div.appendChild(progress);\n",
" document.body.appendChild(div);\n",
"\n",
" const buffers = [];\n",
" let downloaded = 0;\n",
"\n",
" const channel = await google.colab.kernel.comms.open(id);\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
"\n",
" for await (const message of channel.messages) {\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
" if (message.buffers) {\n",
" for (const buffer of message.buffers) {\n",
" buffers.push(buffer);\n",
" downloaded += buffer.byteLength;\n",
" progress.value = downloaded;\n",
" }\n",
" }\n",
" }\n",
" const blob = new Blob(buffers, {type: 'application/binary'});\n",
" const a = document.createElement('a');\n",
" a.href = window.URL.createObjectURL(blob);\n",
" a.download = filename;\n",
" div.appendChild(a);\n",
" a.click();\n",
" div.remove();\n",
" }\n",
" "
]
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"download(\"download_287c0d81-4084-4c8e-8547-62dcd4218943\", \"Preprocessing_komentar_youtube.csv\", 103161)"
]
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"DataFrame berhasil disimpan dan diunduh sebagai 'Preprocessing_komentar_youtube.csv'\n"
]
}
],
"source": [
"from google.colab import files\n",
"\n",
"# Define the filename according to the instruction, replace NIM and NAMA\n",
"csv_filename_preprocessed = 'Preprocessing_komentar_youtube.csv' # IMPORTANT: Replace NIM and NAMA with actual values\n",
"\n",
"# Save the DataFrame to a CSV file without the index\n",
"df.to_csv(csv_filename_preprocessed, index=False)\n",
"\n",
"# Download the newly created CSV file\n",
"files.download(csv_filename_preprocessed)\n",
"print(f\"DataFrame berhasil disimpan dan diunduh sebagai '{csv_filename_preprocessed}'\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "df9709fa"
},
"source": [
"#Leksikon Sentimen"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "29e39e4e"
},
"source": [
"## Persiapan Lexicon Sentimen\n",
"Membuat atau memuat kamus leksikon sentimen yang berisi daftar kata positif dan negatif dalam Bahasa Indonesia."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "d7bea6b9",
"outputId": "198604ee-0565-41a0-ae98-e3bd8cc7d6f2"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Lexicon sentimen (positive_words dan negative_words) telah dibuat.\n"
]
}
],
"source": [
"positive_words = [\n",
" 'baik', 'bagus', 'hebat', 'luar biasa', 'senang', 'cinta', 'suka', 'menarik',\n",
" 'positif', 'berhasil', 'sukses', 'optimis', 'gembira', 'bahagia', 'antusias',\n",
" 'damai', 'tenang', 'memuaskan', 'sempurna', 'unggul', 'istimewa', 'rajin',\n",
" 'setia', 'jujur', 'bijak', 'pintar', 'cerdas', 'tepat', 'benar', 'terbaik',\n",
" 'efektif', 'produktif', 'maju', 'berkembang', 'solutif', 'kreatif', 'inovatif'\n",
"]\n",
"\n",
"negative_words = [\n",
" 'buruk', 'jelek', 'gagal', 'mengecewakan', 'sedih', 'benci', 'tidak suka', 'membosankan',\n",
" 'negatif', 'rugi', 'mundur', 'pesimis', 'marah', 'kecewa', 'khawatir', 'busuk',\n",
" 'resah', 'cemas', 'menjengkelkan', 'buruk', 'parah', 'gila', 'malas',\n",
" 'bodoh', 'salah', 'keliru', 'payah', 'lemah', 'gagal', 'masalah',\n",
" 'kritik', 'sulit', 'berat', 'menurun', 'lambat', 'korup', 'curang', 'bohong'\n",
"]\n",
"\n",
"print(\"Lexicon sentimen (positive_words dan negative_words) telah dibuat.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "18815893"
},
"source": [
"## Penghitungan Skor Sentimen\n",
"Untuk setiap komentar, hitung skor sentimen dengan menjumlahkan frekuensi kata-kata positif dan negatif yang ditemukan dalam kamus leksikon. Kata-kata positif akan menambah skor, sementara kata-kata negatif akan mengurangi skor."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 380
},
"id": "e79dac97",
"outputId": "450dd45c-da15-4a03-8160-feede98b5981"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score \n",
"0 0 \n",
"1 0 \n",
"2 1 \n",
"3 0 \n",
"4 0 "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
Sentiment_Score
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
0
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
1
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
0
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
0
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": -2,\n \"max\": 8,\n \"num_unique_values\": 7,\n \"samples\": [\n 0,\n 1,\n 3\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 20
}
],
"source": [
"def calculate_sentiment_score(comment_text):\n",
" score = 0\n",
" words = comment_text.split() # Split the comment into words\n",
" for word in words:\n",
" if word in positive_words:\n",
" score += 1\n",
" elif word in negative_words:\n",
" score -= 1\n",
" return score\n",
"\n",
"# Apply the function to the 'Comment' column and create a new 'Sentiment_Score' column\n",
"df['Sentiment_Score'] = df['Comment'].apply(calculate_sentiment_score)\n",
"\n",
"# Display the DataFrame with the new sentiment scores\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "55950761"
},
"source": [
"## Klasifikasi Sentimen\n",
"Mengklasifikasikan setiap komentar ke dalam kategori sentimen (Positif, Negatif, atau Netral) berdasarkan `Sentiment_Score` yang telah dihitung.\n",
"\n",
"#### Instructions\n",
"1. Definisikan sebuah fungsi, misalnya `classify_sentiment`, yang menerima `score` sebagai input.\n",
"2. Di dalam fungsi, gunakan logika berikut untuk mengembalikan label sentimen:\n",
" a. Jika `score` > 0, kembalikan 'Positif'.\n",
" b. Jika `score` < 0, kembalikan 'Negatif'.\n",
" c. Jika `score` == 0, kembalikan 'Netral'.\n",
"3. Terapkan fungsi `classify_sentiment` ke kolom 'Sentiment_Score' di DataFrame `df` dan simpan hasilnya dalam kolom baru bernama 'Sentiment_Label'.\n",
"4. Tampilkan lima baris pertama dari DataFrame `df` untuk memverifikasi penambahan kolom 'Sentiment_Label'."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 400
},
"id": "0d762b0c",
"outputId": "1135cb7c-27b2-432c-eec4-b7559f8d0790"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score Sentiment_Label \n",
"0 0 Netral \n",
"1 0 Netral \n",
"2 1 Positif \n",
"3 0 Netral \n",
"4 0 Netral "
],
"text/html": [
"\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": -2,\n \"max\": 8,\n \"num_unique_values\": 7,\n \"samples\": [\n 0,\n 1,\n 3\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Label\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Netral\",\n \"Positif\",\n \"Negatif\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 22
}
],
"source": [
"df.head()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 52
},
"id": "hCbrPC7SEQC-",
"outputId": "8bc757b0-28af-44c4-d6b4-8475be13f3f7"
},
"outputs": [
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"\n",
" async function download(id, filename, size) {\n",
" if (!google.colab.kernel.accessAllowed) {\n",
" return;\n",
" }\n",
" const div = document.createElement('div');\n",
" const label = document.createElement('label');\n",
" label.textContent = `Downloading \"${filename}\": `;\n",
" div.appendChild(label);\n",
" const progress = document.createElement('progress');\n",
" progress.max = size;\n",
" div.appendChild(progress);\n",
" document.body.appendChild(div);\n",
"\n",
" const buffers = [];\n",
" let downloaded = 0;\n",
"\n",
" const channel = await google.colab.kernel.comms.open(id);\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
"\n",
" for await (const message of channel.messages) {\n",
" // Send a message to notify the kernel that we're ready.\n",
" channel.send({})\n",
" if (message.buffers) {\n",
" for (const buffer of message.buffers) {\n",
" buffers.push(buffer);\n",
" downloaded += buffer.byteLength;\n",
" progress.value = downloaded;\n",
" }\n",
" }\n",
" }\n",
" const blob = new Blob(buffers, {type: 'application/binary'});\n",
" const a = document.createElement('a');\n",
" a.href = window.URL.createObjectURL(blob);\n",
" a.download = filename;\n",
" div.appendChild(a);\n",
" a.click();\n",
" div.remove();\n",
" }\n",
" "
]
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"application/javascript": [
"download(\"download_97262360-2875-44aa-a403-4aeb1d43aa2c\", \"LexiconSentiment_komentar_youtube.csv\", 109951)"
]
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"DataFrame berhasil disimpan dan diunduh sebagai 'LexiconSentiment_komentar_youtube.csv'\n"
]
}
],
"source": [
"from google.colab import files\n",
"\n",
"# Define the filename according to the instruction, replace NIM and NAMA\n",
"csv_filename_preprocessed = 'LexiconSentiment_komentar_youtube.csv'\n",
"\n",
"# Save the DataFrame to a CSV file without the index\n",
"df.to_csv(csv_filename_preprocessed, index=False)\n",
"\n",
"# Download the newly created CSV file\n",
"files.download(csv_filename_preprocessed)\n",
"print(f\"DataFrame berhasil disimpan dan diunduh sebagai '{csv_filename_preprocessed}'\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bea4e21a"
},
"source": [
"# Task\n",
"Improve the sentiment analysis of YouTube comments by extracting and utilizing the InSet lexicon from the `InSet-master.zip` file, enhancing preprocessing to remove noise words like 'br' and 'quot', and then re-evaluating the sentiment distribution to assess the impact of these changes."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "286e1fba"
},
"source": [
"## Extract InSet Lexicon\n",
"\n",
"### Subtask:\n",
"Extract the contents of the `InSet-master.zip` file to access the lexicon files. This step will make the positive and negative word lists from InSet available for use.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "799b5d29"
},
"source": [
"**Reasoning**:\n",
"To extract the contents of the InSet-master.zip file, I will use the zipfile module to open and extract the archive into a new directory, ensuring the lexicon files are accessible for further use.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "b3a58f14",
"outputId": "b1ac2599-e6cc-40ea-8c7f-4dbb8e7bae9f"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Contents of '/content/InSet-master (1).zip' extracted to '/content/InSet_extracted'.\n",
"Loaded 3610 raw positive words from InSet lexicon.\n",
"Loaded 6610 raw negative words from InSet lexicon.\n",
"Updated positive_words list contains 3609 words.\n",
"Updated negative_words list contains 6609 words.\n",
"Sentiment scores and labels recalculated with InSet lexicon.\n",
"\n",
"Most Liked Comment (Likes: 2021):\n",
"membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\n",
"Sentiment of Most Liked Comment: Positif\n",
"\n",
"Analyzing sentiment contribution for the most liked comment:\n",
"Original Comment: membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\n",
"Total Sentiment Score: 14\n",
"Sentiment Label: Positif\n",
"\n",
"Words contributing Positively (41): hatiku, buat, aku, aku, penjelasan, penting, guru, jawab, aku, sebenarnya, aku, aku, diajak, melalui, karya, aku, sering, membuat, aku, membuat, aku, punya, membuat, aku, setuju, siswa, boleh, sesuai, siswa, baca, siswa, solusi, sampai, sekolah, jujur, lingkungan, lihat, jujur, bentuk, kepedulian, alam\n",
"Words contributing Negatively (27): membekas, sendiri, sistem, apa, meski, sembarangan, harus, meski, sendiri, katanya, sistem, harus, mencari, semuanya, hanya, mengerjakan, sendiri, berita, korupsi, datang, masalah, buang, sampah, sembarangan, malas, harus, saya\n",
"Words not in lexicon (Neutral) (111): 'malu', menjadi, warga, negara, indonesia, pengalamanku, menempuh, pendidikan, sma., risih, pendidikan, berkutit, hafalan., "mengapa, hal, terjadi", "apa, terapkan, kehidupan, sehari-hari"., hafalin, diomongin, buku,, lembar, ujian., baru, merasakan, pendidikan, ketika, bangku, kuliah,, tepatnya, mengambil, jurusan, dkv., disana, berpikir, menumpahkan, ide-ideku, desain., karya,, karya., dasardalam, suatu, karya., kuliah,, kurikulum, merdeka,, 'belajar', passion., al, hasil,, smp, apalagi, berhitung., intinya,, pendidikan, dirancang, memancing, berpikir, kehidupan, nyata., sekarang,, mengajar, bagaimana, menjadi, orang, dipercaya,, bagaimana, cara, berempati, orang-orang, sekitar,, masiiiihh, sekedar, lembaran, kertas., to., pungli, dimana-mana,, diajarkan, cara, menjadi, orang, dipercaya,, tanah, adat, dirusak, diekploitasi,, investor, dicegat, ormas,, diajarkan, cara, berempati., selain, gerak, sehingga, menggunakan, kendaraan, bermotor,, tawuran, kurangnya, pendidikan, mengenai, sosial., lakukan, dikerjakan, 1, orang, pribadi.\n"
]
}
],
"source": [
"import zipfile\n",
"import os\n",
"import pandas as pd # Ensure pandas is imported\n",
"\n",
"# Define the path to the InSet-master.zip file (assuming it's in /content/)\n",
"# Use the actual uploaded file name from the 'uploaded' dictionary\n",
"zip_file_name = list(uploaded.keys())[0] if 'uploaded' in locals() and uploaded else 'InSet-master.zip' # Fallback\n",
"zip_file_path = os.path.join('/content/', zip_file_name)\n",
"\n",
"# Define the directory where the contents will be extracted\n",
"extract_path = '/content/InSet_extracted'\n",
"\n",
"# Create the extraction directory if it doesn't already exist\n",
"os.makedirs(extract_path, exist_ok=True)\n",
"\n",
"# Open the zip file and extract its contents\n",
"if os.path.exists(zip_file_path):\n",
" try:\n",
" with zipfile.ZipFile(zip_file_path, 'r') as zip_ref:\n",
" zip_ref.extractall(extract_path)\n",
" print(f\"Contents of '{zip_file_path}' extracted to '{extract_path}'.\")\n",
" except Exception as e:\n",
" print(f\"An error occurred during extraction: {e}\")\n",
"else:\n",
" print(f\"Error: The file '{zip_file_path}' was not found. Please ensure it is uploaded.\")\n",
"\n",
"# Corrected paths for InSet lexicon files\n",
"extract_inset_data_path = os.path.join(extract_path, 'InSet-master')\n",
"positive_lexicon_path = os.path.join(extract_inset_data_path, 'positive.tsv')\n",
"negative_lexicon_path = os.path.join(extract_inset_data_path, 'negative.tsv')\n",
"\n",
"# Load positive words\n",
"inset_positive_words = []\n",
"if os.path.exists(positive_lexicon_path):\n",
" with open(positive_lexicon_path, 'r', encoding='utf-8') as f:\n",
" for line in f:\n",
" inset_positive_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Positive lexicon file not found at {positive_lexicon_path}\")\n",
"\n",
"# Load negative words\n",
"inset_negative_words = []\n",
"if os.path.exists(negative_lexicon_path):\n",
" with open(negative_lexicon_path, 'r', encoding='utf-8') as f:\n",
" for line in f:\n",
" inset_negative_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Negative lexicon file not found at {negative_lexicon_path}\")\n",
"\n",
"print(f\"Loaded {len(inset_positive_words)} raw positive words from InSet lexicon.\")\n",
"print(f\"Loaded {len(inset_negative_words)} raw negative words from InSet lexicon.\")\n",
"\n",
"# Clean and update positive_words and negative_words global lists\n",
"positive_words = [word.split('\\t')[0] for word in inset_positive_words if word and word != 'word\\tweight']\n",
"negative_words = [word.split('\\t')[0] for word in inset_negative_words if word and word != 'word\\tweight']\n",
"\n",
"print(f\"Updated positive_words list contains {len(positive_words)} words.\")\n",
"print(f\"Updated negative_words list contains {len(negative_words)} words.\")\n",
"\n",
"# Redefine functions in case kernel reset or not executed\n",
"def calculate_sentiment_score(comment_text):\n",
" score = 0\n",
" words = comment_text.split() # Split the comment into words\n",
" for word in words:\n",
" if word in positive_words:\n",
" score += 1\n",
" elif word in negative_words:\n",
" score -= 1\n",
" return score\n",
"\n",
"def classify_sentiment(score):\n",
" if score > 0:\n",
" return 'Positif'\n",
" elif score < 0:\n",
" return 'Negatif'\n",
" else:\n",
" return 'Netral'\n",
"\n",
"def analyze_comment_sentiment_contribution(comment_text, positive_words_list, negative_words_list):\n",
" score = 0\n",
" positive_contributions = []\n",
" negative_contributions = []\n",
" neutral_words = []\n",
"\n",
" words = comment_text.split()\n",
" for word in words:\n",
" if word in positive_words_list:\n",
" score += 1\n",
" positive_contributions.append(word)\n",
" elif word in negative_words_list:\n",
" score -= 1\n",
" negative_contributions.append(word)\n",
" else:\n",
" neutral_words.append(word)\n",
"\n",
" print(f\"Original Comment: {comment_text}\")\n",
" print(f\"Total Sentiment Score: {score}\")\n",
" print(f\"Sentiment Label: {'Positif' if score > 0 else ('Negatif' if score < 0 else 'Netral')}\")\n",
" print(f\"\\nWords contributing Positively ({len(positive_contributions)}): {', '.join(positive_contributions) if positive_contributions else 'None'}\")\n",
" print(f\"Words contributing Negatively ({len(negative_contributions)}): {', '.join(negative_contributions) if negative_contributions else 'None'}\")\n",
" print(f\"Words not in lexicon (Neutral) ({len(neutral_words)}): {', '.join(neutral_words) if neutral_words else 'None'}\")\n",
"\n",
"# Ensure preprocessing (noise removal) is applied before sentiment calculation\n",
"# df['Comment'] = df['Comment'].apply(remove_noise_words) # Assuming remove_noise_words is defined earlier\n",
"\n",
"# Recalculate sentiment scores with the updated InSet lexicon\n",
"df['Sentiment_Score'] = df['Comment'].apply(calculate_sentiment_score)\n",
"df['Sentiment_Label'] = df['Sentiment_Score'].apply(classify_sentiment)\n",
"\n",
"print(\"Sentiment scores and labels recalculated with InSet lexicon.\")\n",
"\n",
"# Identify the most liked comment (from cell a71c580d)\n",
"most_liked_comment_row = df.loc[df['LikeCount'].idxmax()]\n",
"most_liked_comment_text = most_liked_comment_row['Comment']\n",
"most_liked_comment_sentiment = most_liked_comment_row['Sentiment_Label']\n",
"most_liked_comment_likes = most_liked_comment_row['LikeCount']\n",
"\n",
"print(f\"\\nMost Liked Comment (Likes: {most_liked_comment_likes}):\\n{most_liked_comment_text}\")\n",
"print(f\"Sentiment of Most Liked Comment: {most_liked_comment_sentiment}\")\n",
"\n",
"# Call the sentiment contribution analysis for the most liked comment (from cell a5d130c3)\n",
"print(\"\\nAnalyzing sentiment contribution for the most liked comment:\")\n",
"analyze_comment_sentiment_contribution(most_liked_comment_text, positive_words, negative_words)\n"
]
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 108
},
"id": "3c93a5c8",
"outputId": "8c4284a9-34f3-456f-df4d-24c8c5e4269b"
},
"source": [
"from google.colab import files\n",
"\n",
"print(\"Silakan unggah file InSet-master.zip:\")\n",
"uploaded = files.upload()\n",
"\n",
"for fn in uploaded.keys():\n",
" print('User uploaded file \"{name}\" with length {length} bytes'.format(\n",
" name=fn, length=len(uploaded[fn])))\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Silakan unggah file InSet-master.zip:\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"text/html": [
"\n",
" \n",
" \n",
" "
]
},
"metadata": {}
},
{
"output_type": "stream",
"name": "stdout",
"text": [
"Saving InSet-master.zip to InSet-master (1).zip\n",
"User uploaded file \"InSet-master (1).zip\" with length 47598 bytes\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3c1a864d"
},
"source": [
"Setelah `InSet-master.zip` berhasil diunggah, Anda dapat melanjutkan untuk menjalankan kembali sel `b3a58f14` untuk mengekstrak isinya, lalu sel `abbdf2d2` untuk memuat leksikon, dan seterusnya."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "43397423"
},
"source": [
"## Load InSet Lexicon\n",
"\n",
"### Subtask:\n",
"Load the positive and negative word lists from the extracted InSet files. This will typically involve reading text files that contain one word per line into Python lists.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7acc63e0"
},
"source": [
"**Reasoning**:\n",
"To load the InSet lexicon, I will first define the paths to the positive and negative lexicon files within the extracted directory. Then, I will read each file line by line, stripping whitespace, and store the words in separate lists. Finally, I will print the count of words loaded to confirm the process.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "09bf0753",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "86157c79-4a78-4e5d-e244-a3dba19dcc40"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Warning: Positive lexicon file not found at /content/InSet-master/data/positive.txt\n",
"Warning: Negative lexicon file not found at /content/InSet-master/data/negative.txt\n",
"Loaded 0 positive words from InSet lexicon.\n",
"Loaded 0 negative words from InSet lexicon.\n"
]
}
],
"source": [
"import os\n",
"\n",
"# Define the paths to the positive and negative lexicon files\n",
"extract_path = '/content/InSet-master'\n",
"positive_lexicon_path = os.path.join(extract_path, 'data', 'positive.txt')\n",
"negative_lexicon_path = os.path.join(extract_path, 'data', 'negative.txt')\n",
"\n",
"# Load positive words\n",
"inset_positive_words = []\n",
"if os.path.exists(positive_lexicon_path):\n",
" with open(positive_lexicon_path, 'r') as f:\n",
" for line in f:\n",
" inset_positive_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Positive lexicon file not found at {positive_lexicon_path}\")\n",
"\n",
"# Load negative words\n",
"inset_negative_words = []\n",
"if os.path.exists(negative_lexicon_path):\n",
" with open(negative_lexicon_path, 'r') as f:\n",
" for line in f:\n",
" inset_negative_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Negative lexicon file not found at {negative_lexicon_path}\")\n",
"\n",
"print(f\"Loaded {len(inset_positive_words)} positive words from InSet lexicon.\")\n",
"print(f\"Loaded {len(inset_negative_words)} negative words from InSet lexicon.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0375b21e"
},
"source": [
"### Analisis Kontribusi Sentimen Kata per Kata pada Komentar Paling Disukai"
]
},
{
"cell_type": "code",
"metadata": {
"id": "6efdf836"
},
"source": [
"def analyze_comment_sentiment_contribution(comment_text, positive_words_list, negative_words_list):\n",
" score = 0\n",
" positive_contributions = []\n",
" negative_contributions = []\n",
" neutral_words = []\n",
"\n",
" words = comment_text.split()\n",
" for word in words:\n",
" if word in positive_words_list:\n",
" score += 1\n",
" positive_contributions.append(word)\n",
" elif word in negative_words_list:\n",
" score -= 1\n",
" negative_contributions.append(word)\n",
" else:\n",
" neutral_words.append(word)\n",
"\n",
" print(f\"Original Comment: {comment_text}\")\n",
" print(f\"Total Sentiment Score: {score}\")\n",
" print(f\"Sentiment Label: {'Positif' if score > 0 else ('Negatif' if score < 0 else 'Netral')}\")\n",
" print(f\"\\nWords contributing Positively ({len(positive_contributions)}): {', '.join(positive_contributions) if positive_contributions else 'None'}\")\n",
" print(f\"Words contributing Negatively ({len(negative_contributions)}): {', '.join(negative_contributions) if negative_contributions else 'None'}\")\n",
" print(f\"Words not in lexicon (Neutral) ({len(neutral_words)}): {', '.join(neutral_words) if neutral_words else 'None'}\")\n"
],
"execution_count": null,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "a5d130c3",
"outputId": "45c67cbc-a4d7-4202-e8fa-49e161d1462f"
},
"source": [
"# Panggil fungsi analisis kontribusi sentimen untuk komentar paling disukai\n",
"# Pastikan sel abbdf2d2, 9030a7d0, dan a71c580d telah dijalankan terlebih dahulu\n",
"\n",
"analyze_comment_sentiment_contribution(most_liked_comment_text, positive_words, negative_words)\n"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Original Comment: membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\n",
"Total Sentiment Score: 14\n",
"Sentiment Label: Positif\n",
"\n",
"Words contributing Positively (41): hatiku, buat, aku, aku, penjelasan, penting, guru, jawab, aku, sebenarnya, aku, aku, diajak, melalui, karya, aku, sering, membuat, aku, membuat, aku, punya, membuat, aku, setuju, siswa, boleh, sesuai, siswa, baca, siswa, solusi, sampai, sekolah, jujur, lingkungan, lihat, jujur, bentuk, kepedulian, alam\n",
"Words contributing Negatively (27): membekas, sendiri, sistem, apa, meski, sembarangan, harus, meski, sendiri, katanya, sistem, harus, mencari, semuanya, hanya, mengerjakan, sendiri, berita, korupsi, datang, masalah, buang, sampah, sembarangan, malas, harus, saya\n",
"Words not in lexicon (Neutral) (111): 'malu', menjadi, warga, negara, indonesia, pengalamanku, menempuh, pendidikan, sma., risih, pendidikan, berkutit, hafalan., "mengapa, hal, terjadi", "apa, terapkan, kehidupan, sehari-hari"., hafalin, diomongin, buku,, lembar, ujian., baru, merasakan, pendidikan, ketika, bangku, kuliah,, tepatnya, mengambil, jurusan, dkv., disana, berpikir, menumpahkan, ide-ideku, desain., karya,, karya., dasardalam, suatu, karya., kuliah,, kurikulum, merdeka,, 'belajar', passion., al, hasil,, smp, apalagi, berhitung., intinya,, pendidikan, dirancang, memancing, berpikir, kehidupan, nyata., sekarang,, mengajar, bagaimana, menjadi, orang, dipercaya,, bagaimana, cara, berempati, orang-orang, sekitar,, masiiiihh, sekedar, lembaran, kertas., to., pungli, dimana-mana,, diajarkan, cara, menjadi, orang, dipercaya,, tanah, adat, dirusak, diekploitasi,, investor, dicegat, ormas,, diajarkan, cara, berempati., selain, gerak, sehingga, menggunakan, kendaraan, bermotor,, tawuran, kurangnya, pendidikan, mengenai, sosial., lakukan, dikerjakan, 1, orang, pribadi.\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "f70076b8"
},
"source": [
"### Penjelasan Hasil Analisis\n",
"\n",
"Dari hasil di atas, Anda bisa melihat kata-kata spesifik yang teridentifikasi sebagai positif atau negatif oleh leksikon InSet.\n",
"\n",
"Misalnya, jika ada kata seperti 'solusi', 'percaya', 'baik', 'memancing' dalam leksikon positif, dan kata-kata ini muncul cukup sering dalam komentar, maka skor sentimen akan cenderung positif meskipun komentar tersebut juga mengandung kata-kata yang mengkritik atau menggambarkan masalah.\n",
"\n",
"Ini menunjukkan bahwa leksikon InSet, meskipun lebih komprehensif, mungkin belum sepenuhnya menangkap konteks atau intensitas sentimen dalam kalimat yang lebih kompleks atau panjang. Untuk hasil yang lebih akurat, diperlukan penyesuaian leksikon, penambahan aturan untuk menangani negasi, atau penggunaan model sentimen yang lebih canggih (misalnya, berbasis machine learning atau deep learning) yang dapat memahami konteks kalimat secara lebih baik."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "0d30f450"
},
"source": [
"**Reasoning**:\n",
"The previous attempt to load the InSet lexicon failed because the files were not found at the specified paths. I need to inspect the directory structure of the extracted `InSet-master` folder to locate the correct paths for `positive.txt` and `negative.txt`. A shell command to list the contents of the `InSet-master` directory will help identify the correct subdirectories.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "3e416b59",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "2380f3af-a857-4e83-a3c5-c08a03c4431a"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Contents of /content/InSet_extracted: ['InSet-master']\n",
"Contents of /content/InSet_extracted/InSet-master: ['negative.tsv', 'positive.tsv', 'README.md']\n"
]
}
],
"source": [
"import os\n",
"\n",
"# List the contents of the extracted directory to find the correct paths\n",
"extract_path = '/content/InSet_extracted'\n",
"print(f\"Contents of {extract_path}: {os.listdir(extract_path)}\")\n",
"\n",
"# If there are subdirectories, list their contents as well\n",
"for root, dirs, files_in_dir in os.walk(extract_path):\n",
" for d in dirs:\n",
" print(f\"Contents of {os.path.join(root, d)}: {os.listdir(os.path.join(root, d))}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fa551d68"
},
"source": [
"**Reasoning**:\n",
"The previous output showed that the lexicon files are `positive.tsv` and `negative.tsv` located directly within the `InSet-master/InSet-master` subdirectory, not in a `data` subdirectory and with a `.tsv` extension instead of `.txt`. I will correct the paths and load the lexicon files using the correct filenames and extensions.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "abbdf2d2",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "28479e44-37ed-45da-8326-c3ef6a6a2ecb"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Loaded 3610 positive words from InSet lexicon.\n",
"Loaded 6610 negative words from InSet lexicon.\n"
]
}
],
"source": [
"import os\n",
"\n",
"# Define the paths to the positive and negative lexicon files based on the corrected structure\n",
"extract_base_path = '/content/InSet_extracted'\n",
"# Assuming the zip extracts into a folder named 'InSet-master' inside the extract_base_path\n",
"extract_inset_data_path = os.path.join(extract_base_path, 'InSet-master')\n",
"\n",
"positive_lexicon_path = os.path.join(extract_inset_data_path, 'positive.tsv')\n",
"negative_lexicon_path = os.path.join(extract_inset_data_path, 'negative.tsv')\n",
"\n",
"# Load positive words\n",
"inset_positive_words = []\n",
"if os.path.exists(positive_lexicon_path):\n",
" with open(positive_lexicon_path, 'r', encoding='utf-8') as f:\n",
" for line in f:\n",
" inset_positive_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Positive lexicon file not found at {positive_lexicon_path}\")\n",
"\n",
"# Load negative words\n",
"inset_negative_words = []\n",
"if os.path.exists(negative_lexicon_path):\n",
" with open(negative_lexicon_path, 'r', encoding='utf-8') as f:\n",
" for line in f:\n",
" inset_negative_words.append(line.strip())\n",
"else:\n",
" print(f\"Warning: Negative lexicon file not found at {negative_lexicon_path}\")\n",
"\n",
"print(f\"Loaded {len(inset_positive_words)} positive words from InSet lexicon.\")\n",
"print(f\"Loaded {len(inset_negative_words)} negative words from InSet lexicon.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "84c133b5"
},
"source": [
"## Update Sentiment Lexicon\n",
"\n",
"### Subtask:\n",
"Replace the existing `positive_words` and `negative_words` lists with the newly loaded InSet lexicon to be used for sentiment scoring.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "cc36dbe3"
},
"source": [
"**Reasoning**:\n",
"I need to clean the loaded InSet lexicon by removing header rows and extracting only the words from each entry before updating the global `positive_words` and `negative_words` lists. The word and its weight are separated by a tab, so I will split and take the first element.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "9030a7d0",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "6b25509a-171f-434c-b103-f6e3394f704b"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Updated positive_words list contains 3609 words.\n",
"Updated negative_words list contains 6609 words.\n"
]
}
],
"source": [
"positive_words = [word.split('\\t')[0] for word in inset_positive_words if word and word != 'word\\tweight']\n",
"negative_words = [word.split('\\t')[0] for word in inset_negative_words if word and word != 'word\\tweight']\n",
"\n",
"print(f\"Updated positive_words list contains {len(positive_words)} words.\")\n",
"print(f\"Updated negative_words list contains {len(negative_words)} words.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "b0339c4e"
},
"source": [
"## Improve Preprocessing (Noise Removal)\n",
"\n",
"### Subtask:\n",
"Introduce an additional step in the preprocessing to remove identified noise words such as 'br' and 'quot' from the comments, which are currently skewing word frequency counts and not contributing to sentiment. This step should be applied before re-running sentiment analysis.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "05263a08"
},
"source": [
"**Reasoning**:\n",
"First, I will define a function called `remove_noise_words` to specifically filter out 'br' and 'quot' from the comments. This function will split the comment into words, remove the specified noise words, and then rejoin the words into a clean string.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "eb8eb627",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "1a236990-b339-4be9-db8b-6349e7507f5a"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Fungsi 'remove_noise_words' telah didefinisikan.\n"
]
}
],
"source": [
"def remove_noise_words(text):\n",
" words = text.split()\n",
" # Remove 'br' and 'quot' (case-insensitive) from the words list\n",
" filtered_words = [word for word in words if word.lower() not in ['br', 'quot']]\n",
" return ' '.join(filtered_words)\n",
"\n",
"print(\"Fungsi 'remove_noise_words' telah didefinisikan.\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6e66d6b8"
},
"source": [
"**Reasoning**:\n",
"Now that the `remove_noise_words` function is defined, I will apply it to the 'Comment' column of the DataFrame `df` to clean the comments, and then display the first few rows to verify the noise words have been removed.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "f7341ab9",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 311
},
"outputId": "c23a6f57-1684-4c01-9cb0-fab1551c876e"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score Sentiment_Label \n",
"0 -2 Negatif \n",
"1 3 Positif \n",
"2 0 Netral \n",
"3 0 Netral \n",
"4 1 Positif "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
Sentiment_Score
\n",
"
Sentiment_Label
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
-2
\n",
"
Negatif
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
3
\n",
"
Positif
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
1
\n",
"
Positif
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2,\n \"min\": -15,\n \"max\": 18,\n \"num_unique_values\": 21,\n \"samples\": [\n -2,\n 18,\n 8\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Label\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Negatif\",\n \"Positif\",\n \"Netral\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 47
}
],
"source": [
"df['Comment'] = df['Comment'].apply(remove_noise_words)\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fef2b58d"
},
"source": [
"**Reasoning**:\n",
"Now that the `positive_words` and `negative_words` lists have been updated with the InSet lexicon and noise words have been removed from the 'Comment' column, I need to recalculate the sentiment scores and labels for each comment in the DataFrame. This ensures the sentiment analysis reflects the improved lexicon and preprocessing.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "c8487928",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 311
},
"outputId": "a9dbfcd8-7bab-4760-c9f0-3922b40c9361"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score Sentiment_Label \n",
"0 -2 Negatif \n",
"1 3 Positif \n",
"2 0 Netral \n",
"3 0 Netral \n",
"4 1 Positif "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
Sentiment_Score
\n",
"
Sentiment_Label
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
-2
\n",
"
Negatif
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
3
\n",
"
Positif
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
1
\n",
"
Positif
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2,\n \"min\": -15,\n \"max\": 18,\n \"num_unique_values\": 21,\n \"samples\": [\n -2,\n 18,\n 8\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Label\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Negatif\",\n \"Positif\",\n \"Netral\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 48
}
],
"source": [
"def calculate_sentiment_score(comment_text):\n",
" score = 0\n",
" words = comment_text.split() # Split the comment into words\n",
" for word in words:\n",
" if word in positive_words:\n",
" score += 1\n",
" elif word in negative_words:\n",
" score -= 1\n",
" return score\n",
"\n",
"# Apply the function to the 'Comment' column and create a new 'Sentiment_Score' column\n",
"df['Sentiment_Score'] = df['Comment'].apply(calculate_sentiment_score)\n",
"\n",
"# Display the DataFrame with the new sentiment scores\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "d696c5db"
},
"source": [
"**Reasoning**:\n",
"Now that the `Sentiment_Score` column has been updated with the InSet lexicon and cleaned comments, I need to re-apply the `classify_sentiment` function to generate updated sentiment labels based on these new scores.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "836eeefd",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 311
},
"outputId": "4ef1fc4b-a3b3-47c1-93c0-79548fc5e2e5"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score Sentiment_Label \n",
"0 0 Netral \n",
"1 0 Netral \n",
"2 1 Positif \n",
"3 0 Netral \n",
"4 0 Netral "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
Sentiment_Score
\n",
"
Sentiment_Label
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
1
\n",
"
Positif
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 0,\n \"min\": -2,\n \"max\": 8,\n \"num_unique_values\": 7,\n \"samples\": [\n 0,\n 1,\n 3\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Label\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Netral\",\n \"Positif\",\n \"Negatif\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 31
}
],
"source": [
"def classify_sentiment(score):\n",
" if score > 0:\n",
" return 'Positif'\n",
" elif score < 0:\n",
" return 'Negatif'\n",
" else:\n",
" return 'Netral'\n",
"\n",
"df['Sentiment_Label'] = df['Sentiment_Score'].apply(classify_sentiment)\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "dd5756a6"
},
"source": [
"**Reasoning**:\n",
"To assess the impact of the updated lexicon and preprocessing, I need to analyze the distribution of sentiment labels by counting the occurrences of 'Positif', 'Negatif', and 'Netral' in the 'Sentiment_Label' column.\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "d0d99245",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "bd5a2f86-5394-4973-a3c8-67757729c0b5"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Sentiment Distribution after InSet Lexicon and Noise Removal:\n",
"Sentiment_Label\n",
"Positif 335\n",
"Netral 234\n",
"Negatif 164\n",
"Name: count, dtype: int64\n"
]
}
],
"source": [
"sentiment_distribution = df['Sentiment_Label'].value_counts()\n",
"print(\"Sentiment Distribution after InSet Lexicon and Noise Removal:\")\n",
"print(sentiment_distribution)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "13f8f7b7"
},
"source": [
"# Task\n",
"Hitung dan tampilkan rangkuman persentase komentar positif, negatif, dan netral berdasarkan analisis sentimen yang telah dilakukan."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "25d8769b"
},
"source": [
"## Hitung Persentase Sentimen\n",
"\n",
"### Subtask:\n",
"Hitung persentase untuk setiap kategori sentimen (Positif, Negatif, Netral) berdasarkan distribusi sentimen yang telah dihitung.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "5883ef0a",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "d2f3b9a0-7be3-4215-f9f9-4ef1649692d2"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Rangkuman Persentase Sentimen:\n",
"Positif: 45.70%\n",
"Netral: 31.92%\n",
"Negatif: 22.37%\n"
]
}
],
"source": [
"total_comments = df['Sentiment_Label'].count()\n",
"sentiment_percentages = (df['Sentiment_Label'].value_counts() / total_comments) * 100\n",
"\n",
"print(\"Rangkuman Persentase Sentimen:\")\n",
"for sentiment, percentage in sentiment_percentages.items():\n",
" print(f\"{sentiment}: {percentage:.2f}%\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "766e216b"
},
"source": [
"## Estimasi Gender dari Username (Heuristik)\n",
"\n",
"### Subtask:\n",
"Mengestimasi gender dari kolom `UserName` menggunakan aturan heuristik sederhana dan menambahkan hasilnya sebagai kolom baru `Estimated_Gender`."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6cd3e9ba"
},
"source": [
"## Re-evaluasi Komentar Netral dengan InSet Lexicon\n",
"\n",
"Langkah-langkah sebelumnya telah memperbarui `positive_words` dan `negative_words` dengan leksikon InSet, dan kemudian menghitung ulang `Sentiment_Score` serta `Sentiment_Label` untuk seluruh DataFrame. Jadi, semua komentar, termasuk yang sebelumnya netral, sudah diproses dengan leksikon InSet."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "6ac3c656"
},
"source": [
"**Reasoning**:\n",
"Untuk memastikan dan menampilkan hasilnya, saya akan menjalankan kembali fungsi `calculate_sentiment_score` dan `classify_sentiment` pada DataFrame `df` yang sudah ada. Meskipun ini seharusnya sudah terjadi di langkah-langkah sebelumnya, mengulanginya akan secara eksplisit menggunakan `positive_words` dan `negative_words` yang kini berisi InSet lexicon. Setelah itu, saya akan menyaring DataFrame untuk hanya menampilkan komentar-komentar yang masih berlabel 'Netral'."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "a1c6a018",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 710
},
"outputId": "cad777e0-2171-4c68-b200-f78340fec222"
},
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Re-evaluasi sentimen selesai dengan leksikon InSet. Berikut adalah distribusi sentimen yang diperbarui:\n",
"Sentiment_Label\n",
"Positif 335\n",
"Netral 234\n",
"Negatif 164\n",
"Name: count, dtype: int64\n",
"\n",
"Contoh komentar yang masih berlabel Netral:\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
" Date UserName \\\n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"8 2025-12-12T05:34:04Z @TrangVan_hvcfpx \n",
"10 2025-12-12T05:32:34Z @Quỳnh_Đào_Huy \n",
"13 2025-12-09T07:34:53Z @alekkhehe7891 \n",
"19 2025-12-02T11:48:09Z @RiskiWahyuabadi-l2w4f \n",
"27 2025-11-16T15:02:20Z @setyosaputro3051 \n",
"29 2025-12-11T21:57:27Z @Faeyza_77 \n",
"30 2025-11-15T08:41:16Z @leyllasekar9448 \n",
"39 2025-10-25T04:01:48Z @regalnola \n",
"\n",
" Comment LikeCount \\\n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"8 ayo datang sekarang,jangan nanti-nanti 🐍💜 r͓̽o... 0 \n",
"10 sini dulu,kita tungguin 🐍💜 r͓̽o͓̽m͓̽a͓̽4͓̽d͓̽ 💙👮 0 \n",
"13 as always, stay curious. 0 \n",
"19 berarti teknologi maju bumi semakin buruk mung... 0 \n",
"27 bahlil bajingannnn 1 \n",
"29 ama tu sawit wowok😂 1 \n",
"30 i()() 0 \n",
"39 konten apa ini??
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"repr_error": "0"
}
},
"metadata": {}
}
],
"source": [
"# Pastikan fungsi perhitungan skor dan klasifikasi tersedia (ini sudah didefinisikan di atas)\n",
"def calculate_sentiment_score(comment_text):\n",
" score = 0\n",
" words = comment_text.split() # Split the comment into words\n",
" for word in words:\n",
" if word in positive_words:\n",
" score += 1\n",
" elif word in negative_words:\n",
" score -= 1\n",
" return score\n",
"\n",
"def classify_sentiment(score):\n",
" if score > 0:\n",
" return 'Positif'\n",
" elif score < 0:\n",
" return 'Negatif'\n",
" else:\n",
" return 'Netral'\n",
"\n",
"# Hitung ulang skor sentimen (menggunakan lexicon InSet yang sudah diupdate)\n",
"df['Sentiment_Score'] = df['Comment'].apply(calculate_sentiment_score)\n",
"\n",
"# Klasifikasikan ulang label sentimen\n",
"df['Sentiment_Label'] = df['Sentiment_Score'].apply(classify_sentiment)\n",
"\n",
"print(\"Re-evaluasi sentimen selesai dengan leksikon InSet. Berikut adalah distribusi sentimen yang diperbarui:\")\n",
"print(df['Sentiment_Label'].value_counts())\n",
"\n",
"# Tampilkan beberapa komentar yang masih berlabel 'Netral'\n",
"print(\"\\nContoh komentar yang masih berlabel Netral:\")\n",
"display(df[df['Sentiment_Label'] == 'Netral'].head(10))"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "77cf9344"
},
"source": [
"Seperti yang ditunjukkan di atas, proses sentimen telah diulang dengan leksikon InSet. Meskipun demikian, masih ada beberapa komentar yang diklasifikasikan sebagai 'Netral'. Ini mungkin karena:\n",
"\n",
"* Komentar tersebut memang tidak mengandung kata-kata sentimen dari leksikon InSet (baik positif maupun negatif).\n",
"* Komentar tersebut mengandung jumlah kata positif dan negatif yang seimbang, sehingga skor sentimennya nol.\n",
"* Kata-kata dalam komentar tersebut tidak ada dalam leksikon sentimen yang digunakan."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "14a7264f"
},
"source": [
"**Reasoning**:\n",
"Estimasi gender dari username adalah tugas yang kompleks. Saya akan mencoba pendekatan heuristik yang sangat dasar dengan mencari kata kunci tertentu dalam username yang mungkin mengindikasikan gender. Karena `UserName` bisa sangat bervariasi, ini adalah demonstrasi sederhana dan mungkin tidak akurat untuk data yang lebih kompleks. Saya akan mendefinisikan daftar kata kunci untuk 'Laki-laki' dan 'Perempuan' (misalnya, 'putra', 'budi' untuk laki-laki; 'putri', 'siti' untuk perempuan) dan sebuah fungsi untuk memeriksa keberadaan kata kunci ini dalam username."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "2c17ce1c",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 400
},
"outputId": "d6d926e1-28b8-4edf-a43a-806a71d9ad12"
},
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/plain": [
" Date UserName \\\n",
"0 2025-12-13T11:43:27Z @nauvalrizky28 \n",
"1 2025-12-13T11:40:45Z @HisyamAbdullahMuyassar \n",
"2 2025-12-12T06:19:06Z @indrajayamahestikahukumpag9109 \n",
"3 2025-12-12T05:41:53Z @Hải.Ninh.Nhật \n",
"4 2025-12-12T05:36:24Z @UyenLinhjvt1to_929 \n",
"\n",
" Comment LikeCount \\\n",
"0 pemerintah buta tuli 0 \n",
"1 malu aku jadi orang indonesia 1 \n",
"2 indonesia bangsa besar, bangsa cerdas 0 \n",
"3 datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽... 0 \n",
"4 cek tempat kami, cocok buat healing santai 🐍💜 ... 0 \n",
"\n",
" Sentiment_Score Sentiment_Label Estimated_Gender \n",
"0 -2 Negatif Tidak Diketahui \n",
"1 3 Positif Tidak Diketahui \n",
"2 0 Netral Tidak Diketahui \n",
"3 0 Netral Tidak Diketahui \n",
"4 1 Positif Tidak Diketahui "
],
"text/html": [
"\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"
\n",
"
\n",
"
Date
\n",
"
UserName
\n",
"
Comment
\n",
"
LikeCount
\n",
"
Sentiment_Score
\n",
"
Sentiment_Label
\n",
"
Estimated_Gender
\n",
"
\n",
" \n",
" \n",
"
\n",
"
0
\n",
"
2025-12-13T11:43:27Z
\n",
"
@nauvalrizky28
\n",
"
pemerintah buta tuli
\n",
"
0
\n",
"
-2
\n",
"
Negatif
\n",
"
Tidak Diketahui
\n",
"
\n",
"
\n",
"
1
\n",
"
2025-12-13T11:40:45Z
\n",
"
@HisyamAbdullahMuyassar
\n",
"
malu aku jadi orang indonesia
\n",
"
1
\n",
"
3
\n",
"
Positif
\n",
"
Tidak Diketahui
\n",
"
\n",
"
\n",
"
2
\n",
"
2025-12-12T06:19:06Z
\n",
"
@indrajayamahestikahukumpag9109
\n",
"
indonesia bangsa besar, bangsa cerdas
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
Tidak Diketahui
\n",
"
\n",
"
\n",
"
3
\n",
"
2025-12-12T05:41:53Z
\n",
"
@Hải.Ninh.Nhật
\n",
"
datang yuk,suasananya cozy banget 🐍💜 r͓̽o͓̽m͓̽...
\n",
"
0
\n",
"
0
\n",
"
Netral
\n",
"
Tidak Diketahui
\n",
"
\n",
"
\n",
"
4
\n",
"
2025-12-12T05:36:24Z
\n",
"
@UyenLinhjvt1to_929
\n",
"
cek tempat kami, cocok buat healing santai 🐍💜 ...
\n",
"
0
\n",
"
1
\n",
"
Positif
\n",
"
Tidak Diketahui
\n",
"
\n",
" \n",
"
\n",
"
\n",
"
\n",
"\n",
"
\n",
" \n",
"\n",
" \n",
"\n",
" \n",
"
\n",
"\n",
"\n",
"
\n",
" \n",
"\n",
"\n",
"\n",
" \n",
"
\n",
"\n",
"
\n",
"
\n"
],
"application/vnd.google.colaboratory.intrinsic+json": {
"type": "dataframe",
"variable_name": "df",
"summary": "{\n \"name\": \"df\",\n \"rows\": 733,\n \"fields\": [\n {\n \"column\": \"Date\",\n \"properties\": {\n \"dtype\": \"object\",\n \"num_unique_values\": 728,\n \"samples\": [\n \"2025-10-19T06:44:48Z\",\n \"2025-06-01T09:37:18Z\",\n \"2025-06-01T11:07:00Z\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"UserName\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 678,\n \"samples\": [\n \"@Reieines\",\n \"@FadilKucrut28\",\n \"@improdexgaming3272\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Comment\",\n \"properties\": {\n \"dtype\": \"string\",\n \"num_unique_values\": 722,\n \"samples\": [\n \"teknologi makin canggih orang makin sibuk pekerjaannya sering main hp banding bersosial makin modern makin orng ngalamin masalah mental dampaknya lingkungan kesehatan mental fisik sama\",\n \"ya gitulah, omongan oposisi selalu terdengar keren. \\ud83d\\ude05\",\n \"pernah pengen nangis nonton kok bisa, baru rasanya hati bergetar.\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"LikeCount\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 83,\n \"min\": 0,\n \"max\": 2021,\n \"num_unique_values\": 37,\n \"samples\": [\n 9,\n 7,\n 6\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Score\",\n \"properties\": {\n \"dtype\": \"number\",\n \"std\": 2,\n \"min\": -15,\n \"max\": 18,\n \"num_unique_values\": 21,\n \"samples\": [\n -2,\n 18,\n 8\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Sentiment_Label\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Negatif\",\n \"Positif\",\n \"Netral\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n },\n {\n \"column\": \"Estimated_Gender\",\n \"properties\": {\n \"dtype\": \"category\",\n \"num_unique_values\": 3,\n \"samples\": [\n \"Tidak Diketahui\",\n \"Laki-laki\",\n \"Perempuan\"\n ],\n \"semantic_type\": \"\",\n \"description\": \"\"\n }\n }\n ]\n}"
}
},
"metadata": {},
"execution_count": 52
}
],
"source": [
"# Daftar kata kunci heuristik untuk gender (contoh sederhana)\n",
"male_keywords = ['putra', 'budi', 'agus', 'rizal', 'eko', 'joko']\n",
"female_keywords = ['putri', 'siti', 'ayu', 'indah', 'dewi', 'ani']\n",
"\n",
"def estimate_gender(username):\n",
" username_lower = str(username).lower() # Pastikan username adalah string dan ubah ke lowercase\n",
" for keyword in male_keywords:\n",
" if keyword in username_lower:\n",
" return 'Laki-laki'\n",
" for keyword in female_keywords:\n",
" if keyword in username_lower:\n",
" return 'Perempuan'\n",
" return 'Tidak Diketahui'\n",
"\n",
"# Terapkan fungsi ke kolom 'UserName' untuk membuat kolom 'Estimated_Gender'\n",
"df['Estimated_Gender'] = df['UserName'].apply(estimate_gender)\n",
"\n",
"# Tampilkan beberapa baris pertama dengan kolom baru\n",
"df.head()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "f234dff7"
},
"source": [
"**Sel ini mengestimasi gender dari username.**\n",
"\n",
"1. **`male_keywords` dan `female_keywords`**: Mendefinisikan daftar kata kunci sederhana yang diasumsikan sering muncul dalam username laki-laki atau perempuan di Indonesia. Ini adalah daftar contoh dan perlu diperluas serta disesuaikan untuk akurasi yang lebih baik.\n",
"2. **`estimate_gender(username)`**: Fungsi ini menerima username, mengubahnya menjadi huruf kecil, lalu memeriksa apakah ada kata kunci dari `male_keywords` atau `female_keywords` di dalamnya. Jika ditemukan, ia mengembalikan 'Laki-laki' atau 'Perempuan'. Jika tidak ada yang cocok, ia mengembalikan 'Tidak Diketahui'.\n",
"3. **`df['Estimated_Gender'] = df['UserName'].apply(estimate_gender)`**: Menerapkan fungsi `estimate_gender` ke setiap nilai di kolom `UserName` DataFrame `df` dan menyimpan hasilnya dalam kolom baru bernama `Estimated_Gender`.\n",
"4. **`df.head()`**: Menampilkan lima baris pertama dari DataFrame untuk memverifikasi penambahan kolom `Estimated_Gender` dan hasilnya."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "91970542",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 671
},
"outputId": "1d9bfad5-1efb-4a7f-8e75-5bc8c1d90d0d"
},
"outputs": [
{
"output_type": "stream",
"name": "stderr",
"text": [
"/tmp/ipython-input-108055088.py:9: FutureWarning: \n",
"\n",
"Passing `palette` without assigning `hue` is deprecated and will be removed in v0.14.0. Assign the `x` variable to `hue` and set `legend=False` for the same effect.\n",
"\n",
" sns.barplot(x='Sentiment', y='Count', data=sentiment_counts, palette='viridis')\n"
]
},
{
"output_type": "display_data",
"data": {
"text/plain": [
""
],
"image/png": "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2MuucPvOO+/YrDs4OKhkyZLq27evoqOj87QwAAAAwF52hdtjx47lVx0AAADAPctVuO3ateudBypSRAEBAWrVqpU6dOhwz4UBAAAA9srVDWXe3t53XFxdXXX48GH16NGD590CAACgQOTqyu38+fNzPeCKFSv0z3/+846fZgYAAADktTx5FNhfNWzYUHXr1s3rYQEAAIA7yvNw6+Pjoy+++CKvhwUAAADuKM/DLQAAAFBQCLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CLcAAAAwDcItAAAATINwCwAAANMg3AIAAMA0CjTcbt68WR06dFDp0qVlsVi0fPlym+2GYWjChAkqVaqUXF1d1bJlSx0+fNimz4ULF9SzZ095eXnJx8dHAwcOVHp6+n08CwAAABQWBRpuL1++rFq1aum999676fZp06Zp5syZmjt3rnbs2CF3d3dFRETo6tWr1j49e/bU/v37tWbNGq1YsUKbN2/W4MGD79cpAAAAoBApUpAHj4yMVGRk5E23GYahGTNmaPz48erUqZMk6aOPPpK/v7+WL1+up59+WgcPHtSqVau0c+dO1a1bV5I0a9YstW3bVm+99ZZKly59384FAAAABa/Qzrk9duyYEhMT1bJlS2ubt7e36tWrp23btkmStm3bJh8fH2uwlaSWLVvKwcFBO3bsuOXYGRkZSktLs1kAAADw4Cu04TYxMVGS5O/vb9Pu7+9v3ZaYmCg/Pz+b7UWKFJGvr6+1z83ExsbK29vbugQGBuZx9QAAACgIhTbc5qfo6GilpqZal1OnThV0SQAAAMgDhTbcBgQESJKSkpJs2pOSkqzbAgIClJycbLM9MzNTFy5csPa5GRcXF3l5edksAAAAePAV2nBboUIFBQQEaN26dda2tLQ07dixQ+Hh4ZKk8PBwpaSkaNeuXdY+69evV3Z2turVq3ffawYAAEDBKtCnJaSnp+vIkSPW9WPHjik+Pl6+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\n"
},
"metadata": {}
}
],
"source": [
"# 2. Menampilkan Jumlah Komentar per Kategori\n",
"print(\"\\nJumlah Komentar per Kategori Sentimen:\")\n",
"print(df['Sentiment_Label'].value_counts())\n",
"# 3. Visualisasi Distribusi Sentimen\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"\n",
"sentiment_counts = df['Sentiment_Label'].value_counts().reset_index()\n",
"sentiment_counts.columns = ['Sentiment', 'Count']\n",
"\n",
"plt.figure(figsize=(8, 6))\n",
"sns.barplot(x='Sentiment', y='Count', data=sentiment_counts, palette='viridis')\n",
"plt.title('Distribusi Sentimen Komentar')\n",
"plt.xlabel('Kategori Sentimen')\n",
"plt.ylabel('Jumlah Komentar')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "79524fcb"
},
"source": [
"# Task\n",
"The original user task is:\n",
"\n",
"Generate a presentation based on the YouTube comments analysis, covering the video's topic, the process of data collection, preprocessing (case folding, normalization, stopword removal, noise removal), the application of the InSet lexicon for sentiment analysis, sentiment scoring and classification, the resulting sentiment distribution, an analysis of the most liked comment, and gender estimation of commenters."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "e494ad4f"
},
"source": [
"## Analyze Most Liked Comment\n",
"\n",
"### Subtask:\n",
"Identify the comment with the highest 'LikeCount' in the DataFrame. Extract its content and sentiment, and derive insights on why this particular comment might have resonated most with the audience.\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "bb5051f7"
},
"source": [
"**Reasoning**:\n",
"To identify the most liked comment, I will find the index of the maximum value in the 'LikeCount' column using `idxmax()` and then use `.loc` to retrieve the entire row corresponding to that comment.\n",
"\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "a71c580d",
"colab": {
"base_uri": "https://localhost:8080/"
},
"outputId": "de64cc99-5e2b-4ea0-bb21-e112b0f28168"
},
"source": [
"most_liked_comment_row = df.loc[df['LikeCount'].idxmax()]\n",
"\n",
"most_liked_comment_text = most_liked_comment_row['Comment']\n",
"most_liked_comment_sentiment = most_liked_comment_row['Sentiment_Label']\n",
"most_liked_comment_likes = most_liked_comment_row['LikeCount']\n",
"\n",
"print(f\"Most Liked Comment (Likes: {most_liked_comment_likes}):\\n{most_liked_comment_text}\")\n",
"print(f\"Sentiment of Most Liked Comment: {most_liked_comment_sentiment}\")"
],
"execution_count": null,
"outputs": [
{
"output_type": "stream",
"name": "stdout",
"text": [
"Most Liked Comment (Likes: 2021):\n",
"membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\n",
"Sentiment of Most Liked Comment: Positif\n"
]
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7a732f5a"
},
"source": [
"### Analisis Komentar Paling Disukai\n",
"\n",
"Komentar dengan jumlah suka terbanyak (Likes: 2021) adalah:\n",
"\n",
"\"membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\"\n",
"\n",
"Sentimen dari komentar ini adalah: **Positif**\n",
"\n",
"**Wawasan dan Alasan Resonansi:**\n",
"\n",
"Komentar ini kemungkinan besar mendapatkan banyak suka karena beberapa alasan:\n",
"\n",
"1. **Pendapat yang Komprehensif dan Mendalam:** Komentar ini tidak hanya sekadar tanggapan singkat, tetapi juga merupakan opini yang sangat terstruktur dan komprehensif, membahas berbagai aspek dari pendidikan hingga masalah sosial dan lingkungan.\n",
"2. **Keterkaitan Emosional dan Pengalaman Pribadi:** Penggunaan frasa seperti \"membekas hatiku buat aku 'malu' menjadi warga negara indonesia\" dan berbagi pengalaman pribadi dalam sistem pendidikan menciptakan koneksi emosional dengan pembaca yang mungkin memiliki perasaan atau pengalaman serupa.\n",
"3. **Mengangkat Isu Sensitif dan Relevan:** Komentar ini menyoroti isu-isu penting yang sering menjadi perhatian publik, seperti kualitas pendidikan, korupsi, kerusakan lingkungan, dan kurangnya empati. Isu-isu ini sangat relevan dengan topik video (\"Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?\") dan kehidupan masyarakat Indonesia pada umumnya.\n",
"4. **Menawarkan Kritik Konstruktif dan Solusi:** Meskipun berisi kritik terhadap kondisi yang ada, komentar ini juga menyertakan harapan dan ide solusi, terutama terkait sistem pendidikan yang harus memancing pemikiran kritis dan empati. Hal ini membuat komentar terasa lebih berbobot dan bukan sekadar keluhan.\n",
"5. **Gaya Bahasa yang Jelas dan Menggugah:** Komentar ditulis dengan gaya yang lugas dan mudah dipahami, memungkinkan pesan kompleks disampaikan secara efektif dan menggugah kesadaran pembaca.\n",
"\n",
"Sentimen 'Positif' dari komentar ini, meskipun membahas banyak masalah negatif, kemungkinan berasal dari elemen-elemen harapan, kritik konstruktif, dan dorongan untuk perubahan yang terangkum di dalamnya. Komentar ini menunjukkan bahwa audiens sangat menghargai opini yang terartikulasi dengan baik, berani menyuarakan kritik terhadap sistem, dan menawarkan perspektif yang relevan dengan pengalaman kolektif."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3ed5de88"
},
"source": [
"### Analisis Komentar Paling Disukai\n",
"\n",
"Komentar dengan jumlah suka terbanyak (Likes: 2021) adalah:\n",
"\n",
"\"membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan "mengapa hal terjadi" "apa terapkan kehidupan sehari-hari". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\"\n",
"\n",
"Sentimen dari komentar ini adalah: **Positif**\n",
"\n",
"**Wawasan dan Alasan Resonansi:**\n",
"\n",
"Komentar ini kemungkinan besar mendapatkan banyak suka karena beberapa alasan:\n",
"\n",
"1. **Pendapat yang Komprehensif dan Mendalam:** Komentar ini tidak hanya sekadar tanggapan singkat, tetapi juga merupakan opini yang sangat terstruktur dan komprehensif, membahas berbagai aspek dari pendidikan hingga masalah sosial dan lingkungan.\n",
"2. **Keterkaitan Emosional dan Pengalaman Pribadi:** Penggunaan frasa seperti \"membekas hatiku buat aku 'malu' menjadi warga negara indonesia\" dan berbagi pengalaman pribadi dalam sistem pendidikan menciptakan koneksi emosional dengan pembaca yang mungkin memiliki perasaan atau pengalaman serupa.\n",
"3. **Mengangkat Isu Sensitif dan Relevan:** Komentar ini menyoroti isu-isu penting yang sering menjadi perhatian publik, seperti kualitas pendidikan, korupsi, kerusakan lingkungan, dan kurangnya empati. Isu-isu ini sangat relevan dengan topik video (\"Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?\") dan kehidupan masyarakat Indonesia pada umumnya.\n",
"4. **Menawarkan Kritik Konstruktif dan Solusi:** Meskipun berisi kritik terhadap kondisi yang ada, komentar ini juga menyertakan harapan dan ide solusi, terutama terkait sistem pendidikan yang harus memancing pemikiran kritis dan empati. Hal ini membuat komentar terasa lebih berbobot dan bukan sekadar keluhan.\n",
"5. **Gaya Bahasa yang Jelas dan Menggugah:** Komentar ditulis dengan gaya yang lugas dan mudah dipahami, memungkinkan pesan kompleks disampaikan secara efektif dan menggugah kesadaran pembaca.\n",
"\n",
"Sentimen 'Positif' dari komentar ini, meskipun membahas banyak masalah negatif, kemungkinan berasal dari elemen-elemen harapan, kritik konstruktif, dan dorongan untuk perubahan yang terangkum di dalamnya. Komentar ini menunjukkan bahwa audiens sangat menghargai opini yang terartikulasi dengan baik, berani menyuarakan kritik terhadap sistem, dan menawarkan perspektif yang relevan dengan pengalaman kolektif."
]
},
{
"cell_type": "code",
"source": [
"from google.colab import files\n",
"\n",
"csv_filename_final = 'LexiconSentiment_komentar_youtube.csv'\n",
"\n",
"# Save the DataFrame to a CSV file without the index (in case it wasn't saved before)\n",
"df.to_csv(csv_filename_final, index=False)\n",
"\n",
"# Download the newly created CSV file\n",
"files.download(csv_filename_final)\n",
"print(f\"DataFrame berhasil disimpan dan diunduh sebagai '{csv_filename_final}'\")"
],
"metadata": {
"id": "QUpB38OOdo9o"
},
"execution_count": null,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "6c978f4c"
},
"source": [
"## Generate Presentation Content\n",
"\n",
"### Subtask:\n",
"Generate structured content for a presentation (PPT) based on the executed steps in the notebook, explaining each part in easy-to-understand language. This will cover data collection, preprocessing steps (case folding, normalization, stopword removal, noise removal), the application of the InSet lexicon for sentiment analysis, sentiment scoring and classification, the resulting sentiment distribution, the analysis of the most liked comment, and additional analysis like gender estimation. The content will be formatted as a series of slides.\n",
"\n",
"---\n",
"\n",
"### Slide 1: Judul - Analisis Sentimen Komentar YouTube\n",
"* **Judul:** Analisis Sentimen Komentar YouTube pada Video \"Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?\"\n",
"* **Nama:** [Nama Anda]\n",
"* **Tanggal:** [Tanggal Presentasi]\n",
"\n",
"---\n",
"\n",
"### Slide 2: Pendahuluan - Topik Video & Tujuan Analisis\n",
"* **Topik Video:** \"Teknologi Makin Canggih, Kenapa Lingkungan Makin Parah?\"\n",
"* **Deskripsi Singkat Video:** Video ini membahas tentang paradoks kemajuan teknologi yang semakin pesat, namun di sisi lain, kondisi lingkungan justru semakin memburuk. Video ini kemungkinan memancing beragam opini dan sentimen dari penontonnya.\n",
"* **Tujuan Analisis:** Menganalisis sentimen (positif, negatif, netral) dari komentar-komentar penonton YouTube terkait video ini untuk mendapatkan pemahaman tentang persepsi publik.\n",
"\n",
"---\n",
"\n",
"### Slide 3: Pengumpulan Data\n",
"* **Apa yang Dikumpulkan:** Komentar-komentar dari video YouTube dengan ID `2xWpbjWp1Qc`.\n",
"* **Metode:** Menggunakan YouTube Data API v3 dan fungsi kustom `video_comments`.\n",
"* **Jumlah Komentar yang Dikumpulkan:** Sebanyak 734 komentar.\n",
"* **Detail Proses:**\n",
" * `api_key` digunakan untuk otentikasi. `video_comments` memanggil API YouTube untuk mengambil komentar utama dan balasannya.\n",
" * Informasi yang diambil meliputi tanggal publikasi, nama pengguna, teks komentar, dan jumlah suka.\n",
" * Data disimpan sementara dalam bentuk daftar (`comments`) dan kemudian diubah menjadi Pandas DataFrame.\n",
"\n",
"---\n",
"\n",
"### Slide 4: Preprocessing Data: Case Folding\n",
"* **Apa Itu Case Folding?** Proses mengubah semua teks menjadi huruf kecil (lowercase).\n",
"* **Mengapa Penting?** Untuk memastikan bahwa kata yang sama dengan kapitalisasi berbeda (misalnya, \"Teknologi\" dan \"teknologi\") dianggap sebagai kata yang sama dalam analisis. Ini menghindari duplikasi dan meningkatkan konsistensi data.\n",
"* **Bagaimana Dilakukan:** Menggunakan metode `.str.lower()` pada kolom 'Comment' DataFrame.\n",
"\n",
"---\n",
"\n",
"### Slide 5: Preprocessing Data: Normalisasi Kata\n",
"* **Apa Itu Normalisasi Kata?** Proses mengubah kata-kata tidak baku atau singkatan menjadi bentuk bakunya (sesuai KBBI).\n",
"* **Mengapa Penting?** Komentar di media sosial seringkali menggunakan bahasa informal dan singkatan. Normalisasi membantu membuat teks lebih standar dan konsisten, yang krusial untuk analisis sentimen yang akurat.\n",
"* **Bagaimana Dilakukan:**\n",
" * Sebuah kamus (`kata_tidak_baku_ke_baku`) dibuat untuk memetakan kata tidak baku ke baku (contoh: 'yg' ke 'yang', 'ga' ke 'tidak').\n",
" * Fungsi `normalize_text` diterapkan ke kolom 'Comment' untuk mengganti kata-kata berdasarkan kamus ini.\n",
"\n",
"---\n",
"\n",
"### Slide 6: Preprocessing Data: Penghapusan Stopword\n",
"* **Apa Itu Stopword?** Kata-kata yang sering muncul dalam bahasa (misalnya, \"yang\", \"untuk\", \"dan\") tetapi tidak memiliki makna sentimen yang signifikan.\n",
"* **Mengapa Penting?** Menghapus stopword membantu mengurangi dimensi data dan fokus pada kata-kata yang benar-benar membawa makna sentimen, sehingga meningkatkan efisiensi dan akurasi analisis.\n",
"* **Bagaimana Dilakukan:**\n",
" * Daftar `indonesian_stopwords` (sekitar 100+ kata) dibuat.\n",
" * Fungsi `remove_stopwords` diterapkan ke kolom 'Comment' untuk memfilter kata-kata ini.\n",
"\n",
"---\n",
"\n",
"### Slide 7: Preprocessing Data: Penghapusan Noise (br, quot)\n",
"* **Apa Itu Noise?** Karakter atau string yang tidak diinginkan seperti 'br' (line break) dan 'quot' (HTML entity for quotes) yang sering muncul dari proses scraping web dan tidak memiliki nilai informatif.\n",
"* **Mengapa Penting?** Menghilangkan noise membersihkan data lebih lanjut, mencegah kata-kata ini mengganggu analisis sentimen atau analisis teks lainnya.\n",
"* **Bagaimana Dilakukan:**\n",
" * Fungsi `remove_noise_words` dibuat untuk menghapus 'br' dan 'quot' (case-insensitive).\n",
" * Fungsi ini diterapkan ke kolom 'Comment' DataFrame.\n",
"\n",
"---\n",
"\n",
"### Slide 8: Analisis Sentimen: Pengenalan Lexicon InSet\n",
"* **Apa Itu Lexicon InSet?** Sebuah kamus sentimen bahasa Indonesia yang lebih komprehensif, berisi ribuan kata positif dan negatif beserta bobotnya.\n",
"* **Mengapa Digunakan?** Untuk meningkatkan akurasi analisis sentimen dengan menggunakan daftar kata sentimen yang lebih lengkap dan telah teruji dibandingkan lexicon sederhana yang dibuat secara manual.\n",
"* **Bagaimana Dilakukan:**\n",
" * File `InSet-master.zip` diekstrak ke `/content/InSet_extracted`.\n",
" * File `positive.tsv` dan `negative.tsv` dari InSet dibaca dan diparsing. Header dan bobot dihilangkan, hanya kata-kata sentimen yang diambil.\n",
" * Daftar `positive_words` dan `negative_words` di-update dengan kata-kata dari InSet.\n",
" * Jumlah Kata Positif InSet: 3609\n",
" * Jumlah Kata Negatif InSet: 6609\n",
"\n",
"---\n",
"\n",
"### Slide 9: Analisis Sentimen: Penghitungan Skor Sentimen\n",
"* **Apa Itu Skor Sentimen?** Sebuah nilai numerik yang merepresentasikan tingkat kepositifan atau kenegatifan suatu komentar.\n",
"* **Bagaimana Dihitung:**\n",
" * Fungsi `calculate_sentiment_score` memecah komentar menjadi kata-kata.\n",
" * Untuk setiap kata:\n",
" * Jika kata ditemukan di `positive_words` InSet, skor +1.\n",
" * Jika kata ditemukan di `negative_words` InSet, skor -1.\n",
" * Total skor adalah penjumlahan dari semua kata dalam komentar.\n",
"* **Penerapan:** Kolom baru `Sentiment_Score` ditambahkan ke DataFrame `df`.\n",
"\n",
"---\n",
"\n",
"### Slide 10: Analisis Sentimen: Klasifikasi Sentimen\n",
"* **Apa Itu Klasifikasi Sentimen?** Proses memberi label kategori sentimen (Positif, Negatif, Netral) berdasarkan skor sentimen.\n",
"* **Kriteria Klasifikasi:**\n",
" * **Positif:** Jika `Sentiment_Score` > 0\n",
" * **Negatif:** Jika `Sentiment_Score` < 0\n",
" * **Netral:** Jika `Sentiment_Score` == 0\n",
"* **Penerapan:** Fungsi `classify_sentiment` diterapkan ke kolom `Sentiment_Score` untuk membuat kolom baru `Sentiment_Label`.\n",
"\n",
"---\n",
"\n",
"### Slide 11: Distribusi Sentimen\n",
"* **Ringkasan Hasil:** Setelah preprocessing dan analisis sentimen menggunakan InSet lexicon, distribusi sentimen komentar adalah sebagai berikut:\n",
" * Positif: 45.64%\n",
" * Netral: 32.02%\n",
" * Negatif: 22.34%\n",
"\n",
"* **Interpretasi:** Sebagian besar komentar menunjukkan sentimen positif, diikuti oleh sentimen netral, dan yang paling sedikit adalah sentimen negatif. Ini menunjukkan respons yang cenderung optimis atau mendukung terhadap topik video.\n",
"\n",
"* **Visualisasi:**\n",
" * [Sertakan bar plot yang telah dihasilkan sebelumnya, dengan judul \"Distribusi Sentimen Komentar\", label X \"Kategori Sentimen\", dan label Y \"Jumlah Komentar\"]\n",
"\n",
"---\n",
"\n",
"### Slide 12: Analisis Komentar Paling Disukai\n",
"* **Komentar Paling Disukai (Likes: 2021):**\n",
" * \"membekas hatiku buat aku 'malu' menjadi warga negara indonesia pengalamanku menempuh pendidikan sma. aku sendiri risih sistem pendidikan berkutit hafalan. penjelasan \"mengapa hal terjadi\" \"apa terapkan kehidupan sehari-hari\". penting hafalin apa diomongin guru buku, jawab lembar ujian. aku baru merasakan pendidikan sebenarnya ketika aku bangku kuliah, tepatnya mengambil jurusan dkv. aku disana diajak berpikir menumpahkan ide-ideku melalui karya desain. meski aku sering membuat karya, aku sembarangan membuat karya. aku harus punya dasardalam membuat suatu karya. meski kuliah, aku sendiri setuju kurikulum merdeka, katanya siswa boleh 'belajar' sesuai passion. al hasil, siswa smp baca apalagi berhitung. intinya, sistem pendidikan harus dirancang memancing siswa berpikir mencari solusi kehidupan nyata. sampai sekarang, sekolah mengajar bagaimana menjadi orang jujur dipercaya, bagaimana cara berempati orang-orang lingkungan sekitar, semuanya masiiiihh hanya sekedar mengerjakan lembaran kertas. lihat sendiri to. berita korupsi pungli dimana-mana, diajarkan cara menjadi orang jujur dipercaya, tanah adat dirusak diekploitasi, investor datang dicegat ormas, diajarkan cara berempati. selain masalah buang sampah sembarangan malas gerak sehingga menggunakan kendaraan bermotor, tawuran bentuk kurangnya pendidikan mengenai kepedulian alam sosial. harus lakukan dikerjakan 1 orang saya pribadi.\"\n",
"* **Sentimen Komentar:** Positif\n",
"* **Insights:** Komentar ini menyoroti kekecewaan terhadap sistem pendidikan Indonesia yang berfokus pada hafalan dan kurangnya pengembangan pemikiran kritis, dengan harapan adanya perubahan ke arah kurikulum merdeka. Meskipun kritik yang tajam, adanya harapan dan perbandingan dengan sistem pendidikan yang lebih baik kemungkinan besar membuat sentimennya tergolong Positif karena mendorong perubahan. Jumlah 'like' yang tinggi menunjukkan banyak penonton yang setuju atau merasakan hal yang sama.\n",
"\n",
"---\n",
"\n",
"### Slide 13: Estimasi Gender Komentator\n",
"* **Metode:** Heuristik Sederhana Berbasis Kata Kunci dalam Username.\n",
"* **Bagaimana Dilakukan:**\n",
" * Daftar kata kunci laki-laki (`male_keywords`: ['putra', 'budi', 'agus', 'rizal', 'eko', 'joko']) dan perempuan (`female_keywords`: ['putri', 'siti', 'ayu', 'indah', 'dewi', 'ani']) dibuat.\n",
" * Fungsi `estimate_gender` memeriksa username untuk menemukan kata kunci ini.\n",
" * Kolom `Estimated_Gender` ditambahkan ke DataFrame `df`.\n",
"* **Contoh Hasil:**\n",
" * Sebagian besar `Estimated_Gender` saat ini adalah 'Tidak Diketahui' karena nama pengguna seringkali tidak mengandung kata kunci yang jelas.\n",
"* **Keterbatasan:** Metode ini sangat dasar dan memiliki akurasi yang rendah. Estimasi gender yang lebih akurat memerlukan pendekatan yang lebih canggih (misalnya, basis data nama-nama umum, model pembelajaran mesin)."
]
}
],
"metadata": {
"colab": {
"provenance": []
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}