-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubmision_movie_recomendation_update_dua.py
945 lines (670 loc) · 40.9 KB
/
submision_movie_recomendation_update_dua.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
# -*- coding: utf-8 -*-
"""Submision_Movie_Recomendation_Update_Dua.ipynb
Automatically generated by Colab.
Original file is located at
https://colab.research.google.com/drive/1TlQGS_oNUPb8_WVtEyhTTtiI_TjyQxEp
# PROYEK REKOMENDASI FILM
- Nama: [Maklon Jaco Frare] <br>
- Email: [[email protected]] <br>
- ID Dicoding: [maklon]
# DATA LOADING
## Import Library
"""
# Commented out IPython magic to ensure Python compatibility.
import shutil
import os
import zipfile
import pandas as pd
import numpy as np
import seaborn as sns
from scipy import stats
from ast import literal_eval
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Embedding, Flatten, Dense
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import layers
from keras.callbacks import EarlyStopping
from keras.models import Sequential
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_squared_error, mean_absolute_error, accuracy_score
import matplotlib.pyplot as plt
import missingno as msno
from wordcloud import WordCloud
# %matplotlib inline
from google.colab import files
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
from sklearn.utils import shuffle
from scipy.sparse import csr_matrix # Untuk struktur sparse
from sklearn.model_selection import train_test_split
"""## Download Dataset dan Extrak Dataset
Pada tahap, kita akan mengambil dataset dari luar (Kaggle) yakni Dataset The Movies Dataset yang diupload oleh
Rounak Banik. Datasetnya dapat dilihat pada [tautan ini](https://www.kaggle.com/datasets/rounakbanik/the-movies-dataset)
"""
#!kaggle datasets download -d rounakbanik/the-movies-dataset
"""Selanjutnya, kita akan mengekstrak file zip dan mengambil dataset dalam format csv"""
#!unzip "the-movies-dataset.zip"
"""## Copy Dataset File to Drive
Pada tahap ini, kita akan menyalin file csv yang akan diolah. Pada proyek ini kita hanya menggunakan file `movies_metadata.csv` dan `rating.csv`. Langkah awal kita hubungankan colab ke drive kita dengan fungsi `mount`
"""
# impor library drive untuk salin data ke drive kita
from google.colab import drive
drive.mount('/content/drive')
"""Selanjutnya, kita salin file `mivies_metadata.csv` dan `ratings.csv` dari folder content google colab ke folder MoviesDataset google drive kita"""
#!cp {"/content/movies_metadata.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/ratings_small.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/ratings.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/credits.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/keywords.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/links.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
#!cp {"/content/links_small.csv"} {"/content/drive/MyDrive/Dataset/MoviesDataset"}
"""## Reading Data
Pada tahap ini kita akan membaca dataset kita yang sudah tersalin pada drive kita
"""
# Path folder yang ingin dihitung
folder_path = "/content/drive/MyDrive/Dataset/MoviesDataset"
# Menghitung jumlah file di dalam folder
file_count = len([f for f in os.listdir(folder_path) if os.path.isfile(os.path.join(folder_path, f))])
# Menghitung jumlah folder di dalam folder
folder_count = len([f for f in os.listdir(folder_path) if os.path.isdir(os.path.join(folder_path, f))])
print(f"Jumlah File Dataset Sebanyak: {file_count}")
# menyimpan dataset dalam variabel
movies = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/movies_metadata.csv', low_memory=False)
ratings = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/ratings_small.csv', low_memory=False)
ratings_all = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/ratings.csv', low_memory=False)
keywords = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/keywords.csv', low_memory=False)
credits = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/credits.csv', low_memory=False)
links = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/links.csv', low_memory=False)
links_small = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/links_small.csv', low_memory=False)
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data film sebanyak: ', len(movies.id.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data rating yang diberikan pengguna pada semua file rating (ratings.csv) sebanyak: ', len(ratings_all))
print('Jumlah data pengguna yang memberikan rating pada semua file rating (ratings.csv) sebanyak: ', len(ratings_all.userId.unique()))
print('Jumlah data film yang diberikan rating oleh pengguna pada semua file rating (ratings.csv) sebanyak: ', len(ratings_all.movieId.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data rating pada sebagian file rating (ratings_small.csv) sebanyak: ', len(ratings))
print('Jumlah data pengguna yang memberikan rating pada sebagian file rating (ratings_all.csv) sebanyak: ', len(ratings.userId.unique()))
print('Jumlah data film yang diberikan rating oleh pengguna pada sebagian file rating (ratings_all.csv) sebanyak: ', len(ratings.movieId.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data kata kunci sebanyak: ',len(keywords.id.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data pemeran dan kru untuk semua film sebanyak: ', len(credits.id.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data ID TMDB dan IMDB dari semua film sebanyak: ', len(links.movieId.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
print('Jumlah data ID TMDB dan IMDB dari sebagian kecil film dari Kumpulan Data Lengkap sebanyak: ', len(links_small.movieId.unique()))
print('----------------------------------------------------------------------------------------------------------------------')
"""Berdasarkan varibel-variabel dataset di ataas, kita cukup mengambil variabel sesuai kebutuhan analisis dan pelatihan model pada proyek ini yakni movies dan rating.
# Exploratory Data Analysis (EDA)
## Univariate Analysis
Pada tahap ini kita akan melihat variabel dataset serta menggunakan grafik untuk menggambarkan distribusi genre dan rating film, serta hubungan antara fitur-fitur dalam dataset.
### Deskripsi Variabel
Pada langkah ini kita akan menampilkan informasi variabel ratings dan movies dengan fungsi `info`. Pertama kita mulai cek variabel ratings
"""
ratings.info()
"""Berdasarkan gambar diatas, variabel ratings terdiri dari 100004 baris dan 4 kolom yang dapat dijelaskan sebagai berikut:
| Variabel | Keterangan |
| ----------------------- | ------------------------------------------------------------------------- |
| userId | ID unik untuk pengguna yang memberikan penilaian (rating). Ini digunakan untuk mengidentifikasi pengguna secara anonim. |
| movieId|ID unik untuk film yang dinilai oleh pengguna untuk mendapatkan informasi lebih detail tentang film tersebut. |
| rating | Nilai yang diberikan oleh pengguna untuk film tertentu dengan skala 1 hingga 5, di mana angka yang lebih tinggi menunjukkan penilaian yang lebih positif. |
| timestamp | Waktu ketika penilaian diberikan, direpresentasikan dalam format UNIX timestamp (jumlah detik sejak 1 Januari 1970). |
Kedua kita cek variabel movies
"""
movies.info()
"""Berdasarkan gambar diatas, variabel movies terdiri dari 100004 baris dan 24 kolom yang dapat dijelaskan sebagai berikut:
| Variabel | Keterangan |
| ----------------------- | ------------------------------------------------------------------------- |
|adult | Mengindikasikan apakah film tersebut untuk orang dewasa (adult content). Nilainya biasanya True atau False.|
|belongs_to_collection|Informasi tentang koleksi atau seri film tertentu yang mencakup film ini (misalnya, film dalam seri Harry Potter). Biasanya berupa JSON atau string deskriptif.|
|Budget|Anggaran produksi film dalam satuan mata uang (biasanya USD). Nilainya berupa angka.|
|genres|Daftar genre film, seperti Action, Comedy, Drama. Biasanya berupa JSON atau daftar string.|
|homepage|URL dari situs web resmi film tersebut.|
|id|ID unik untuk film, biasanya merujuk pada database film tertentu seperti TMDb.|
|imdb_id|ID unik dari film di IMDb (misalnya, tt1234567).|
|original_language|Bahasa asli film tersebut dalam format kode bahasa ISO 639-1 (misalnya, en untuk bahasa Inggris).|
|original_title|Judul asli film dalam bahasa produksinya.|
|overview|Judul asli film dalam bahasa produksinya.|
|popularity|Skor popularitas film berdasarkan sistem tertentu, sering dihitung menggunakan algoritma dari platform film.|
|poster_path|Path atau tautan menuju gambar poster film. Biasanya berupa path yang dapat digabungkan dengan URL dasar untuk akses.|
|production_companies|Informasi tentang perusahaan produksi film tersebut. Biasanya berupa JSON dengan nama dan ID perusahaan.|
|production_countries|Negara tempat film tersebut diproduksi. Biasanya berupa JSON dengan nama negara dan kode negara.|
|release_date|Tanggal rilis film (format: YYYY-MM-DD).|
|revenue|Pendapatan kotor yang diperoleh film (biasanya dalam USD).|
|runtime|Durasi film dalam menit.|
|spoken_languages|Bahasa yang digunakan dalam dialog film. Biasanya berupa JSON dengan nama dan kode bahasa.|
|status|Status rilis film (misalnya, Released, In Production).|
|tagline|Slogan atau frasa singkat yang biasanya digunakan untuk promosi film.|
|title|Judul utama film yang digunakan untuk promosi.|
|video|Mengindikasikan apakah ada video terkait film. Nilainya biasanya berupa True atau False.|
|vote_average|Nilai rata-rata yang diberikan oleh pengguna (misalnya dari IMDb atau TMDb) berdasarkan skala tertentu (biasanya 1-10).|
|vote_count|Jumlah suara atau ulasan yang diberikan untuk film tersebut.|
Kedua gambar diatas merupakan informasi variabel movies dan rating dataset kita.
### Melihat Infromasi Tipe Data
Pada tahap ini, kita akan melihat informasi pada dataset *ratings* dan *movies*
"""
tipe_data_movies = movies.dtypes.value_counts()
tipe_data_movies
tipe_data_ratings = ratings.dtypes.value_counts()
tipe_data_ratings
"""Dapat dilihat pada informasi dataset **movies** 20 variable dengan tipe data object dan 4 variabel bertipe float64. Sedangkan pada informasi dataset **ratings** terdapat 1 variabel dengan tipe data float64 dan 3 variable dengan tipe data int64.
### Menghitung Total Dataset
Pertama, kita akan melihat total dataset `ratings` dan `movies`
"""
rows_movie = movies.shape[0]
cols_movie = movies.shape[1]
rows_rating = ratings.shape[0]
cols_rating = ratings.shape[1]
print(f'Jumlah data Movie sebanyak {rows_movie}, dan memiliki {cols_movie} kolom')
print(f'Jumlah data Rating sebanyak {rows_rating}, dan memiliki {cols_rating} kolom')
"""### Menghitung Total Data Unik"""
print(f"Jumlah film unik pada dataset movies : {movies['id'].nunique()}")
print(f"Jumlah film unik pada dataset ratings: {ratings['movieId'].nunique()}")
print(f"Jumlah user unik pada dataset ratings: {ratings['userId'].nunique()}")
"""Dari hasil diatas terdapat 45436 film pada dataset movies, 9066 film pada dataset ratings dan 671 user pada dataset ratings
### Melihat Data Deskriptif pada variabel dataset
"""
movies.describe()
ratings.describe()
"""Berdasarkan tampilan deskriptif dataset movies dan ratings dapat dilihat tidak mencolok ada pesebaran nilai yang menimbulkan `outlier`
### Distribusi Ratings
Pada langkah ini kita akan mendistribusi ratings dengan tujuan:
1. Mengidentifikasi nilai rating yang paling umum diberikan oleh pengguna.
2. Menilai apakah data rating cenderung condong ke satu nilai (misalnya, lebih banyak rating tinggi atau rendah).
3. Membantu memahami pola preferensi pengguna.
"""
#Mengelompokkan data berdasarkan kolom rating dan menghitung jumlah baris (count) untuk setiap nilai rating
count_rates = ratings.groupby('rating').count()
#Menghitung persentase jumlah rating tertentu terhadap total jumlah rating.
count_rates['percents_total']=round(count_rates['userId']*100/count_rates['userId'].sum(),1)
# Memvisualisasikan kolom perc_total dalam bentuk diagram batang menggunakan fungsi plot.bar()
# Membuat diagram batang
ax = count_rates['percents_total'].plot.bar(color='#0A3981', figsize=(8, 5))
# Menambahkan label persentase pada batang
for index, value in enumerate(count_rates['percents_total']):
plt.text(index, value + 0.5, f'{value}%', ha='center', fontsize=10)
# Memberikan label pada sumbu
plt.xlabel('Rating', fontsize=12)
plt.ylabel('Presentasi (%)', fontsize=12)
plt.title('Presentasi rating', fontsize=14)
"""Berdasarkan diagram plot rating diatas, dapat dilihat bahwa nilai ratings paling umum diberikan pengguna adalah rating 4.0 dengan presentasi 28.7%, rating 3.0 dengan presentasi 20.1%, rating 5.0 dengan prestansi 15.1%. Sedangkan nilai rating yang lain berada dibawah pada presentasi 12.0%
### Distribusi Genres
Pada tahap ini kita akan membersihkan, memproses, dan menormalkan data dalam kolom genres pada DataFrame df_movies. Ada beberapa fungsi yang kita pakai yakni:
* `fillna('[]')`, berfungsi untuk mengisi nilai`null` atau `NaN` dalam kolom genres dengan string kosong dalam format `list` ('[]').
* `apply(literal_eval)`, fungsi `literal_eval` dari pustaka `ast` untuk mengubah string yang terlihat seperti Python literal menjadi tipe data `list`.
* `apply(lambda x: [i['name'] for i in x] if isinstance(x, list) else []`,
fungsi lambda ini memproses setiap nilai dalam kolom genres:
Jika nilai adalah sebuah daftar `(isinstance(x, list))`, maka ambil nilai dari kunci `name` untuk setiap elemen. Jika nilai bukan daftar, mengembalikan daftar kosong (`[]`).
Langkah pertama kita buat variabel dataframe baru untuk melakukan analisis visualisasi data. Kemudian kita konversi fitur(variabel) genres ke dalam bentuk list sehingga dapat dianalisis.
"""
df_analisis_movies = movies.copy()
df_analisis_movies['genres'] = df_analisis_movies['genres'].fillna('[]').apply(literal_eval).apply(lambda x: [i['name'] for i in x] if isinstance(x, list) else [])
"""Selanjutanya kita ubah setiap elemen dalam daftar (genre) menjadi baris terpisah dengan fungsi `explode()`, kemudian menghitung jumlah kemunculan setiap genre dengan fungsi `value_counts()` dan terakhir kita membuat diagram batang untuk menampilkan distribusi genre dengan plot bar `plot(kind='bar')`."""
# Menghitung distribusi genre
all_genres = df_analisis_movies['genres'].explode() # Mengubah elemen dalam list menjadi baris terpisah
genre_counts = all_genres.value_counts() # Menghitung jumlah tiap genre
# Menampilkan hasil distribusi
print("Distribusi Genre:")
print(genre_counts)
# Gradasi warna dengan cmap
colors = plt.cm.viridis(np.linspace(0, 1, len(genre_counts)))
# Plot distribusi genre
plt.figure(figsize=(18, 6))
genre_counts.plot(kind='bar', color=colors)
plt.title('Distribusi dari Genre', fontsize=14)
plt.xlabel('Genre', fontsize=12)
plt.ylabel('Frekuensi', fontsize=12)
plt.xticks(rotation=45)
plt.show()
"""Dari grafik diatas, dapat dilihat bahwa genre Drama dan Comedy paling banyak tersebar pada setiap film dalam dataset dengan jumah sebesar 20265 dan 13182. Sedangkan genre yang lain berada dibawah 10000. Terlihat juga ada 12 genre dengan jumlah 1.
### Analisis Daftar film dengan skor tertinggi di seluruh rentang film
Untuk membuat daftar film dengan skor tertinggi menggunakan metode `Weighted Score`. Metode ini merupakan perhitungan skor berbobot untuk menggabungkan nilai-nilai yang berbeda berdasarkan pentingnya masing-masing komponen. Dalam konteks film, kita perlu menghitung skor berbobot berdasarkan informasi yang tersedia, seperti rata-rata penilaian (`vote_average`), jumlah suara (`vote_count`), dan jumlah suara rata-rata minimum yang diperlukan untuk dipertimbangkan dalam daftar.
Keterangan:
* v = jumlah suara untuk film tertentu (`vote_count`)
* m = jumlah suara minimum untuk masuk ke daftar (`threshold`)
* R = rata-rata skor film tersebut (`vote_average`)
* C = rata-rata skor semua film dalam dataset (`rata-rata global`)
"""
# Menghitung nilai rata-rata
C = df_analisis_movies['vote_average'].mean()
R = df_analisis_movies['vote_average']
v = df_analisis_movies['vote_count']
# Menentukan nilai m (threshold vote_count minimum)
m = df_analisis_movies['vote_count'].quantile(0.75) # Mengambil persentil ke-75 sebagai threshold
# Menghitung Weighted Score
df_analisis_movies['weighted_score'] = (v / (v + m) * R) + (m / (v + m) * C)
# Menyortir berdasarkan Weighted Score
top_movies = df_analisis_movies.sort_values('weighted_score', ascending=False)
# Menampilkan hasil
print("Daftar 5 Film dengan Skor Tertinggi:")
#top_movies.head(5)
top_movies[['id', 'genres', 'title', 'vote_average', 'vote_count', 'weighted_score']].head(5)
"""Hasil Daftar tabel diatas menunjukan 5 filim dengan skor tertinggi yang diberikan oleh pengguna.
### Melakukan Analisis Rating Tertinggi
Selanjutnya kita gabungkan dataset df_movies dan ratings dengan fungsi pandas `pd.merge` dan mencari 10 film dengan rating tertinggi.
"""
# membuat salinan varibael dataset untuk proses analisis
movies_copy = movies.copy()
# Identifikasi dan tangani nilai tidak valid
movies_copy = movies_copy[movies['id'].apply(lambda x: str(x).isnumeric())]
# Konversi ke tipe int64
movies_copy['id'] = movies_copy['id'].astype('int64')
# df_movies.head()
movies_copy.rename(columns={'id': 'movieId'}, inplace=True)
df_movies = movies_copy.copy()
rating_movies = pd.merge(ratings, df_movies, on='movieId', how='inner')
rating_movies.drop(['timestamp','genres'],axis=1, inplace=True)
df_analisis_rating = pd.DataFrame(rating_movies.groupby('title')['rating'].mean())
df_analisis_rating['total ratings'] = pd.DataFrame(rating_movies.groupby('title')['rating'].count())
df_analisis_rating.rename(columns = {'rating': 'mean ratings'}, inplace=True)
df_analisis_rating.sort_values('total ratings', ascending=False).head(10)
"""Dapat dilihat dari 10 rating tertinggi film yang ada, film dengan judul Terminator 3: Rise of the Machines memiliki rating teratas dengan *mean rating* 4.256 dan total rating sebanyak 324.
### Membandingkan Peringkat rata-rata dan Jumlah total peringkat
Pada tahap ini kita akan membandingkan rata-rata rangkin dan total rangking menggunakan `joinplot` untuk melihat pesebaran data.
"""
sns.jointplot(x = 'mean ratings', y = 'total ratings', data = df_analisis_rating )
"""Berdasarkan grafik pesebaran data diatas total rating terting berada diatas 250 sebanyak 5 film, sadangkan rata-rata terbanyak pengguna memberi rating terhadap film berada diretang nilai 2 - 4.5 rating.
# DATA PREPARATION
## Data Clean
Proses ini bertujuan untuk menyiapkan data mentah agar dapat digunakan secara efektif dalam model machine learning. Setelah data terkumpul ada beberapa langkah yang perlu lakukan dalam tahap ini yaitu:
### Mengambil Fitur Sesuai Kebutuhan
Pada tahap ini, kita hanya mengambil beberapa fitur atau kolom dari variabel movies sesuai kebutuhan analsis pengolahan data yakni `['id', 'genres', 'title', 'vote_average', 'vote_count']`. Kemudian kita simpan pada variabel df_movies.
"""
# Pilih kolom yang diinginkan
selected_features_movies = ['id', 'genres', 'title', 'vote_average', 'vote_count']
# Buat DataFrame baru
df_movies = movies[selected_features_movies]
df_movies.head()
"""### Menyesuaikan Tipe Data Primary Key dan Foregein Key
Jika dilihat pada informasi sebelumnya, dataset movies atribut id (`primary key`) dengan type data `object` berbeda pada dataset ratings atribut movieId dengan type data `int64`. Oleh karena itu,kita perlu menyamakan tipe data tersebut dengan cara mnyamakan nama atribut movieId dan tipe data `int64`.
"""
df_movies_copy = df_movies.copy()
# Identifikasi dan tangani nilai tidak valid
df_movies_copy = df_movies_copy[df_movies['id'].apply(lambda x: str(x).isnumeric())]
# Konversi ke tipe int64
df_movies_copy['id'] = df_movies_copy['id'].astype('int64')
# df_movies.head()
df_movies_copy.rename(columns={'id': 'movieId'}, inplace=True)
df_movies = df_movies_copy.copy()
# Mengubah nama kolom dari 'id' menjadi 'movieId'
#df_movies.rename(columns={'id': 'movieId'}, inplace=True)
"""### Menangani Nilai Kosong (Missing Value)
Pada tap ini kita akan lakukan pengecekan nilai kosong pada variabel dataset df_movies dan ratings
"""
df_movies.isnull().sum()
"""Dari hasil diatas, nilai null terdapat pada variabel `title`, `vote_average` dan `vote_count` memiliki nilai null = 3."""
# Menampilkan baris yang memiliki nilai null
df_movies[df_movies.isnull().any(axis = 1)]
"""Dapat dilihat hasilnya terdapat beberap nilai kosong pada variabel dataset df_movies"""
df_movies = df_movies.dropna(subset=['title', 'vote_average', 'vote_count'])
df_movies.isnull().sum()
ratings.isnull().sum()
"""### Melihat Duplikat Data
Langkah pertama kita cek variabel dataset df_movies
"""
df_movies.duplicated().sum()
#df_movies.head()
"""Selanjutnya kita tampilkan movies yang duplikat"""
# Menampilkan movies duplikat
df_movies[df_movies.duplicated]
"""Dari hasil di atas, terlihat bahwa ada data-data tersebut memang terduplikasi."""
df_movies.drop_duplicates(inplace = True)
"""Kedua kita cek dataset ratings yang duplikat"""
ratings.duplicated().sum()
"""Hasil yang ditampilkan yakni 0 maka tidak ada duplikat data pada dataset ratings
## Data Preprocesing
Proses ini bertujuan untuk menyiapkan data mentah agar dapat digunakan secara efektif dalam model machine learning. Langkah-langkah yang dilakukan dalam proyak ini adalah sebagai berikut:
* Mengurutkan pengguna dan film berdasarkan id
* Mengubah fitur genres movie ke bentuk list
* Melakukan penggabungan dataset ratings dan movies
* Menghapus fitur yang tidak diperlukan
* Mengambil Dataset sesuai kebutuhan
### Mengurutkan pengguna berdasarkan ID
"""
ratings = ratings.sort_values('userId')
df_movies = df_movies.sort_values('movieId')
ratings.head()
df_movies.head()
"""### Mengubah fitur genres movie ke bentuk list"""
df_movies['genres'] = df_movies['genres'].fillna('[]').apply(literal_eval).apply(lambda x: [i['name'] for i in x] if isinstance(x, list) else [])
df_movies['genres']
"""### Melakukan penggabungan Data
Pada tahap ini kita akan mengabungkan dataset ratings dan dataset movies menggunakan fungsi `merge` dan mengahapus variabel `timestamp` yang dibutuhkan.
"""
df_movies_ratings = pd.merge(ratings, df_movies, on='movieId', how='inner')
df_movies_ratings.head()
"""### Menghapus fitur yang tidak diperlukan
Selanjutnya, menghapus fitur-firur yang tidak diperlukan yaitu `timestamp`, `vote_average` dan `vote_count`.
"""
df_movies_ratings.drop(['timestamp', 'vote_average', 'vote_count'],axis=1, inplace=True)
"""Selanjutnya gunakan fungsi `head` untuk melihat hasilnya."""
df_movies_ratings.head(10)
"""### Mengambil Dataset sesuai kebutuhan
Pada tahap ini, kita mengambil 20000 gabugan dataset movies dan ratings dengan teknik sampling menggunakan fungsi `shuffle` dari library `sklearn.utils` untuk mengambil data secara acak dataset besar untuk mempermudah pengolahan dan mencegah **crash**.
"""
df_sample_final = shuffle(df_movies_ratings).head(20000)
df_sample_final
"""# Content Based Filtering (CBF)
Content-Based Filtering adalah metode dalam sistem rekomendasi yang memberikan rekomendasi berdasarkan karakteristik atau konten dari item yang telah disukai atau dinilai oleh pengguna.
## A. Data Preparation
Teknik yang digunakan yaitu teknik TF-IDF (Term Frequency-Inverse Document Frequency) untuk menentukan bobot fitur dan menghitung kesamaan antara item. Pada proyek ini item yang aka kita gunaka yaitu `genres` film.
Langkah yang pertama kita cek datset kita sesuai dengan kebutuhan yang kita inginkan dengan fungsi `info()`
"""
df_sample_final.info()
"""Dapa dilihat hasil informasi dataset kita terdiri dari 20000 baris dan 5 kolom dengan 1 tipe data float64, 2 tipe data int64 dan 2 tipe data object.
Berikutnya, kita bisa melanjutkan ke tahap persiapan dengan membuat variabel preparation yang berisi dataframe df_sample_final kemudian mengurutkan berdasarkan `movieId`
"""
preparation = df_sample_final
preparation.sort_values('movieId')
# Membuang data duplikat pada variabel preparation
preparation = preparation.drop_duplicates('movieId')
preparation
"""Selanjutnya, kita perlu melakukan konversi data series menjadi list. Dalam hal ini, kita menggunakan fungsi `tolist()` dari library numpy."""
# Mengonversi data series 'movieId' menjadi dalam bentuk list
movie_id = preparation['movieId'].tolist()
# Mengonversi data series ‘Title’ menjadi dalam bentuk list
movie_name = preparation['title'].tolist()
# Mengonversi data series ‘Genres’ menjadi dalam bentuk list
movie_genres = preparation['genres'].tolist()
print(len(movie_id))
print(len(movie_name))
print(len(movie_genres))
"""Tahap berikutnya, kita akan membuat dictionary untuk menentukan pasangan key-value pada data `movie_id`, `movie_name` dan `movie_genres` yang telah kita siapkan sebelumnya."""
# Membuat dictionary untuk data ‘movie_id’, ‘movie_name’, dan genres
movies_new = pd.DataFrame({
'id': movie_id,
'movie_name': movie_name,
'genres': movie_genres
})
movies_new
"""Selanjutnya langkah berikut kita gunakan fungsi `TfidfVectorizer` untuk mengkonversi `genres`. Namusn sebelum itu `genres` perlu kita konversi dari list ke siting akar dapay diproses."""
data = movies_new
# Mengonversi list menjadi string dengan pengecekan tipe data
data['genres'] = data['genres'].apply(lambda x: ', '.join(x) if isinstance(x, list) else '')
# Inisialisasi TfidfVectorizer
tf_cbf = TfidfVectorizer()
# Melakukan perhitungan idf pada data track_genre
tf_cbf.fit(data["genres"])
# Mapping array dari fitur index integer ke fitur nama
tf_cbf.get_feature_names_out()
"""Setelah mendapat index seluruh genre film, akan difit lalu ditransformasikan ke bentuk matriks."""
# Melakukan fit lalu ditransformasikan ke bentuk matrix
tfidf_matrix = tf_cbf.fit_transform(data["genres"])
# Melihat ukuran matrix tfidf
tfidf_matrix.shape
"""Setelah dilakukan fit dan ditransformasikan ke bentuk matrix diperoleh ukuran (2266 x 22). Selanjutnya kita akan mengubah vektor tf-idf dalam bentuk matriks dengan fungsi `todense()`."""
# Mengubah vektor tf-idf dalam bentuk matriks dengan fungsi todense()
tfidf_matrix.todense()
"""Setelah dibentuk matriks, dibuat tabel berisi judul film beserta genrenya berdasarkan TF-IDF yang telah diinisiasi."""
# Membentuk tabel dari judul film beserta genrenya berdasarkan tfidf
pd.DataFrame(
tfidf_matrix.todense(),
columns = tf_cbf.get_feature_names_out(),
index = data.movie_name
)
"""## B. Modeling
Pada tahp ini kita gunakan metode `Consine Similarity`, yang berfungsi mengukur kesamaan antara dua dokumen atau vektor dalam ruang multidimensi. Pada proyek ini, kita akan gunakan untuk sistem rekomendasi berbasis `Content-Based Filtering` yang memberikan rekomendasi berdasarkan karakteristik atau konten dari item genre film yang telah disukai atau dinilai oleh pengguna. Menurut Firmansyah(2018), `Cosine similarity` digunakan dalam ruang positif, dimana hasilnya dibatasi antara nilai `0` dan `1`. Kalau nilainya `0` maka dokumen tersebut dikatakan mirip jika hasilnya 1 maka nilai tersebut dikatakan tidak mirip Perhatikan bahwa batas ini berlaku untuk sejumlah dimensi.
Untuk menentukan content-based filtering, pada proyek ini digunakan cosine similarity untuk mencari kemiripan antar film.
"""
# Menghitung cosine similarity pada matrix tf-idf
cosine_sim = cosine_similarity(tfidf_matrix)
cosine_sim
# Menghitung cosine similarity
cosine_sim_df = pd.DataFrame(cosine_sim, index = data["movie_name"], columns = data["movie_name"])
print('Shape:', cosine_sim_df.shape)
# Melihat similarity matrix pada setiap film
cosine_sim_df.sample(10, axis = 1).sample(10, axis = 0)
"""Selanjutnya kita buat fungsi rekomendasi film berdasarkan kemiripan genre dengan menerapkan fungsi Top-N rekokemendasi"""
def film_recommendations(nama_film, similarity_data=cosine_sim_df, items=data[['movie_name', 'genres']], k=10):
# Mengambil data dengan menggunakan argpartition untuk melakukan partisi secara tidak langsung sepanjang sumbu yang diberikan
# Dataframe diubah menjadi numpy
# Range(start, stop, step)
index = similarity_data.loc[:,nama_film].to_numpy().argpartition(
range(-1, -k, -1))
# Mengambil data dengan similarity terbesar dari index yang ada
closest = similarity_data.columns[index[-1:-(k+2):-1]]
# Drop nama_film agar nama filim yang dicari tidak muncul dalam daftar rekomendasi
closest = closest.drop(nama_film, errors='ignore')
return pd.DataFrame(closest).merge(items).head(k)
"""## C. Pengujian Sistem Rekomendasi
Pada tahap ini, kita akan melakukan pengujian model yang dibuat.
"""
data[data.movie_name.eq('The Man with the Golden Arm')]
# Mendapatkan rekomendasi film yang mirip dengan yang dipilih
recommended_movies = film_recommendations('The Man with the Golden Arm')
recommended_movies
"""Hasil yang ditampilkan akan berupa judul film yang memiliki kesaaman genre.
## D. Evaluation
Pada tahap evaluasi model kita gunakan metrik precision untuk menghitung proporsi prediksi positif yang benar (`True Positives`) dibandingkan dengan semua prediksi positif (`True Positives` + `False Positives`).
"""
relevant_genres = {"Crime", "Drama", "Romance"} # gunakan set agar urutan tidak penting
# Fungsi untuk memeriksa kecocokan genre
def is_relevant(genres):
genres_set = set(genres.split(', ')) # ubah string genre menjadi set
return relevant_genres.issubset(genres_set) # periksa apakah semua genre relevan ada dalam genres_set
# Tambahkan kolom apakah film relevan
recommended_movies['is_relevant'] = recommended_movies['genres'].apply(is_relevant)
# Hitung True Positives dan Total Recommended
true_positives = recommended_movies['is_relevant'].sum()
total_recommended = len(recommended_movies)
# Precision
precision = true_positives / total_recommended * 100
print(f"Precision: {precision:.2f}%")
"""Dari hasil diatas, nilai metriks precesion sebesar 100.00% untuk 10 film yang direkomendasikan berdasarkan kemiripan genre.
# Collaborative Filtering (CF)
Model-Based Deep Learning Collaborative Filtering adalah pendekatan yang menggabungkan teknik collaborative filtering dengan metode deep learning untuk meningkatkan akurasi dan efektivitas sistem rekomendasi. Ada beberapa langkah persiapan untuk melakukan pelatiahn model dalam tahap ini yang dapat dijelaskan sebagai berikut:
## A. Data Preparation
Langkah pertama, kita cek dataset kita dengan fungsi `info()`
"""
df_sample_final.info()
"""Dari hasil diatas, terdapat 20000 baris dan 7 kolom dan memiliki 3 tipe data `float64`, 2 tipe data `int64` dan 2 tipe data `object`.
Kedua, kita hapus kolom yang tidak dibutuhkan dalam pelatihan.
"""
# Menghapus kolom 'title'
df_sample_final = df_sample_final.drop(columns=['genres', 'title'])
"""Langkah berikutnya kita urutkan berdasarkan kolom `userId`"""
df_sample_final = df_sample_final.sort_values('userId')
"""## Encoding userId dan movieId
Langkah pertama kita lakukan encoding pada `userId`
"""
# Mengubah userID menjadi list tanpa nilai yang sama
user_ids = df_sample_final['userId'].unique().tolist()
print('list userID: ', user_ids)
# Melakukan encoding userID
user_to_user_encoded = {x: i for i, x in enumerate(user_ids)}
print('encoded userID : ', user_to_user_encoded)
# Melakukan proses encoding angka ke ke userID
user_encoded_to_user = {i: x for i, x in enumerate(user_ids)}
print('encoded angka ke userID: ', user_encoded_to_user)
"""Langkah kedua, lakukan hal yang sama pada `movieId`."""
# Mengubah placeID menjadi list tanpa nilai yang sama
movie_ids = df_sample_final['movieId'].unique().tolist()
print('list movieId: ', movie_ids)
# Melakukan proses encoding placeID
movie_to_movie_encoded = {x: i for i, x in enumerate(movie_ids)}
print('encoded movieId : ', movie_to_movie_encoded)
# Melakukan proses encoding angka ke placeID
movie_encoded_to_movie = {i: x for i, x in enumerate(movie_ids)}
print('encoded angka ke movieId: ', movie_encoded_to_movie)
"""Setelah proses encoding selesai, kita petakan `userId` dan `movieId` ke dataframe yang berkaitan."""
# Mapping userID ke dataframe user
df_sample_final['user'] = df_sample_final['userId'].map(user_to_user_encoded)
# Mapping placeID ke dataframe movie
df_sample_final['movie'] = df_sample_final['movieId'].map(movie_to_movie_encoded)
"""Selanjutnya kita ambil total_user, total movie dan nilai rating minimum dan maksimum untuk proses pembagian dataset sebelum melakukan pelatihan"""
# Mendapatkan jumlah user
total_user = len(user_to_user_encoded)
print(total_user)
# Mendapatkan jumlah movie
total_movies = len(movie_encoded_to_movie)
print(total_movies)
# Mengubah rating menjadi nilai float
df_sample_final['rating'] = df_sample_final['rating'].values.astype(np.float32)
# Nilai minimum rating
min_rating = min(df_sample_final['rating'])
# Nilai maksimal rating
max_rating = max(df_sample_final['rating'])
print('Number of User: {}, Number of Movie: {}, Min Rating: {}, Max Rating: {}'.format(
total_user, total_movies, min_rating, max_rating
))
"""Dapat dilihat hasilnya, kita memiliki 669 user, 2277 movie dan rating minimim 0.5 dan rating maksimum 5.0
### Membagi Data untuk Training dan Validasi
Pada tahap ini kita membagi data training dan data validasi untuk proses pelatihan model. Namusn sebelum itu kita perlu mengacak dataset kita sehingga menjadi data yang valid.
"""
# Mengacak dataset
df_sample_final = df_sample_final.sample(frac=1, random_state=42)
df_sample_final
"""Selanjutnya kita buat variabel x untuk mencocokkan data user dan Movie menjadi satu value, kemudian variabel y untuk membuat rating dari hasil. Terakhir kita Membagi menjadi 80% data train dan 20% data validasi"""
x = df_sample_final[['user', 'movie']].values
y = df_sample_final['rating'].apply(lambda x: (x - min_rating) / (max_rating - min_rating)).values
train_indices = int(0.8 * df_sample_final.shape[0])
x_train, x_val, y_train, y_val = (
x[:train_indices],
x[train_indices:],
y[:train_indices],
y[train_indices:]
)
print(x, y)
"""## B. Modeling
Pada tahap ini, model menghitung skor kecocokan antara user dan movie teknik embedding. Pertama, kita melakukan proses embedding terhadap data user dan movie. Selanjutnya, lakukan operasi perkalian dot product antara embedding user dan movie. Selain itu, kita juga dapat menambahkan bias untuk setiap user dan movie. Skor kecocokan ditetapkan dalam skala [0,1] dengan fungsi aktivasi sigmoid. Di sini, kita membuat class RecommenderNet dengan keras Model class.
"""
class RecommenderNet(tf.keras.Model):
# Insialisasi fungsi
def __init__(self, total_user, total_movies, embedding_size, **kwargs):
super(RecommenderNet, self).__init__(**kwargs)
self.total_user = total_user
self.total_movies = total_movies
self.embedding_size = embedding_size
self.user_embedding = layers.Embedding( # layer embedding user
total_user,
embedding_size,
embeddings_initializer = 'he_normal',
embeddings_regularizer = keras.regularizers.l2(1e-6)
)
self.user_bias = layers.Embedding(total_user, 1) # layer embedding user bias
self.movie_embedding = layers.Embedding( # layer embeddings movie
total_movies,
embedding_size,
embeddings_initializer = 'he_normal',
embeddings_regularizer = keras.regularizers.l2(1e-6)
)
self.movie_bias = layers.Embedding(total_movies, 1) # layer embedding movie bias
def call(self, inputs):
user_vector = self.user_embedding(inputs[:,0]) # memanggil layer embedding 1
user_bias = self.user_bias(inputs[:, 0]) # memanggil layer embedding 2
movie_vector = self.movie_embedding(inputs[:, 1]) # memanggil layer embedding 3
movie_bias = self.movie_bias(inputs[:, 1]) # memanggil layer embedding 4
dot_user_movie = tf.tensordot(user_vector, movie_vector, 2)
x = dot_user_movie + user_bias + movie_bias
return tf.nn.sigmoid(x) # activation sigmoid
"""Selanjutnya, lakukan proses compile terhadap model."""
model = RecommenderNet(total_user, total_movies, 50) # inisialisasi model
# model compile
model.compile(
loss=tf.keras.losses.MeanSquaredError(),
optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),
metrics=[
tf.keras.metrics.MeanAbsoluteError(name="mean_absolute_error"),
tf.keras.metrics.RootMeanSquaredError(name="root_mean_squared_error")
]
)
"""Model ini menggunakan Binary Crossentropy untuk menghitung loss function, Adam (Adaptive Moment Estimation) sebagai optimizer, dan root mean squared error (RMSE) sebagai metrics evaluation.
Langkah berikutnya, mulailah proses training. Pada proses ini kita gunakan fungsi `callbacks`, dimana jika kinerja model tidak mengalami keanaikan maka pelatiahan dihentikan. Pada proses training parameter yang digunakan yakni `batch_size=8`, `epoch = 50`, `shuffle = True` dan `verbose=1`
"""
callbacks = EarlyStopping(
min_delta=0.0001,
patience=7,
restore_best_weights=True,
)
# Memulai training
history = model.fit(
x = x_train,
y = y_train,
batch_size = 8,
shuffle = True,
epochs = 50,
validation_data = (x_val, y_val),
verbose=1,
callbacks=[callbacks]
)
"""Dapat dilihat, hasil pelatiahn memperoleh nilai mean_absolute_error: 0.1374 dan root_mean_squared_error: 0.1760
## C. Pengujian Rekomendasi Movie CF
Sebelumnya, pengguna telah memberi rating pada beberapa film yang telah mereka nonton. Kita menggunakan rating ini untuk membuat rekomendasi film yang mungkin cocok untuk pengguna.
"""
movies_df = movies_new
df = pd.read_csv('/content/drive/MyDrive/Dataset/MoviesDataset/ratings_small.csv')
# Mengambil sample user
user_id = df.userId.sample(1).iloc[0]
movie_watch_by_user = df[df.userId == user_id]
# Operator bitwise (~), bisa diketahui di sini https://docs.python.org/3/reference/expressions.html
movie_not_watch = movies_df[~movies_df['id'].isin(movie_watch_by_user.movieId.values)]['id']
movie_not_watch = list(
set(movie_not_watch)
.intersection(set(movie_to_movie_encoded.keys()))
)
movie_not_watch = [[movie_to_movie_encoded.get(x)] for x in movie_not_watch]
user_encoder = user_to_user_encoded.get(user_id)
user_movie_array = np.hstack(
([[user_encoder]] * len(movie_not_watch), movie_not_watch)
)
"""Selanjutnya, untuk memperoleh rekomendasi film, gunakan fungsi `model.predict()` dari library Keras dengan menerapkan kode berikut."""
ratings_pre = model.predict(user_movie_array).flatten()
top_ratings_indices = ratings_pre.argsort()[-10:][::-1]
recommended_movie_ids = [
movie_encoded_to_movie.get(movie_not_watch[x][0]) for x in top_ratings_indices
]
print('Rekomendasi Film untuk Pengguna dengan ID: {}'.format(user_id))
print()
print('----' * 20)
print('Film dengan rating tertinggi untuk pengguna:')
print('----' * 20)
top_movie_user = (
movie_watch_by_user.sort_values(
by = 'rating',
ascending=False
)
.head(5)
.movieId.values
)
movie_df_rows = movies_df[movies_df['id'].isin(top_movie_user)]
for row in movie_df_rows.itertuples():
print(row.movie_name, ':', row.genres)
print()
print('----' * 20)
print('Rekomendasi 10 Film Terbaik:')
print('----' * 20)
no=1
recommended_movie = movies_df[movies_df['id'].isin(recommended_movie_ids)]
for row in recommended_movie.itertuples():
print('----' * 20)
print('No :', no)
print('Nama Film :', row.movie_name)
print('Genre :', row.genres)
print('----' * 20)
no += 1
"""## D. Evaluation
### Visualisasi Metriks
Pada tahap ini kita akana lakukan visualisasi metrik seperti **Mean Absolute Error (MAE)** dan **Root Mean Squared Error (RMSE)**. Kedua metrik ini sangat penting dalam mengevaluasi kinerja model prediksi. Kedua metrik ini memberikan informasi tentang seberapa baik model dapat memprediksi nilai aktual, dan visualisasi dapat membantu dalam memahami perbandingan antara keduanya serta tren kesalahan dari waktu ke waktu.
#### Mean Absolute Error Plot
"""
plt.plot(history.history['mean_absolute_error'])
plt.plot(history.history['val_mean_absolute_error'])
plt.title('model_metrics')
plt.ylabel('mean_absolute_error')
plt.xlabel('epoch')
plt.legend(['mean_absolute_error', 'val_mean_absolute_error'])
plt.show()
"""Berdasarkan hasil `fitting` nilai konvergen metrik MAE berada sedikit dibawah 0.1374 untuk training dan sedikit diatas 0.1500 untuk validasi.
#### Root Mean Squared Error Plot
"""
plt.plot(history.history['root_mean_squared_error'])
plt.plot(history.history['val_root_mean_squared_error'])
plt.title('model_metrics')
plt.ylabel('root_mean_squared_error')
plt.xlabel('epoch')
plt.legend(['root_mean_squared_error', 'val_root_mean_squared_error'])
plt.show()
"""Berdasarkan hasil fitting nilai konvergen metrik RMSE berada sedikit diatas 0.1760 untuk training dan sedikit dibawah 0.180 untuk validasi."""