Data yang digunakan pada tugas besar ini merupaka data sekunder IMDB 5000 Movie Dataset yang terdiri dari 28 variabel dan 5043 judul film. Dataset ini mengandung film dengan tahun rilis 1927 hingga 2016.
Sebelum menggali informasi dari dataset ini, dilakukan langkah preprocessing data. Setelah itu dilakukan eksplorasi data. Selanjutnya ingin diketahui metode terbaik dalam melakukan analisis regresi untuk memprediksi skor IMDB sebuah film berdasarkan sejumlah variabel prediktor. Metode yang akan dibandingkan ialah Support Vector Regression, dan K-Nearest Neighbor.
IMDB <- read.csv("C://Users//Admin//Documents//movie_metadata.csv")
library(ggplot2)
library(ggrepel)
library(ggthemes)
library(scales)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(VIM)
## Loading required package: colorspace
## Loading required package: grid
## Loading required package: data.table
##
## Attaching package: 'data.table'
## The following objects are masked from 'package:dplyr':
##
## between, first, last
## VIM is ready to use.
## Since version 4.0.0 the GUI is in its own package VIMGUI.
##
## Please use the package to use the new (and old) GUI.
## Suggestions and bug-reports can be submitted at: https://github.com/alexkowa/VIM/issues
##
## Attaching package: 'VIM'
## The following object is masked from 'package:datasets':
##
## sleep
library(data.table)
library(formattable)
##
## Attaching package: 'formattable'
## The following objects are masked from 'package:scales':
##
## comma, percent, scientific
library(plotly)
##
## Attaching package: 'plotly'
## The following object is masked from 'package:formattable':
##
## style
## The following object is masked from 'package:ggplot2':
##
## last_plot
## The following object is masked from 'package:stats':
##
## filter
## The following object is masked from 'package:graphics':
##
## layout
library(GGally)
##
## Attaching package: 'GGally'
## The following object is masked from 'package:dplyr':
##
## nasa
library(caret)
## Loading required package: lattice
Langkah Preprocessing yang digunakan adalah menghilangkan observasi yang terduplikat, mengatasi missing value, imputasi untuk variabel numerik yang mengandung nilai 0 dan menyeragamkan sistem rating (menjadi sistem rating terbaru yakni G, PG, PG-13, R, dan NC-17), serta mengatasi outlier.
# Mengetahui jumlah data terduplikat
sum(duplicated(IMDB))
## [1] 45
# Menghapus baris yang terduplikat
IMDB <- IMDB[!duplicated(IMDB), ]
# Mengetahui variabel yang mengandung missing value
colSums(sapply(IMDB, is.na))
## color director_name
## 0 0
## num_critic_for_reviews duration
## 49 15
## director_facebook_likes actor_3_facebook_likes
## 103 23
## actor_2_name actor_1_facebook_likes
## 0 7
## gross genres
## 874 0
## actor_1_name movie_title
## 0 0
## num_voted_users cast_total_facebook_likes
## 0 0
## actor_3_name facenumber_in_poster
## 0 13
## plot_keywords movie_imdb_link
## 0 0
## num_user_for_reviews language
## 21 0
## country content_rating
## 0 0
## budget title_year
## 487 107
## actor_2_facebook_likes imdb_score
## 13 0
## aspect_ratio movie_facebook_likes
## 327 0
Karena variabel gross dan variabel budget memiliki jumlah NA yang besar, maka observasi yang menganung NA dihapus.
IMDB <- IMDB[!is.na(IMDB$gross), ] # Menghapus observasi di variabel gross yang mengandung NA
IMDB <- IMDB[!is.na(IMDB$budget), ] # Menghapus observasi di variabel budget yang mengandung NA
IMDB <- IMDB[!(IMDB$content_rating %in% ""),]
Setelah dilakukan penghapusan observasi pada variabel gross dan budget yang mengandung NA, berikut jumlah observasi dan variabel pada dataset yang digunakan.
dim(IMDB)
## [1] 3806 28
# NA pada variabel facenumber in poster diimputasi dengan nilai rata-rata kolom
IMDB$facenumber_in_poster[is.na(IMDB$facenumber_in_poster)] <-
round(mean(IMDB$facenumber_in_poster, na.rm = TRUE))
# Mengubah nilai 0 menjadi NA untuk variabel numerik lain sehingga mempermudah imputasi
dim(IMDB)
## [1] 3806 28
IMDB[,c(5,6,8,13,26)][IMDB[,c(5,6,8,13,26)] == 0] <- NA
# NA diimputasi dengan nilai rata-rata kolom
IMDB$num_critic_for_reviews[is.na(IMDB$num_critic_for_reviews)] <- round(mean(IMDB$num_critic_for_reviews, na.rm = TRUE))
IMDB$duration[is.na(IMDB$duration)] <- round(mean(IMDB$duration, na.rm = TRUE))
IMDB$director_facebook_likes[is.na(IMDB$director_facebook_likes)] <- round(mean(IMDB$director_facebook_likes, na.rm = TRUE))
IMDB$actor_3_facebook_likes[is.na(IMDB$actor_3_facebook_likes)] <- round(mean(IMDB$actor_3_facebook_likes, na.rm = TRUE))
IMDB$actor_1_facebook_likes[is.na(IMDB$actor_1_facebook_likes)] <- round(mean(IMDB$actor_1_facebook_likes, na.rm = TRUE))
IMDB$cast_total_facebook_likes[is.na(IMDB$cast_total_facebook_likes)] <- round(mean(IMDB$cast_total_facebook_likes, na.rm = TRUE))
IMDB$actor_2_facebook_likes[is.na(IMDB$actor_2_facebook_likes)] <- round(mean(IMDB$actor_2_facebook_likes, na.rm = TRUE))
IMDB$movie_facebook_likes[is.na(IMDB$movie_facebook_likes)] <- round(mean(IMDB$movie_facebook_likes, na.rm = TRUE))
# Menyeragamkan sistem Rating film
IMDB$content_rating[IMDB$content_rating == 'M'] <- 'PG'
IMDB$content_rating[IMDB$content_rating == 'GP'] <- 'PG'
IMDB$content_rating[IMDB$content_rating == 'X'] <- 'NC-17'
IMDB$content_rating[IMDB$content_rating == 'Approved'] <- 'R'
IMDB$content_rating[IMDB$content_rating == 'Not Rated'] <- 'R'
IMDB$content_rating[IMDB$content_rating == 'Passed'] <- 'R'
IMDB$content_rating[IMDB$content_rating == 'Unrated'] <- 'R'
# Mengetahui jumlah film untuk masing-masing Rating
IMDB$content_rating <- factor(IMDB$content_rating)
table(IMDB$content_rating)
##
## G NC-17 PG PG-13 R
## 91 16 576 1314 1809
# Menghapus karakter "Â" di variabel movie title
library(stringr)
IMDB$movie_title <- gsub("Â", "", as.character(factor(IMDB
$movie_title)))
# Menghilangkan space kosong di sebelah kanan judul film pada variabel movie title
IMDB$movie_title <- str_trim(IMDB$movie_title, side = "right")
# Mendeteksi Outlier pada variabel title year
ggplot(IMDB, aes(title_year))+geom_bar()+
labs(x="Tahun Perilisan Film", y="Jumlah Film", title="Histogram Tahun Perilisan Film")
IMDB %>%
group_by(title_year) %>%
summarise(count_title_year = length(movie_title)) %>%
arrange(desc(count_title_year)) %>%
top_n(-10, count_title_year) %>%
formattable(list(count_title_year = color_bar("orange")), align = 'l')
title_year | count_title_year |
---|---|
1927 | 1 |
1929 | 1 |
1933 | 1 |
1935 | 1 |
1936 | 1 |
1937 | 1 |
1947 | 1 |
1948 | 1 |
1950 | 1 |
1952 | 1 |
1957 | 1 |
1959 | 1 |
1960 | 1 |
1961 | 1 |
1966 | 1 |
1967 | 1 |
Diketahui bahwa pada IMDB 5000 Movie Dataset terdapat banyak film lama, dimana tahun perilisan paling lama ialah tahun 1927. Pada tabel di atas terlihat di tahun-tahun sebelum 1980 hanya terdapat 1 hingga 2 film yang tercatat pada dataset, sehingga selanjutnya hanya dilakukan analisis untuk film-film yang rilis pada dan setelah tahun 1980.
IMDB <- IMDB[IMDB$title_year >= 1980,]
dim(IMDB)
## [1] 3711 28
Setelah dilakukan preprocessing data, selanjutnya data yang digunakan ada sebanyak 3711 observasi dengan 25 variabel. Berikut merupakan variabel-variabel yang digunakan untuk eksplorasi data.
colnames(IMDB)
## [1] "color" "director_name"
## [3] "num_critic_for_reviews" "duration"
## [5] "director_facebook_likes" "actor_3_facebook_likes"
## [7] "actor_2_name" "actor_1_facebook_likes"
## [9] "gross" "genres"
## [11] "actor_1_name" "movie_title"
## [13] "num_voted_users" "cast_total_facebook_likes"
## [15] "actor_3_name" "facenumber_in_poster"
## [17] "plot_keywords" "movie_imdb_link"
## [19] "num_user_for_reviews" "language"
## [21] "country" "content_rating"
## [23] "budget" "title_year"
## [25] "actor_2_facebook_likes" "imdb_score"
## [27] "aspect_ratio" "movie_facebook_likes"
Eksplorasi data dilakukan untuk menggali informasi lebih lanjut dari IMDB 5000 Movie Dataset.
# Histogram Skor IMDB
ggplot(IMDB,
aes(x = imdb_score)) +
geom_histogram(aes(fill = ..count..),
binwidth =0.5) +
scale_x_continuous(name = "Skor IMDB",
breaks = seq(0,10),
limits=c(1, 10)) +
ggtitle("Histogram Skor IMDB") +
scale_fill_gradient("Count",
low = "blue",
high = "red")
Diketahui bahwa skor yang paling banyak diperoleh pada film dalam IMDB Movie Dataset adalah sebesar 6,5 diikuti dengan skor 7 dan 5. Sementara itu skor IMDB terendah tercatat 2 dan yang tertinggi 9. Terlihat bahwa histogram bersifat negatively skewed atau condong negatif, mengartikan bahwa modus skor IMDB lebih besar dari rata-rata skor IMDB. Hal ini menunjukkan bahwa banyak film yang memperoleh skor IMDB sangat rendah.
# Menambah variabel profit dan Return on Investment untuk mempermudah analisis
IMDB <- IMDB %>%
mutate(profit = gross-budget,
return_on_investment_perc = (profit/budget)*100)
# Top 10 Film dengan Keuntungan Terbesar
IMDB %>%
filter(title_year %in% c(2000:2016)) %>%
arrange(desc(profit)) %>%
top_n(10,
profit) %>%
ggplot(aes(x = budget/1000000,
y = profit/1000000)) +
geom_point() +
geom_smooth() +
geom_text_repel(aes(label = movie_title)) +
labs(x = "Budget (Juta USD)",
y = "Profit (Juta USD)",
title = "Top 10 Film dengan Keuntungan Terbesar") +
theme(plot.title = element_text(hjust = 0.5))
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Ketika budget untuk membuat film di atas 125 Juta USD, terdapat kecenderungan profit atau keuntungan yang didapatkan juga mengalami kenaikan. Film Avatar menjadi film dengan budget terbesar, namun juga mendapatkan keuntungan paling tinggi.
Film Jurassic World memiliki budget 150 juta USD, hampir 100 juta USD lebih hemat dibanding Avatar. Namun keuntungan yang diperoleh Jurassic World sangat tinggi yakni 500 juta USD, hanya berbeda sekitar 25 juta USD dengan profit film Avatar. Keadaan seperti ini yang diinginkan oleh produser-produser film, yakni pembuatan film dengan budget sesedikit mungkin namun dapat menghasilkan keuntungan yang besar.
# Top 10 Film Paling Menguntungkan berdasarkan ROI
IMDB %>%
filter(budget > 100000) %>%
mutate(profit = gross - budget,
return_on_investment_perc = (profit/budget)*100) %>%
arrange(desc(profit)) %>%
top_n(10,
profit) %>%
ggplot(aes(x = budget/1000000,
y = return_on_investment_perc)) +
geom_point(size = 2) +
geom_smooth(size = 1) +
geom_text_repel(aes(label = movie_title),
size = 3) +
xlab("Budget (Juta USD)") +
ylab("Persentase ROI") +
ggtitle("Top 10 Film Paling Menguntungkan berdasarkan ROI")
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'
Pada kasus ini, Return on Investment (ROI) merupakan rasio yang dipakai untuk mengevaluasi efisiensi investasi pada sebuah film dengan membandingkan modal dan biaya awal yang dikeluarkan.
Berdasarkan gambar di atas diketahui bahwa film dengan tingkat pengembalian paling tinggi ialah E.T. the Extra-Terrestrial. Selain itu diketahui pula bahwa film-film bergenre fantasi cenderung menghasilkan ROI yang lebih besar, seperti E.T. the Extra-Terrestrial, beberapa film Star Wars, Jurassic Park, dan lain-lain. Hal ini dapat menjadi masukan bagi produser film untuk berinvestasi pada film-film fantasi, drama, aksi, serta animasi mengingat genre tersebut memberikan ROI yang lebih besar dibandingkan genre lain.
# Sutradara Film Paling Produktif
IMDB %>%
group_by(director_name) %>%
summarise(count_movie_title = length(movie_title)) %>%
arrange(desc(count_movie_title)) %>%
top_n(10,
count_movie_title) %>%
formattable(list(count_movie_title = color_bar("orange")),
align = 'l')
director_name | count_movie_title |
---|---|
Steven Spielberg | 23 |
Clint Eastwood | 19 |
Woody Allen | 18 |
Ridley Scott | 16 |
Steven Soderbergh | 16 |
Tim Burton | 16 |
Martin Scorsese | 15 |
Renny Harlin | 15 |
Spike Lee | 15 |
Barry Levinson | 13 |
Michael Bay | 13 |
Oliver Stone | 13 |
Robert Rodriguez | 13 |
Robert Zemeckis | 13 |
Ron Howard | 13 |
Sutradara yang paling banyak membuat film ialah Steven Spielberg yakni dengan total 25 judul film. Film-filmnya yang paling terkenal di antaranya E.T. The Extra-Terrestrial, serial Indiana Jones, serial Jurassic Park, Jaws, A.I: Artificial Intelligence, dan lain-lain.
# Commercial Success Vs Critical Acclaim
IMDB %>%
top_n(10,
profit) %>%
ggplot(aes(x = imdb_score,
y = gross/10^6,
size = profit/10^6,
color = content_rating)) +
geom_point() +
geom_hline(aes(yintercept = 600)) +
geom_vline(aes(xintercept = 7.75)) +
geom_text_repel(aes(label = movie_title),
size = 4) +
xlab("Imdb score") +
ylab("Gross money earned in million dollars") +
ggtitle("Commercial success Vs Critical acclaim") +
annotate("text",
x = 8.5,
y = 700,
label = "High ratings \n & High gross") +
theme(plot.title = element_text(hjust = 0.5))
Secara visual tidak terdapat hubungan yang signifikan antara skor IMDB yang menunjukkan kesuksesan film di mata kritikus, dengan pendapatan kotor film yang menggambarkan kesuksesan film di pasar.
Seperti yang terlihat pada beberapa film-film dengan skor IMDB tinggi semacam Star Wars: Episode V - The Empire Strikes Back dan The Lord of The Rings: The Return of The King. Kedua film tersebut memiliki skor IMDB yang tinggi namun hanya memperoleh pendapatan kotor tidak sampai 500 juta USD serta keuntungan yang tidak besar. Hal ini berbeda dengan film seperti Jurrasic World yang meskipun mendapat skor IMDB di bawah 7,5, film tersebut sukses di pasar yakni dilihat dari jumlah pendapatan kotor dan keuntungan yang besar.
Film-film yang sukses mendapat sanjungan dari kritikus film serta memperoleh pendapatan kotor dan keuntungan besar di antaranya ialah Avatar dan The Avengers.
Gambar tersebut juga memberikan informasi mengenai rating film yang berpotensi memberi pendapatan kotor dan keuntungan yang lebih banyak. Diketahui bahwa pendapatan kotor di atas 500 juta USD dan keuntungan di atas 400 juta USD dimiliki oleh film-film dengan rating PG-13, yakni film yang menyasar penonton usia 13 tahun ke atas. Sementara untuk film dengan rating G atau film tanpa unsur kekerasan, seks, ketelanjangan, dan semacamnya cenderung memiliki skor IMDB tinggi namun pendapatan kotor yang tidak besar.
Dalam tahap analisis selanjutnya, variabel profit dan return on investment tidak digunakan sehingga kedua variabel tersebut dihapus.
# Menghapus variabel profit dan ROI
IMDB <- subset(IMDB,
select = -c(profit,
return_on_investment_perc))
Menjumlahkan variabel actor 2 facebook likes dan variabel 3 facebook likes ke dalam variabel baru yaitu other actors facebook likes. Serta membagi jumlah kritik dengan jumlah pengguna untuk mendapatkan rasio kritik yang diberikan terhadap sebuah film. Selanjutnya, variabel-variabel yang terlah diwakili tersebut dihapus.
# Menjumlahkan variabel actor 2 facebook likes dan variabel 3 facebook likes
IMDB$other_actors_facebook_likes <- IMDB$actor_2_facebook_likes + IMDB$actor_3_facebook_likes
# Membuat variabel critic review ratio
IMDB$critic_review_ratio <- IMDB$num_critic_for_reviews / IMDB$num_user_for_reviews
# Menghapus variabel
IMDB <- subset(IMDB,
select = -c(cast_total_facebook_likes,
actor_2_facebook_likes,
actor_3_facebook_likes,
num_critic_for_reviews,
num_user_for_reviews))
Untuk analisis regresi, selanjutnya dari dataset IMDB dipilih variabel numerik.
# Membuat dataset baru dengan hanya menggunakan variabel numerik
IMDBNum <- subset(IMDB, select=c(3,4,6,7,13,19,21,23,24,25))
Variabel yang digunakan untuk analisis regresi ialah sebagai berikut.
colnames(IMDBNum)
## [1] "duration" "director_facebook_likes"
## [3] "actor_1_facebook_likes" "gross"
## [5] "facenumber_in_poster" "budget"
## [7] "imdb_score" "movie_facebook_likes"
## [9] "other_actors_facebook_likes" "critic_review_ratio"
Analisis regresi dilakukan untuk memprediksi skor IMDB sebuah film berdasarkan durasi, kepopuleran sutradara film (directo facebook likes), kepopuleran aktor utama (actor 1 facebook likes), pendapatan kotor, jumlah wajah di poster, budget, kepopuleran film (movie facebook likes), kepopuleran pemeran pendukung (other actor facebook likes), dan kritik yang diberikan untuk film tersebut (critic review ratio).
Langkah awal untuk mencari metode terbaik dalam meregresikan data adalah membagi data IMDB 5000 Movie Dataset menjadi data training dan testing dengan proporsi pembagian 70:30. Data diambil secara random.
n <- nrow(IMDBNum)
trainIndex <- sample(1:n, size = round(0.7*n), replace=FALSE)
moviedata_train2 <- IMDBNum[trainIndex ,]
moviedata_test2 <- IMDBNum[-trainIndex ,]
write.csv(moviedata_train2, file = "C://Users//Admin//Documents//moviedata_train2.csv",row.names=FALSE)
write.csv(moviedata_test2, file = "C://Users//Admin//Documents//moviedata_test2.csv",row.names=FALSE)
movie_train2 <- read.csv("C://Users//Admin//Documents//moviedata_train2.csv")
movie_test2 <- read.csv("C://Users//Admin//Documents//moviedata_train2.csv")
Dalam analisis regresi menggunakan metode kNearest Neighbor dengan nilai k dan distance (Parameter Minkowski) yang diubah-ubah.
library(caret)
library(kknn)
##
## Attaching package: 'kknn'
## The following object is masked from 'package:caret':
##
## contr.dummy
Digunakan k = 3 dan distance = 2
# Train
model.knn2 <- kknn(imdb_score~., movie_train2, movie_test2, k=3, distance=2, scale=FALSE)
summary(model.knn2)
##
## Call:
## kknn(formula = imdb_score ~ ., train = movie_train2, test = movie_test2, k = 3, distance = 2, scale = FALSE)
##
## Response: "continuous"
# Test
pred.knn2 <- predict(model.knn2, newdata=movie_test2)
err.knn2 <- movie_test2$imdb_score - pred.knn2 # Menghitung error
rmse.knn2 <- sqrt(mean((err.knn2^2)))
rmse.knn2
## [1] 0.4342625
Dengan syntax yang sama, untuk nilai k dan distance selanjutnya diperoleh hasil sebagaik berikut.
k=3, distance=2 | RMSE=0.4340803
k=3, distance=1 | RMSE=0.5413981
k=4, distance=1 | RMSE=0.5432945
k=7, distance=2 | RMSE=0.7034374
k=7, distance=1 | RMSE=0.701382
Dalam analisis regresi menggunakan metode Support Vector Machines Regression digunakan kernel linear, kernel polynomial, kernel radial basis, dan kernel sigmoid dengan masing-masing nilai cost 1 dan epsilon 0,1.
library(e1071)
# TRAIN
model.SVR12 <- svm(imdb_score~., movie_train2, kernel="radial", cost=1, epsilon=0.1)
# TEST
# setelah didapatkan model SVR, dilanjutkan memprediksi data berdasarkan data testing
pred.SVR12 <- predict(model.SVR12, newdata=movie_test2)
err.SVR12 <- movie_test2$imdb_score - pred.SVR12
rmse.SVR12 <- sqrt(mean((err.SVR12^2))) #utk ngitung kebaikan model (rsquare)
rmse.SVR12
## [1] 0.8146649
# TRAIN
model.SVR22 <- svm(imdb_score~., movie_train2, kernel="linear", cost=1, epsilon=0.1)
# TEST
# setelah didapatkan model SVR, dilanjutkan memprediksi data berdasarkan data testing
pred.SVR22 <- predict(model.SVR22, newdata=movie_test2)
err.SVR22 <- movie_test2$imdb_score - pred.SVR22
rmse.SVR22 <- sqrt(mean((err.SVR22^2)))
rmse.SVR22
## [1] 0.9825716
# TRAIN
model.SVR32 <- svm(imdb_score~., movie_train2, kernel="polynomial", cost=1, epsilon=0.1)
# TEST
# setelah didapatkan model SVR, dilanjutkan memprediksi data berdasarkan data testing
pred.SVR32 <- predict(model.SVR22, newdata=movie_test2)
err.SVR32 <- movie_test2$imdb_score - pred.SVR32
rmse.SVR32 <- sqrt(mean((err.SVR32^2)))
rmse.SVR32
## [1] 0.9825716
# TRAIN
model.SVR42 <- svm(imdb_score~., movie_train2, kernel="sigmoid", cost=1, epsilon=0.1)
# TEST
# setelah didapatkan model SVR, dilanjutkan memprediksi data berdasarkan data testing
pred.SVR42 <- predict(model.SVR42, newdata=movie_test2)
err.SVR42 <- movie_test2$imdb_score - pred.SVR42
rmse.SVR42 <- sqrt(mean((err.SVR42^2)))
rmse.SVR42
## [1] 30.53871
Metode analisis regresi yang memberikan nilai kesalahan paling kecil dilihat dari nilai RMSE ialah metode k-Nearest Neighbor dengan k sama dengan 3 dan parameter minkowski sama dengan 2. Metode ini memberikan RMSE sebesar 0,434.