{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Data Mining\n", "\n", "## Tugas 5: Sistem Rekomendasi\n", "\n", "### Mekanisme\n", "\n", "Anda hanya diwajibkan untuk mengumpulkan file ini saja ke uploader yang disediakan di http://elearning2.uai.ac.id/. Ganti nama file ini saat pengumpulan menjadi **tugas5_NIM.ipynb**.\n", "\n", "**Keterlambatan**: Pengumpulan tugas yang melebihi tenggat yang telah ditentukan tidak akan diterima. Keterlambatan akan berakibat pada nilai nol untuk tugas ini.\n", "\n", "**Kolaborasi**: Anda diperbolehkan untuk berdiskusi dengan teman Anda, tetapi *dilarang keras* menyalin kode maupun tulisan dari teman Anda.\n", "\n", "### Petunjuk\n", "\n", "Terdapat enam *packages* yang Anda akan gunakan dalam mengerjakan tugas ini, yaitu:\n", "\n", "- matplotlib\n", "- numpy\n", "- pandas\n", "- scipy\n", "- seaborn\n", "- scikit-learn\n", "\n", "Anda diperbolehkan (jika dirasa perlu) untuk mengimpor modul tambahan untuk tugas ini, kecuali dijelaskan sebaliknya. Namun, seharusnya modul yang tersedia sudah cukup untuk memenuhi kebutuhan Anda.\n", "\n", "Pastikan jawaban Anda singkat, padat, dan jelas. Mayoritas pertanyaan yang diberikan dapat dijawab dalam 3-4 kalimat saja." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**NIM: **\n", "\n", "**Nilai akhir: XX/70**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Import" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "import numpy as np\n", "import pandas as pd\n", "import seaborn as sns\n", "%matplotlib inline\n", "\n", "RANDOM_STATE = 538\n", "plt.style.use('fivethirtyeight')\n", "plt.rcParams['figure.figsize'] = (15.0, 7.0)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "df = pd.read_csv('../dataset/lastfm/user_artists.dat', delimiter='\\t')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Deskripsi Dataset\n", "\n", "Dataset yang digunakan dalam tugas ini merupakan data pengguna mendengarkan seorang artis/musisi dari situs [Last.fm](https://www.last.fm/). Dalam dataset ini, terdapat 92,834 pasang pengguna-artis dari 17,632 artis dan 1,892 pengguna. Terdapat atribut *weight* yang menggambarkan berapa kali pengguna mendengarkan seorang artis.\n", "\n", "Tugas Anda adalah menghasilkan *root mean squared error* (RMSE) serendah mungkin dengan masing-masing metode yang digunakan. Gunakan pengetahuan yang telah Anda dapatkan dari materi dan tugas-tugas sebelumnya.\n", "\n", "### Referensi\n", "\n", "Cantador, I., Brusilovsky, P.L. and Kuflik, T., 2011. Second workshop on information heterogeneity and fusion in recommender systems (HetRec2011).\n", "\n", "Beberapa konsep yang diterapkan dalam tugas ini dapat Anda lihat dalam buku [Mining of Massive Datasets](http://www.mmds.org/#book) (Leskovec et al., 2014) pada [Chapter 9](http://infolab.stanford.edu/~ullman/mmds/ch9.pdf)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1. Eksplorasi Dataset (20 poin)\n", "\n", "Pada bagian ini, Anda diminta untuk melakukan eksplorasi awal dari dataset yang terbatas ini. Anda juga diminta untuk membuat prediksi *weight* dengan menggunakan beberapa metode sederhana, yaitu dengan pencarian rata-rata dan median." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.1.a (2 poin)\n", "\n", "Kelompokkan data berdasarkan `artistID`, lalu jumlahkan `weight`-nya. Hal ini dilakukan untuk melihat sebaran artis-artis yang populer untuk didengarkan di last.fm." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.1.b (1 poin)\n", "\n", "Anda dapat mengubah nilai yang telah dijumlahkan di atas dengan transformasi logaritmik terlebih dahulu. Gambarkan kembali histogramnya. Apa yang terjadi?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": false }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.1.c (2 poin)\n", "\n", "Apa yang dapat Anda amati dari distribusi di atas? Mengapa hal ini dapat terjadi?" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Jawaban Anda di sini*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.2.a (1 poin)\n", "\n", "Bagi data menjadi dua variabel: `train` dan `test`. Pastikan bahwa Anda melakukan pengacakan urutan data sebelum membaginya dan proporsi data `train`:`test` adalah 70:30.\n", "\n", "*Catatan: Hanya dua variabel yang perlu dihasilkan, bukan `X_train`, `X_test`, `y_train`, `y_test` seperti di tugas-tugas sebelumnya.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sklearn.model_selection import train_test_split" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.2.b (3 poin)\n", "\n", "Buang semua data dalam `test` yang `artistID`-nya tidak ada dalam `train`. Mengapa kita melakukan hal ini?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.3.a (3 poin)\n", "\n", "Salah satu asumsi paling mendasar adalah kita dapat menggunakan rata-rata *weight* yang diberikan oleh seorang pengguna untuk menebak *weight* yang akan diberikan untuk artis tertentu. Oleh karena itu, cari nilai rata-rata untuk *weight* berdasarkan `userID` dalam `train`. Lalu, gunakan nilai rata-rata tersebut untuk memprediksi *weight* yang akan diberikan oleh pengguna tersebut pada artis yang akan didengar pada `test`. Laporkan nilai RMSE-nya." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sklearn.metrics import mean_squared_error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.3.b (3 poin)\n", "\n", "Asumsi lain yang dapat digunakan adalah: seorang pengguna akan mendengarkan seorang artis seperti halnya orang-orang lain akan mendengarkan artis tersebut. Jadi, lakukan hal yang sama seperti pada soal 1.3.a, tetapi ambil nilai rata-rata dengan pengelompokan berdasarkan `artistID`. Laporkan nilai RMSE-nya." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.3.c (2 poin)\n", "\n", "Lakukan prediksi seperti pada bagian a dan b, tetapi kali ini ganti nilai yang akan diprediksi dengan menggunakan median. Apakah hasilnya menjadi lebih baik?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 1.4 (3 poin)\n", "\n", "Berikan kesimpulan sementara dari yang Anda telah temukan sejauh ini." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Jawaban Anda di sini*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 2. Collaborative Filtering (30 poin)\n", "\n", "Sebagai perbandingan, Anda akan membuat prediksi nilai dengan menggunakan metode *collaborative filtering*.\n", "\n", "**Perhatian: Berhati-hatilah dengan bagian ini karena ada banyak manipulasi matriks yang mungkin diperlukan. Selalu lakukan *sanity check*. *Do not procrastinate*.**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.1 (2 poin)\n", "\n", "Buat `X_train` dari hasil pivot `train` dengan menjadikan `userID` sebagai index, `artistID` sebagai kolom, dan `weight` menjadi nilai dari *cell*.\n", "\n", "*Sanity check: Perintah ini seharusnya menghasilkan sparse matrix.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.2.a (2 poin)\n", "\n", "Prediksi dengan *collaborative filtering* berdasarkan pengguna dapat dilakukan dengan menghitung *cosine similarity*. Nilai *similarity* tersebut kemudian akan dijadikan bobot untuk tiap nilai yang akan dihasilkan alih-alih menggunakan k-rekomendasi terbaik.\n", "\n", "Hitung nilai *cosine similarity* dari `X_train` dengan menggunakan fungsi dari `scikit-learn`. Lalu, simpanlah nilai *cosine similarity* tersebut.\n", "\n", "*Cosine similarity* didefinisikan sebagai\n", "$$\n", "sim(u, u^{\\prime}) = \\cos(\\theta) = \\frac{\\mathbf{w}_u \\cdot \\mathbf{w}_{u^{\\prime}}}{\\|\\mathbf{w}_u\\| \\|\\mathbf{w}_{u^{\\prime}}\\|}\n", "$$\n", "dengan $u$ adalah pengguna dan $w_u$ adalah seberapa sering pengguna $u$ mendengarkan daftar artis dalam bentuk vektor.\n", "\n", "*Sanity check: Untuk similarity berdasarkan pengguna, pastikan matriks yang dihasilkan berukuran $U \\times U$ dengan $U$ adalah jumlah pengguna dalam data.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sklearn.metrics.pairwise import cosine_similarity" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.2.b (3 poin)\n", "\n", "Munculkan nilai minimum, maksimum, dan rata-rata dari seluruh *cosine similarity* yang dihasilkan." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.3 (3 poin)\n", "\n", "Hasil prediksi untuk artis yang belum didengar yang kita simpan pada `test` dapat dihitung dengan\n", "\n", "$$\n", "\\hat{w}_{ui} = \\sum_{u^{\\prime}} sim(u,u^{\\prime}) w_{u^{\\prime} i}\n", "$$\n", "\n", "Namun, nilai ini masih perlu dinormalisasi lagi (mengapa?). Hasil prediksi dengan normalisasi menjadi\n", "\n", "$$\n", "\\hat{w}_{ui} = \\frac{\\sum_{u^{\\prime}} sim(u,u^{\\prime}) w_{u^{\\prime} i}}{\\sum_{u^{\\prime}} |sim(u,u^{\\prime})|}\n", "$$\n", "\n", "Dengan menggunakan referensi [ini](http://blog.ethanrosenthal.com/2015/11/02/intro-to-collaborative-filtering/), coba hasilkan prediksi berdasarkan *similarity* dan `X_train` yang telah dibentuk di soal sebelumnya. Lalu, simpan hasilnya ke menjadi `DataFrame` sebagai variabel `X_pred`. Jangan lupa untuk mengisi parameter `index` dengan `X_train.index` dan `columns` dengan `X_train.columns`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.4.a (3 poin)\n", "\n", "Prediksi nilai di data `test` dari `X_pred` yang telah dihasilkan. Laporkan RMSE-nya.\n", "\n", "*Petunjuk: Anda dapat memanfaatkan `test.apply()` lalu menerapkan fungsi lambda yang mengambil prediksi untuk `userID` dan `artistID` tertentu dalam `X_pred`. Pastikan bahwa Anda mengambil weight yang benar dari matriks tersebut. Anda mungkin perlu menghapus variabel `X_pred` setelah selesai digunakan untuk menghemat memory.*" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.4.b (4 poin)\n", "\n", "Bandingkan RMSE tersebut dengan hasil pada bagian 1. Apa yang dapat Anda lihat? Apa yang menyebabkan hasilnya seperti itu dibandingkan dengan metode yang telah dicobakan sebelumnya?\n", "\n", "*Petunjuk: Anda mungkin perlu melihat isi matriks `X_pred`.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.5 (2 poin)\n", "\n", "Apakah hasilnya berbeda jika kita menggunakan fungsi logaritma untuk normalisasi nilai `X_train`? Terapkan proses normalisasi ini pada `X_train`, lalu simpan sebagai `X_normal`. Isi nilai kosong pada `X_train` sementara dengan 0." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.6 (4 poin)\n", "\n", "Hitung nilai *cosine similarity* dari `X_normal`, lalu tampilkan nilai minimum, maksimum, dan rata-rata dari *similarity* yang dihasilkan." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "scrolled": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.7 (3 poin)\n", "\n", "Prediksi kembali *weight* yang diberikan pada data `test`. Hitung nilai RMSE-nya. Apakah hasilnya kali ini lebih baik?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 2.8 (4 poin)\n", "\n", "Berikan kesimpulan yang dapat Anda ambil untuk sistem rekomendasi dengan menggunakan *collaborative filtering* ini." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 3. UV-Decomposition (20 poin)\n", "\n", "Metode lain yang dapat digunakan untuk melakukan prediksi adalah dengan menggunakan proses faktorisasi matriks. Dalam bagian ini, Anda akan melakukan UV-decomposition dengan *routine* yang telah disediakan oleh scikit-learn." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.1.a (2 poin)\n", "\n", "Dengan menggunakan modul `NMF` untuk *non-negative matrix factorization* dengan `n_components=2`. Transformasi `X_train` dengan terlebih dahulu mengisi nilai kosong dengan 0, lalu simpan sebagai `X_transformed`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "from sklearn.decomposition import NMF" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.1.b (2 poin)\n", "\n", "Ide dari UV-decomposition adalah menghasilkan matriks $U$ dan $V$ yang dimensinya jauh lebih kecil dibandingkan $X$. Dari matriks $U$ dan $V$ tersebut, kita akan melakukan inversi dari hasil transformasi untuk mendapatkan aproksimasi untuk nilai yang kosong.\n", "\n", "Lakukan transformasi dan inversnya, kemudian simpan matriks ini sebagai `X_pred`. Jangan lupa untuk mengisi nilai `index` dan `columns` dari `DataFrame` yang dibentuk dengan `X_pred`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.1.c (2 poin)\n", "\n", "Gunakan matriks `X_pred` untuk memprediksi *weight* pada data `test`. Lalu, laporkan RMSE-nya." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.1.d (2 poin)\n", "\n", "Apakah RMSE yang dihasilkan cukup bagus? Kita dapat mengonfirmasi ini dengan melihat nilai error pada aproksimasi yang dihasilkan. Cetak nilai ini dengan menggunakan `.reconstruction_err_`. Apa yang dapat Anda simpulkan dari nilai error ini?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.2.a (4 poin)\n", "\n", "Coba hasilkan faktorisasi matriks dengan menggunakan jumlah komponen $n = [2, 4, 8, 16, 32, 64]$, lalu laporkan *reconstruction error*-nya dalam bentuk *line plot*." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.2.b (3 poin)\n", "\n", "Anda akan melihat bahwa tren error rekonstruksinya selalu menurun seiring dengan bertambahnya jumlah komponen. Apakah dengan menggunakan $n = u$ errornya bisa mendekati nol? Jika bisa, apakah hasil prediksi untuk data `test` akan menjadi lebih baik, lalu apa yang menjadi masalahnya? Jika tidak, jelaskan mengapa hal tersebut tidak mungkin.\n", "\n", "*Petunjuk: Anda mungkin bisa melihat perubahan hasil prediksi ketika $n$ ditambah.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.3 (2 poin)\n", "\n", "Apa yang mungkin perlu dilakukan agar hasil prediksi menggunakan UV-decomposition ini bisa lebih baik?\n", "\n", "*Petunjuk: Anda bisa menggunakan referensi buku Mining of Massive Datasets (Leskovec et al., 2014) pada Section 9.4.*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Soal 3.4 (3 poin)\n", "\n", "Berikan kesimpulan Anda terkait sistem rekomendasi dengan menggunakan UV-decomposition ini." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "_Jawaban Anda di sini_" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4. Bonus (10 poin)\n", "\n", "Apakah Anda dapat menghasilkan prediksi yang lebih baik dengan metode yang lain atau dengan mengembangkan metode yang ada? Anda juga dapat menggunakan data lain dalam folder `dataset/lastfm`." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.2" } }, "nbformat": 4, "nbformat_minor": 1 }