library(readr)
library(stringr)
library(tidyverse)
library(magrittr)
library(dplyr)
library(tidytext)
library(ggplot2)
movies <- read_csv("~/shared/minor2_2017/data/netflix/movie_info.csv") %>% rename(movie_id = id)
## Warning: Duplicated column names deduplicated: 'id' => 'id_1' [7]
marks_3 <- read_csv("~/shared/minor2_2017/data/netflix/groups/marks_3.csv")
# данные по актерам и режиссеру
TAD <- read_delim("~/project_databases/title_actors_directors.csv",
";", escape_double = FALSE, trim_ws = TRUE)
## Warning: Missing column names filled in: 'X20' [20]
TAD = select(TAD, title, actor1_name, actor2_name, director_name, release_date)
library(lubridate)
TAD$release_date = dmy(TAD$release_date)
## Warning: 1040 failed to parse.
TAD$release_date = year(TAD$release_date)
TAD$fy = str_c(TAD$title,TAD$release_date)
TAD = select(TAD, actor1_name, actor2_name, director_name, fy)
# считаем среднюю оценку
data = marks_3 %>% group_by(movie_id) %>% summarize(marks = mean(mark, na.rm = T))
# соеденим два датасета
data = inner_join(data, movies)
# присоединяем год фильма
data$fy = str_c(data$title,data$year)
# присоединим 2 актеров и режиссера
data = left_join(data,TAD, by = "fy")
data$idD = as.integer(duplicated(data$movie_id))
data = filter(data, data$idD=="0")
#Удаляем все ненужные столбцы
data = select(data, -homepage, -id_1)
# добавляем Оскар
Oscar <- read_csv("~/project_databases/database.csv")
#connect
Oscar1 = select(Oscar, -Name)
Oscar2 = select(Oscar, -Film)
names(Oscar2)[5] = "Film"
OscarF = bind_rows(Oscar1,Oscar2)
#уникальный идентификатор
OscarF$fy = str_c(OscarF$Film,OscarF$Year)
data4 = left_join(data,OscarF,by="fy")
data4 = select(data4, movie_id, marks, popularity, Award, Winner)
data4$nominee = as.integer(is.na(data4$Winner))
data4$oscar = as.integer(is.na(data4$Award))
data4 %<>% mutate(prize=ifelse(data4$oscar==0 & data4$nominee==0,2,ifelse(data4$oscar==0 & data4$nominee==1,1,0)))
data4 = select(data4, movie_id, marks, popularity, prize, Award)
data4$Award[data4$prize==0] = "none"
data4$idD = as.integer(duplicated(data4))
data4 = filter(data4, data4$idD=="0")
data4 = select(data4,-idD)
data4 = data4[-458,]
data0 = select(data, movie_id, title, popularity)
data4 = left_join(data4,data0,by="movie_id")
# special data
data4Oscar <- data4 %>% group_by(movie_id) %>% summarise(Award = paste(unique(Award), collapse = ' '))
data4Oscar <- left_join(data4Oscar,data0,by="movie_id")
# выгружаем данные
#write.csv(data, "~/data_noOscar.csv")
Крутой пользователь:
top_users = marks_3 %>% count(user_id, sort=T) %>% head(n=10)
Введите фильтры для поиска:
user = sample(top_users$user_id) %>% head(n=1)
gnr <- as.character("Drama")
drc <- as.character("Adam Shankman")
act <- as.character("Ben Affleck")
osc <- as.character("Best Picture")
wrd1 <- as.character("slaughter")
wrd2 <- as.character("death")
wrd3 <- as.character("suicide")
wrd4 <- as.character("killing")
wrd5 <- as.character("war")
Выбираем переменные, которые пригодятся для составления матрицы схожести фильмов: здесь это жанры, популярность и дата выпуска (в финальном варианте сюда будут записаны ещё наличие наград, режиссёры, актёры)
data1 = data %>% dplyr::select(movie_id, marks, genres, popularity, release_date)
data2 = data %>% dplyr::select(movie_id, marks, popularity, director_name)
data3 = data %>% dplyr::select(movie_id, marks, popularity, actor1_name)
Через ifelse разобьём на сезоны, исходя из нашего предположения о наклонности производителей выпускать фильмы определённых жанров в определённые сезоны
data1 %<>% mutate(Season=ifelse(str_detect(data1$release_date, "-01|-02|-12"), "1", ifelse(str_detect(data1$release_date, "-03|-04|-05"), "2", ifelse(str_detect(data1$release_date, "-06|-07|-08"), "3", ifelse(str_detect(data1$release_date, "-09|-10|-11"), "4", NA)))))
data1$Season = as.numeric(data1$Season)
Преобразуем жанры
library(tidyr)
source("~/shared/minor2_2017/2-tm-net/lab08-proj-data/extract_json.R")
data1 = extract_json(df = data1, col = "genres")
Удаляем лишние переменные
data1 %<>% dplyr::select(-genres, -release_date)
Считаем матрицу схожести фильмов
rownames(data1) = data1$movie_id
data1 %<>% dplyr::select(-movie_id)
sim = lsa::cosine(t(as.matrix(data1)))
# удаляем единицы в диагональных значениях
diag(sim) = 0
Описание. Пользователь должен будет ввести свой id; жанр фильма, который он хочет посмотреть; и слова, которые он НЕ хочет встретить в keywords к этому фильму (в идеале, и тематика фильма не должна содержать эти элементы). Таким образом, система: 1)изначально фильтрует таблицу с оценками пользователей так, что там остаются отзывы только данного пользователя, причём с МАКСИМАЛЬНОЙ для него оценкой 2)далее, система, основываюсь на матрице схожести, ищет ПОХОЖИЕ фильмы для оценённых фильмов; после этого наиболее похожие фильмы соотносятся с датасетом data
3)здесь уже отбираются фильмы указанного жанра и не содержащие указанные слова в keywords и overview 4)если пользователь не оценил ни одного фильма, то тогда ему рекомендуются ТОП-5 фильмов, отфильтрованных по жанру и не включающих указанные слова в keywords и overview
# итоговый вариант; nof = 50 - количество рекомендаций)
find_film = function(userId, genre, kw1, kw2, kw3, kw4, kw5, nof = 50){
m = marks_3 %>% filter(user_id == userId) %>% filter(mark %in% max(mark)) %>% filter(movie_id %in% data$movie_id)
if (nrow(m) > 0){
mostSimilar = head(sort(sim[,as.character(m$movie_id)], decreasing = T), n = 50)
a = which(sim[,as.character(m$movie_id)] %in% mostSimilar, arr.ind = TRUE)
rows = a %% dim(sim)[1]
result = rownames(sim)[rows]
data %>% filter(movie_id %in% result) %>% filter(str_detect(genres, genre)) %>% filter(!str_detect(keywords, str_c(kw1, "&", kw2, "&", kw3, "&", kw4, "&", kw5))) %>% filter(!str_detect(overview, str_c(kw1, "&", kw2, "&", kw3, "&", kw4, "&", kw5))) %>% dplyr::select(title) %>% head(nof, title)
} else {
data %>% filter(str_detect(genres, genre)) %>% filter(!str_detect(keywords, str_c(kw1, "&", kw2, "&", kw3, "&", kw4, "&", kw5))) %>% filter(!str_detect(overview, str_c(kw1, "&", kw2, "&", kw3, "&", kw4, "&", kw5))) %>% top_n(nof, popularity) %>% dplyr::select(title)
}
}
Если пользователь имеет аккаунт в системе: Сделаем рекомендацию для пользователя с userId = 712664, который хочет посмотреть драму, но такую, чтобы её основная тематика не касалсь слов в кавычках
a = sample(top_users$user_id) %>% head(n=1)
recGA <- find_film(user, gnr, wrd1,wrd2,wrd3,wrd4,wrd5)
# Убираем фильмы, которые пользователь уже посмотрел
recG <- recGA
recG <- left_join(recG, data, by="title")
recG <- select(recG, title, movie_id)
recG <- left_join(recG, marks_3, by="movie_id")
recG <- filter(recG, recG$user_id==a)
recGA %<>% filter(!title %in% recG$title)
Если пользователь никогда не ставил оценки до этого, пусть в userId пишет “0” (так система сразу перенесёт его ко второй части функции)
find_film(0, gnr, wrd1,wrd2,wrd3,wrd4,wrd5)
## # A tibble: 50 x 1
## title
## <chr>
## 1 Wild Things
## 2 Solaris
## 3 Trainspotting
## 4 Irreversible
## 5 Braveheart
## 6 About a Boy
## 7 10 Things I Hate About You
## 8 Man on the Moon
## 9 The Last Samurai
## 10 25th Hour
## # ... with 40 more rows
coldG <- head(find_film(0, gnr, wrd1,wrd2,wrd3,wrd4,wrd5),n=1)
# creating WIDE format
data2$value = 1
data2w = spread(data2, director_name, value, fill = 0)
Считаем матрицу схожести фильмов:
rownames(data2w) = data2w$movie_id
## Warning: Setting row names on a tibble is deprecated.
data2w %<>% dplyr::select(-movie_id)
sim2 = lsa::cosine(t(as.matrix(data2w)))
# удаляем единицы в диагональных значениях
diag(sim2) = 0
Функция по режиссерам:
# итоговый вариант; nof = 5 - количество рекомендаций)
find_film2 = function(userId, director, nof = 100){
m = marks_3 %>% filter(user_id == userId) %>% filter(mark %in% max(mark)) %>% filter(movie_id %in% data$movie_id)
if (nrow(m) > 0){
mostSimilar = head(sort(sim2[,as.character(m$movie_id)], decreasing = T), n = 100)
a = which(sim2[,as.character(m$movie_id)] %in% mostSimilar, arr.ind = TRUE)
rows = a %% dim(sim2)[1]
result = rownames(sim2)[rows]
data %>% filter(movie_id %in% result) %>% filter(str_detect(director_name, director)) %>% dplyr::select(title) %>% head(nof, title)
} else {
data %>% filter(str_detect(director_name, director)) %>% top_n(nof, popularity) %>% dplyr::select(title)
}
}
Если пользователь имеет аккаунт в системе: Сделаем рекомендацию для пользователя с userId = 712664, который хочет посмотреть драму, но такую, чтобы её основная тематика не касалсь слов в кавычках
b = sample(top_users$user_id) %>% head(n=1)
recDA <- find_film2(user, drc)
# Убираем фильмы, которые пользователь уже посмотрел
recD <- recDA
recD <- left_join(recD, data, by="title")
recD <- select(recD, title, movie_id)
recD <- left_join(recD, marks_3, by="movie_id")
recD <- filter(recD, recD$user_id==b)
recDA %<>% filter(!title %in% recD$title)
Если пользователь никогда не ставил оценки до этого, пусть в userId пишет “0” (так система сразу перенесёт его ко второй части функции)
find_film2(0, drc)
## # A tibble: 3 x 1
## title
## <chr>
## 1 The Wedding Planner
## 2 Bringing Down the House
## 3 A Walk to Remember
coldD <- head(find_film2(0, drc),n=1)
# creating WIDE format
data3$value = 1
data3w = spread(data3, actor1_name, value, fill = 0)
Считаем матрицу схожести фильмов:
rownames(data3w) = data3w$movie_id
## Warning: Setting row names on a tibble is deprecated.
data3w %<>% dplyr::select(-movie_id)
sim3 = lsa::cosine(t(as.matrix(data3w)))
# удаляем единицы в диагональных значениях
diag(sim3) = 0
Функция по актерам:
# итоговый вариант; nof = 5 - количество рекомендаций)
find_film3 = function(userId, actor, nof = 250){
m = marks_3 %>% filter(user_id == userId) %>% filter(mark %in% max(mark)) %>% filter(movie_id %in% data$movie_id)
if (nrow(m) > 0){
mostSimilar = head(sort(sim3[,as.character(m$movie_id)], decreasing = T), n = 250)
a = which(sim3[,as.character(m$movie_id)] %in% mostSimilar, arr.ind = TRUE)
rows = a %% dim(sim3)[1]
result = rownames(sim3)[rows]
data %>% filter(movie_id %in% result) %>% filter(str_detect(actor1_name, actor)) %>% dplyr::select(title) %>% head(nof, title)
} else {
data %>% filter(str_detect(actor1_name, actor)) %>% top_n(nof, popularity) %>% dplyr::select(title)
}
}
Если пользователь имеет аккаунт в системе: Сделаем рекомендацию для пользователя с userId = 712664, который хочет посмотреть драму, но такую, чтобы её основная тематика не касалсь слов в кавычках
c = sample(top_users$user_id) %>% head(n=1)
recAA <- find_film3(c, act)
# Убираем фильмы, которые пользователь уже посмотрел
recA <- recAA
recA <- left_join(recA, data, by="title")
recA <- select(recA, title, movie_id)
recA <- left_join(recA, marks_3, by="movie_id")
recA <- filter(recA, recA$user_id==c)
recAA %<>% filter(!title %in% recA$title)
Если пользователь никогда не ставил оценки до этого, пусть в userId пишет “0” (так система сразу перенесёт его ко второй части функции)
find_film3(0, act)
## # A tibble: 4 x 1
## title
## <chr>
## 1 Dogma
## 2 200 Cigarettes
## 3 The Sum of All Fears
## 4 Gigli
coldA <- head(find_film3(0, act),n=1)
Данная рекомендательная система работает только с уже существующими юзерами, которые оценивали фильмы - алгоритм смотрит на оцененные юзером фильмы, ищет среди них фильмы-победители/номинанты на Оскар за определённые категории и предлагает фильмы, которые были номинированы на Оскар или побеждали в этих же категориях.
Допустим, пользователь посмотрел несколько фильмов, которые победили/были номинированы на Оскар за лучшие костюмы, тогда мы делаем предплоложение, что этому пользователю нравятся в фильмах именно костюмы и предлагаем ему другие фильмы, которые также победили/были номинированы на Оскар за лучшие костюмы - и так по любой категории фильмов.
# creating WIDE format
data4 = select(data4, -title)
data4w = spread(data4, Award, prize, fill = 0)
data4 = left_join(data4,data0,by="movie_id")
data4 %<>% mutate(prize=ifelse(data4$prize==0,0,1))
Считаем матрицу схожести фильмов:
rownames(data4w) = data4w$movie_id
## Warning: Setting row names on a tibble is deprecated.
data4w %<>% dplyr::select(-movie_id)
sim4 = lsa::cosine(t(as.matrix(data4w)))
# удаляем единицы в диагональных значениях
diag(sim4) = 0
Функция по Оскару:
# итоговый вариант; nof = 5 - количество рекомендаций)
data4w$movie_id = as.integer(rownames(data4w))
data4w = left_join(data4w,data0,by="movie_id")
find_film4 = function(userId, prize, nof = 250){
m = marks_3 %>% filter(user_id == userId) %>% filter(mark %in% max(mark)) %>% filter(movie_id %in% data4$movie_id)
if (nrow(m) > 0){
mostSimilar = head(sort(sim4[,as.character(m$movie_id)], decreasing = T), n = 250)
a = which(sim4[,as.character(m$movie_id)] %in% mostSimilar, arr.ind = TRUE)
rows = a %% dim(sim4)[1]
result = rownames(sim4)[rows]
data4Oscar %>% filter(movie_id %in% result) %>% filter(str_detect(Award, prize)) %>% dplyr::select(title) %>% head(nof, title)
} else {
data4Oscar %>% filter(str_detect(Award, prize)) %>% top_n(nof, popularity) %>% dplyr::select(title)
}
}
Если пользователь имеет аккаунт в системе: Сделаем рекомендацию для пользователя с userId = 712664, который хочет посмотреть драму, но такую, чтобы её основная тематика не касалсь слов в кавычках
d = sample(top_users$user_id) %>% head(n=1)
recOA <- find_film4(d, osc)
# Убираем фильмы, которые пользователь уже посмотрел
recO <- recOA
recO <- left_join(recO, data, by="title")
recO <- select(recO, title, movie_id)
recO <- left_join(recO, marks_3, by="movie_id")
recO <- filter(recO, recO$user_id==d)
recOA %<>% filter(!title %in% recA$title)
Если пользователь никогда не ставил оценки до этого, пусть в userId пишет “0” (так система сразу перенесёт его ко второй части функции)
find_film4(0, osc)
## # A tibble: 23 x 1
## title
## <chr>
## 1 Jaws
## 2 The Piano
## 3 Midnight Cowboy
## 4 Braveheart
## 5 The Full Monty
## 6 Gandhi
## 7 Erin Brockovich
## 8 A Passage to India
## 9 Apocalypse Now
## 10 Lawrence of Arabia
## # ... with 13 more rows
coldO <- head(find_film4(0, osc),n=1)
markss=marks_3%>%group_by(user_id)%>%count()
table(markss$n)
##
## 1 2 3 4 5 6 7 8 9 10 11 12
## 17516 19609 21076 21106 20240 19449 18017 16439 14683 13325 11992 10915
## 13 14 15 16 17 18 19 20 21 22 23 24
## 9908 9073 8656 7952 7518 6958 6448 6240 6155 5740 5409 5190
## 25 26 27 28 29 30 31 32 33 34 35 36
## 5063 4690 4698 4486 4359 4127 3956 3852 3808 3698 3671 3424
## 37 38 39 40 41 42 43 44 45 46 47 48
## 3297 3269 3158 3017 2882 2871 2736 2620 2640 2408 2492 2362
## 49 50 51 52 53 54 55 56 57 58 59 60
## 2347 2192 2209 2053 2020 1987 1934 1792 1841 1834 1774 1616
## 61 62 63 64 65 66 67 68 69 70 71 72
## 1695 1619 1562 1495 1547 1493 1424 1392 1368 1306 1298 1251
## 73 74 75 76 77 78 79 80 81 82 83 84
## 1270 1257 1141 1204 1071 1081 1098 1098 1048 974 925 919
## 85 86 87 88 89 90 91 92 93 94 95 96
## 950 901 918 872 874 837 854 806 805 779 688 758
## 97 98 99 100 101 102 103 104 105 106 107 108
## 731 697 637 688 614 570 604 563 569 562 562 502
## 109 110 111 112 113 114 115 116 117 118 119 120
## 549 540 527 504 522 429 449 429 419 423 390 438
## 121 122 123 124 125 126 127 128 129 130 131 132
## 422 379 388 369 342 363 361 328 342 301 339 303
## 133 134 135 136 137 138 139 140 141 142 143 144
## 321 281 292 281 272 272 241 249 258 234 273 239
## 145 146 147 148 149 150 151 152 153 154 155 156
## 232 209 209 213 193 202 200 208 192 198 183 184
## 157 158 159 160 161 162 163 164 165 166 167 168
## 173 165 164 169 145 136 128 145 140 129 134 133
## 169 170 171 172 173 174 175 176 177 178 179 180
## 142 131 114 117 134 109 95 88 105 107 111 105
## 181 182 183 184 185 186 187 188 189 190 191 192
## 100 86 89 90 67 87 93 84 81 86 62 77
## 193 194 195 196 197 198 199 200 201 202 203 204
## 76 58 80 58 62 74 66 49 58 45 71 45
## 205 206 207 208 209 210 211 212 213 214 215 216
## 54 67 44 32 57 43 29 39 35 35 37 28
## 217 218 219 220 221 222 223 224 225 226 227 228
## 30 30 41 37 23 26 33 33 30 30 33 32
## 229 230 231 232 233 234 235 236 237 238 239 240
## 32 20 24 31 23 26 36 30 14 23 23 20
## 241 242 243 244 245 246 247 248 249 250 251 252
## 22 11 15 15 16 14 16 8 16 12 15 11
## 253 254 255 256 257 258 259 260 261 262 263 264
## 15 15 15 18 9 8 12 9 18 12 9 9
## 265 266 267 268 269 270 271 272 273 274 275 276
## 13 11 10 8 8 10 8 6 8 8 15 6
## 277 278 279 280 281 282 283 284 285 286 287 288
## 14 7 10 11 10 5 4 4 5 6 9 8
## 289 290 291 292 293 295 296 297 299 300 301 302
## 3 6 2 4 9 5 6 8 3 2 6 1
## 303 304 305 306 307 308 309 310 311 312 313 314
## 4 4 4 1 3 1 1 2 2 1 2 3
## 315 316 317 320 321 322 323 324 325 326 327 329
## 4 2 1 3 3 4 1 2 1 3 1 2
## 330 332 333 334 335 336 337 340 341 342 344 345
## 2 1 1 2 2 1 1 1 1 3 1 3
## 348 350 356 357 359 360 364 365 367 368 375 376
## 1 1 1 1 1 1 2 1 1 2 1 1
## 378 379 386 389 397 401 404 413 414 436 447 452
## 1 1 1 1 1 1 1 2 1 1 1 1
## 458 462 488 489 495 499
## 1 1 1 1 1 1
marksss=markss%>%filter(n>100)%>%select(-n)
markssss=left_join(x=marksss,y=marks_3,by="user_id")
mn= left_join(x=markssss,y=movies,by="movie_id")
Сохраним только оценки пользователей и фильмы
rates = select(mn, user_id, movie_id, mark)
my_review = data.frame(user_id = c(1000000,1000000,1000000,1000000,1000000, 1000000), movie_id = c(2470, 3938, 5430, 14209,1073, 8644), mark = c(4, 5, 3, 5, 3, 4) )
rates = bind_rows(rates, my_review)
Преобразуем к таблице в “широком” формате
library(tidyr)
rates = spread(rates, key = movie_id, value = mark)
Для дальнейшей работы в данных должны остаться только оценки, поэтому переведем сначала пользователей в имена строк
rownames(rates) = rates$user_id
## Warning: Setting row names on a tibble is deprecated.
rates = dplyr::select(rates, -user_id)
## Adding missing grouping variables: `user_id`
library(recommenderlab)
## Loading required package: Matrix
##
## Attaching package: 'Matrix'
## The following object is masked from 'package:tidyr':
##
## expand
## Loading required package: arules
##
## Attaching package: 'arules'
## The following object is masked from 'package:dplyr':
##
## recode
## The following objects are masked from 'package:base':
##
## abbreviate, write
## Loading required package: proxy
##
## Attaching package: 'proxy'
## The following object is masked from 'package:Matrix':
##
## as.matrix
## The following objects are masked from 'package:stats':
##
## as.dist, dist
## The following object is masked from 'package:base':
##
## as.matrix
## Loading required package: registry
rates = as.matrix(rates)
r = as(rates, "realRatingMatrix")
r
## 26768 x 501 rating matrix of class 'realRatingMatrix' with 3791425 ratings.
head(rowMeans(r))
## 7 79 134 199 481 769
## 3.899083 3.908397 5.689394 5.672897 8.764151 8.976562
head(colMeans(r))
## user_id 3 45 148 167
## 1.324411e+06 3.435644e+00 2.958914e+00 3.215813e+00 3.824919e+00
## 175
## 3.986182e+00
Похожесть фильмов и пользователей.
Рассмотрим похожесть первых 15 пользователей (чем ближе к нулю, тем больше схожи пользователи. 1 - полная несхожесть):
similarity_users15 <- similarity(r[1:15, ], method = "cosine", which = "user")
as.matrix(similarity_users15)
## 7 79 134 199 481 769 1310
## 7 0.0000000 0.5031747 0.4638638 0.3615757 0.3129351 0.2558470 0.2456068
## 79 0.5031747 0.0000000 0.9942512 0.9826012 0.9704653 0.9669163 0.9596618
## 134 0.4638638 0.9942512 0.0000000 0.9909353 0.9799733 0.9703067 0.9701322
## 199 0.3615757 0.9826012 0.9909353 0.0000000 0.9970274 0.9926225 0.9923791
## 481 0.3129351 0.9704653 0.9799733 0.9970274 0.0000000 0.9991534 0.9989589
## 769 0.2558470 0.9669163 0.9703067 0.9926225 0.9991534 0.0000000 0.9999365
## 1310 0.2456068 0.9596618 0.9701322 0.9923791 0.9989589 0.9999365 0.0000000
## 1333 0.2056341 0.9289050 0.9514750 0.9869486 0.9979344 0.9997273 0.9999397
## 1442 0.2443682 0.9476219 0.9639546 0.9925739 0.9987121 0.9999266 0.9999741
## 1457 0.2277609 0.9506302 0.9670147 0.9911629 0.9987234 0.9998503 0.9999752
## 1500 0.2325164 0.9489738 0.9665103 0.9902719 0.9986739 0.9998694 0.9999786
## 1527 0.2615272 0.9580362 0.9655750 0.9912500 0.9986063 0.9998454 0.9999798
## 1897 0.2560250 0.9617354 0.9678940 0.9931153 0.9989072 0.9998740 0.9999720
## 1918 0.2413101 0.9580342 0.9671351 0.9918959 0.9985564 0.9998164 0.9999475
## 2000 0.2395212 0.9640998 0.9652337 0.9907977 0.9986467 0.9998095 0.9999572
## 1333 1442 1457 1500 1527 1897 1918
## 7 0.2056341 0.2443682 0.2277609 0.2325164 0.2615272 0.2560250 0.2413101
## 79 0.9289050 0.9476219 0.9506302 0.9489738 0.9580362 0.9617354 0.9580342
## 134 0.9514750 0.9639546 0.9670147 0.9665103 0.9655750 0.9678940 0.9671351
## 199 0.9869486 0.9925739 0.9911629 0.9902719 0.9912500 0.9931153 0.9918959
## 481 0.9979344 0.9987121 0.9987234 0.9986739 0.9986063 0.9989072 0.9985564
## 769 0.9997273 0.9999266 0.9998503 0.9998694 0.9998454 0.9998740 0.9998164
## 1310 0.9999397 0.9999741 0.9999752 0.9999786 0.9999798 0.9999720 0.9999475
## 1333 0.0000000 0.9999037 0.9999642 0.9999523 0.9999521 0.9999754 0.9999573
## 1442 0.9999037 0.0000000 0.9999639 0.9999572 0.9999730 0.9999540 0.9999337
## 1457 0.9999642 0.9999639 0.0000000 0.9999799 0.9999797 0.9999830 0.9999641
## 1500 0.9999523 0.9999572 0.9999799 0.0000000 0.9999757 0.9999821 0.9999660
## 1527 0.9999521 0.9999730 0.9999797 0.9999757 0.0000000 0.9999834 0.9999740
## 1897 0.9999754 0.9999540 0.9999830 0.9999821 0.9999834 0.0000000 0.9999816
## 1918 0.9999573 0.9999337 0.9999641 0.9999660 0.9999740 0.9999816 0.0000000
## 2000 0.9999648 0.9999467 0.9999762 0.9999754 0.9999853 0.9999848 0.9999888
## 2000
## 7 0.2395212
## 79 0.9640998
## 134 0.9652337
## 199 0.9907977
## 481 0.9986467
## 769 0.9998095
## 1310 0.9999572
## 1333 0.9999648
## 1442 0.9999467
## 1457 0.9999762
## 1500 0.9999754
## 1527 0.9999853
## 1897 0.9999848
## 1918 0.9999888
## 2000 0.0000000
image(as.matrix(similarity_users15), main = "User similarity")
Схожесть фильмов:
similarity_items10 <- similarity(r[ ,1:10 ], method = "cosine", which = "items")
as.matrix(similarity_items10)
## user_id 3 45 148 167 175
## user_id 0.0000000 0.8308339 0.8338002 0.8240311 0.8361083 0.8406427
## 3 0.8308339 0.0000000 0.9340915 0.8613332 0.9611704 0.9405935
## 45 0.8338002 0.9340915 0.0000000 0.9339134 0.9354400 0.9207791
## 148 0.8240311 0.8613332 0.9339134 0.0000000 0.9101498 0.9104461
## 167 0.8361083 0.9611704 0.9354400 0.9101498 0.0000000 0.9397583
## 175 0.8406427 0.9405935 0.9207791 0.9104461 0.9397583 0.0000000
## 181 0.8158412 0.9129934 0.9183559 0.9010467 0.9258057 0.9326005
## 213 0.8351627 0.9534264 0.9641488 0.9128488 0.9571725 0.9466281
## 216 0.8345324 0.9198758 0.9249114 0.9423931 0.9101503 0.9339023
## 329 0.8277691 0.9141463 0.9258719 0.9121601 0.9275266 0.9449366
## 181 213 216 329
## user_id 0.8158412 0.8351627 0.8345324 0.8277691
## 3 0.9129934 0.9534264 0.9198758 0.9141463
## 45 0.9183559 0.9641488 0.9249114 0.9258719
## 148 0.9010467 0.9128488 0.9423931 0.9121601
## 167 0.9258057 0.9571725 0.9101503 0.9275266
## 175 0.9326005 0.9466281 0.9339023 0.9449366
## 181 0.0000000 0.9272514 0.9362987 0.9185125
## 213 0.9272514 0.0000000 0.9332700 0.9228805
## 216 0.9362987 0.9332700 0.0000000 0.9313528
## 329 0.9185125 0.9228805 0.9313528 0.0000000
image(as.matrix(similarity_items10), main = "Item similarity")
Чем темнее ячейка, тем больше схожесть.
Подготовка данных:
Количество оценок у фильма:
ggplot(data = data.frame(filmRate=colCounts(r))) + geom_histogram(aes(x=filmRate))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
Количество оценок, поставленных одним пользователем:
ggplot(data = data.frame(userRate=rowCounts(r))) + geom_histogram(aes(x=userRate))
## `stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
ratings_movies <- r[rowCounts(r) > 100, colCounts(r) > 40]
ratings_movies
## 26767 x 500 rating matrix of class 'realRatingMatrix' with 3791378 ratings.
Разделим данные на тестовую и обучающую выборки. На обучающей построим модель, для пользователей из тестовой будем рекомендовать фильмы.
set.seed(100)
test_ind <- sample(1:nrow(ratings_movies), size = nrow(ratings_movies)*0.2)
recc_data_train <- ratings_movies[-test_ind, ]
recc_data_test <- ratings_movies[test_ind, ]
IBCF (основан на схожести фильмов) -вычислить похожесть всех пар фильмов -для каждого фильма найти k наиболее похожих -для каждого пользователя определить фильмы, наиболее близкие к тем, которые он оценил
recc_model <- Recommender(data = recc_data_train, method = "IBCF", parameter = list(k = 30))
recc_model
## Recommender of type 'IBCF' for 'realRatingMatrix'
## learned using 21414 users.
Матрица схожести:
model_details <- getModel(recc_model)
model_details$description
## [1] "IBCF: Reduced similarity matrix"
model_details$sim[25:30, 40:55]
## 6 x 16 sparse Matrix of class "dgCMatrix"
## [[ suppressing 16 column names '1336', '1367', '1394' ... ]]
##
## 746 . . . . . . . . . . . . . . . .
## 758 . . . . . . . . . . . . . . . .
## 798 . . . . . . . . . . . . . . . .
## 811 1 . . 1 . . . . . . . . 1 . . .
## 829 . . . . . . . . . . . . . . . .
## 962 . . . . . . . . . . . . . . . .
recc_predicted <- predict(object = recc_model, newdata = recc_data_test, n = 5)
recc_predicted
## Recommendations as 'topNList' with n = 5 for 5353 users.
Теперь наша рекомендательная система будет рекомендовать пользователю 5 фильмов.
str(recc_predicted)
## Formal class 'topNList' [package "recommenderlab"] with 4 slots
## ..@ items :List of 5353
## .. ..$ 818736 : int [1:5] 336 430 373 437 261
## .. ..$ 693353 : int [1:5] 345 416 281 325 148
## .. ..$ 1454357: int [1:5] 454 45 97 147 307
## .. ..$ 153500 : int [1:5] 38 416 494 47 226
## .. ..$ 1239121: int [1:5] 322 287 155 441 31
## .. ..$ 1279398: int [1:5] 84 310 54 301 170
## .. ..$ 2145206: int [1:5] 322 5 301 376 437
## .. ..$ 978881 : int [1:5] 498 226 278 176 325
## .. ..$ 1439261: int [1:5] 371 32 281 97 301
## .. ..$ 460526 : int [1:5] 112 251 299 385 437
## .. ..$ 1644255: int [1:5] 97 186 326 437 230
## .. ..$ 2339841: int [1:5] 328 191 126 420 259
## .. ..$ 750327 : int [1:5] 50 187 352 494 325
## .. ..$ 1056819: int [1:5] 14 45 70 124 180
## .. ..$ 2014656: int [1:5] 5 20 81 84 228
## .. ..$ 1761324: int [1:5] 14 437 493 91 97
## .. ..$ 549416 : int [1:5] 416 239 435 393 264
## .. ..$ 944189 : int [1:5] 310 326 385 493 51
## .. ..$ 950078 : int [1:5] 139 199 345 2 13
## .. ..$ 1818137: int [1:5] 97 416 22 393 343
## .. ..$ 1412898: int [1:5] 219 14 279 490 224
## .. ..$ 1874187: int [1:5] 226 168 243 309 494
## .. ..$ 1418569: int [1:5] 326 421 2 416 345
## .. ..$ 1976734: int [1:5] 435 449 497 299 94
## .. ..$ 1114617: int [1:5] 41 50 156 344 454
## .. ..$ 464621 : int [1:5] 84 90 354 437 322
## .. ..$ 2035310: int [1:5] 7 123 2 81 216
## .. ..$ 2338153: int [1:5] 156 480 246 434 155
## .. ..$ 1444640: int [1:5] 402 310 6 10 146
## .. ..$ 742799 : int [1:5] 118 214 499 226 297
## .. ..$ 1290120: int [1:5] 38 332 491 479 232
## .. ..$ 2459573: int [1:5] 50 187 236 190 121
## .. ..$ 922922 : int [1:5] 97 354 272 195 2
## .. ..$ 2524669: int [1:5] 27 472 487 45 176
## .. ..$ 1829014: int [1:5] 81 412 430 470 33
## .. ..$ 2356471: int [1:5] 118 180 214 344 90
## .. ..$ 486399 : int [1:5] 59 299 5 278 204
## .. ..$ 1654132: int [1:5] 344 272 148 281 34
## .. ..$ 2618955: int [1:5] 325 195 437 443 354
## .. ..$ 356103 : int [1:5] 258 310 487 176 2
## .. ..$ 875273 : int [1:5] 158 272 362 185 5
## .. ..$ 2288907: int [1:5] 354 180 138 470 243
## .. ..$ 2051379: int [1:5] 421 435 77 313 487
## .. ..$ 2185062: int [1:5] 2 494 41 266 230
## .. ..$ 1584352: int [1:5] 97 421 402 321 454
## .. ..$ 1295424: int [1:5] 344 254 287 468 371
## .. ..$ 2058312: int [1:5] 199 272 494 38 39
## .. ..$ 2341509: int [1:5] 266 487 354 2 230
## .. ..$ 557167 : int [1:5] 416 138 176 336 443
## .. ..$ 815165 : int [1:5] 243 322 272 470 176
## .. ..$ 874732 : int [1:5] 50 97 266 272 454
## .. ..$ 531396 : int [1:5] 112 325 345 245 50
## .. ..$ 633253 : int [1:5] 124 393 243 18 264
## .. ..$ 735078 : int [1:5] 228 379 412 371 279
## .. ..$ 1553270: int [1:5] 494 322 487 301 376
## .. ..$ 679947 : int [1:5] 336 322 380 493 54
## .. ..$ 336413 : int [1:5] 74 272 176 148 97
## .. ..$ 617786 : int [1:5] 91 322 214 443 180
## .. ..$ 1568758: int [1:5] 148 187 243 87 138
## .. ..$ 567198 : int [1:5] 321 209 98 309 158
## .. ..$ 1225081: int [1:5] 266 345 344 41 375
## .. ..$ 1698123: int [1:5] 385 251 267 375 70
## .. ..$ 2538880: int [1:5] 281 336 5 487 224
## .. ..$ 1777917: int [1:5] 487 354 443 430 336
## .. ..$ 1174173: int [1:5] 325 47 195 437 336
## .. ..$ 943314 : int [1:5] 344 70 243 51 325
## .. ..$ 1203374: int [1:5] 247 262 357 14 380
## .. ..$ 1174779: int [1:5] 345 416 437 281 354
## .. ..$ 657364 : int [1:5] 416 375 91 261 412
## .. ..$ 1824444: int [1:5] 354 24 357 409 487
## .. ..$ 1092677: int [1:5] 80 165 274 153 92
## .. ..$ 867947 : int [1:5] 171 272 226 313 188
## .. ..$ 1502539: int [1:5] 2 23 266 136 379
## .. ..$ 2556129: int [1:5] 390 99 260 201 33
## .. ..$ 1737824: int [1:5] 112 357 239 366 249
## .. ..$ 1638551: int [1:5] 66 77 139 385 156
## .. ..$ 2260472: int [1:5] 197 325 494 437 261
## .. ..$ 2042756: int [1:5] 286 180 230 393 195
## .. ..$ 2203182: int [1:5] 149 220 343 101 390
## .. ..$ 252054 : int [1:5] 288 118 170 345 310
## .. ..$ 1213065: int [1:5] 322 326 213 81 51
## .. ..$ 1572525: int [1:5] 77 33 213 247 345
## .. ..$ 2430356: int [1:5] 38 251 322 417 294
## .. ..$ 2596404: int [1:5] 322 487 334 98 437
## .. ..$ 104237 : int [1:5] 232 381 408 18 64
## .. ..$ 1516350: int [1:5] 301 310 20 373 111
## .. ..$ 1930074: int [1:5] 228 307 393 138 8
## .. ..$ 667438 : int [1:5] 402 5 59 158 216
## .. ..$ 795665 : int [1:5] 33 79 371 376 281
## .. ..$ 1930443: int [1:5] 344 468 345 279 146
## .. ..$ 2397057: int [1:5] 345 32 371 171 258
## .. ..$ 561700 : int [1:5] 224 443 24 345 416
## .. ..$ 2643082: int [1:5] 50 123 129 493 404
## .. ..$ 1181609: int [1:5] 219 31 480 236 287
## .. ..$ 2396038: int [1:5] 195 261 354 325 437
## .. ..$ 1027371: int [1:5] 322 146 115 236 400
## .. ..$ 1360897: int [1:5] 379 156 416 310 50
## .. ..$ 341468 : int [1:5] 281 322 416 149 245
## .. ..$ 82577 : int [1:5] 79 156 180 138 228
## .. .. [list output truncated]
## ..@ ratings :List of 5353
## .. ..$ 818736 : num [1:5] 3.87 3.83 3.73 3.69 3.64
## .. ..$ 693353 : num [1:5] 5 4.67 4.63 4.56 4.55
## .. ..$ 1454357: num [1:5] 4.6 4.58 4.57 4.5 4.44
## .. ..$ 153500 : num [1:5] 4 4 4 3.93 3.89
## .. ..$ 1239121: num [1:5] 3.8 3.55 3.5 3.4 3.38
## .. ..$ 1279398: num [1:5] 4.5 4.38 4.19 4.14 4.07
## .. ..$ 2145206: num [1:5] 4.2 4.18 4.18 4.16 4.15
## .. ..$ 978881 : num [1:5] 4.29 4.29 4.27 4.25 4.22
## .. ..$ 1439261: num [1:5] 4.38 4.37 4.33 4.33 4.25
## .. ..$ 460526 : num [1:5] 5 5 5 5 4.78
## .. ..$ 1644255: num [1:5] 5 4.33 4.27 4.25 4.2
## .. ..$ 2339841: num [1:5] 4 3.86 3.75 3.75 3.67
## .. ..$ 750327 : num [1:5] 4 4 4 4 3.67
## .. ..$ 1056819: num [1:5] 5 5 5 5 5
## .. ..$ 2014656: num [1:5] 5 5 5 5 5
## .. ..$ 1761324: num [1:5] 4.79 4.71 4.69 4.68 4.67
## .. ..$ 549416 : num [1:5] 5 4.11 4 4 4
## .. ..$ 944189 : num [1:5] 4.5 4.42 4.4 4.38 4.37
## .. ..$ 950078 : num [1:5] 5 5 5 5 5
## .. ..$ 1818137: num [1:5] 5 4.5 4.5 4.5 4.21
## .. ..$ 1412898: num [1:5] 3.5 3.5 3.5 3.5 3.5
## .. ..$ 1874187: num [1:5] 4 4 4 4 4
## .. ..$ 1418569: num [1:5] 4.27 4.25 4.25 4.25 4.2
## .. ..$ 1976734: num [1:5] 5 5 5 4.5 4.5
## .. ..$ 1114617: num [1:5] 4 4 4 4 4
## .. ..$ 464621 : num [1:5] 4.33 4.07 4 4 4
## .. ..$ 2035310: num [1:5] 5 4.75 4.71 4.71 4.67
## .. ..$ 2338153: num [1:5] 5 4.17 4.14 4.12 4.07
## .. ..$ 1444640: num [1:5] 4.5 4.14 4.09 4.05 4
## .. ..$ 742799 : num [1:5] 5 4.5 4.4 4.17 4.17
## .. ..$ 1290120: num [1:5] 5 4.78 4.75 4.58 4.56
## .. ..$ 2459573: num [1:5] 4 4 4 3.89 3.89
## .. ..$ 922922 : num [1:5] 4.58 4.56 4.55 4.5 4.44
## .. ..$ 2524669: num [1:5] 4.32 4.26 4.17 4.13 4.12
## .. ..$ 1829014: num [1:5] 5 5 4.35 4.33 4.33
## .. ..$ 2356471: num [1:5] 5 5 5 5 5
## .. ..$ 486399 : num [1:5] 5 4.5 4.4 4.25 4.14
## .. ..$ 1654132: num [1:5] 5 4.75 4.71 4.57 4.5
## .. ..$ 2618955: num [1:5] 4.5 4.37 4.37 4.37 4.37
## .. ..$ 356103 : num [1:5] 5 4.44 4.4 4.2 4.17
## .. ..$ 875273 : num [1:5] 5 5 4.67 4.67 4.67
## .. ..$ 2288907: num [1:5] 5 4.67 4.5 4.5 4.5
## .. ..$ 2051379: num [1:5] 5 5 4.5 4.31 4.25
## .. ..$ 2185062: num [1:5] 5 5 5 5 4.75
## .. ..$ 1584352: num [1:5] 5 4.5 4.5 4.12 4
## .. ..$ 1295424: num [1:5] 4 3.64 3.63 3.61 3.6
## .. ..$ 2058312: num [1:5] 5 5 5 5 5
## .. ..$ 2341509: num [1:5] 3.79 3.77 3.73 3.73 3.71
## .. ..$ 557167 : num [1:5] 5 4.75 4.75 4.62 4.6
## .. ..$ 815165 : num [1:5] 5 5 4.83 4.78 4.75
## .. ..$ 874732 : num [1:5] 5 5 5 5 5
## .. ..$ 531396 : num [1:5] 5 4.67 4.67 4.5 4.5
## .. ..$ 633253 : num [1:5] 4.5 4.5 4.33 4.33 4.25
## .. ..$ 735078 : num [1:5] 4 4 4 3.8 3.74
## .. ..$ 1553270: num [1:5] 5 4.75 4.71 4.5 4.5
## .. ..$ 679947 : num [1:5] 4.16 4.14 4.11 4.1 4.09
## .. ..$ 336413 : num [1:5] 4 3.92 3.83 3.82 3.8
## .. ..$ 617786 : num [1:5] 4.5 4.33 4.33 4.33 4.33
## .. ..$ 1568758: num [1:5] 5 5 5 5 5
## .. ..$ 567198 : num [1:5] 4 3.67 3.5 3.5 3.4
## .. ..$ 1225081: num [1:5] 5 5 4.5 4 4
## .. ..$ 1698123: num [1:5] 5 4.75 4.75 4.7 4.67
## .. ..$ 2538880: num [1:5] 4.83 4.72 4.71 4.56 4.55
## .. ..$ 1777917: num [1:5] 5 4.38 4.33 4.25 4.21
## .. ..$ 1174173: num [1:5] 4.57 4.53 4.5 4.5 4.5
## .. ..$ 943314 : num [1:5] 5 4.5 4.38 4.33 4.33
## .. ..$ 1203374: num [1:5] 4.2 4.17 4.06 4 4
## .. ..$ 1174779: num [1:5] 5 4.67 4.5 4.4 4.38
## .. ..$ 657364 : num [1:5] 5 4.4 4.38 4.27 4.25
## .. ..$ 1824444: num [1:5] 4.17 4.13 4.12 4 4
## .. ..$ 1092677: num [1:5] 5 4.79 4.75 4.73 4.71
## .. ..$ 867947 : num [1:5] 4.53 4.5 4.5 4.43 4.39
## .. ..$ 1502539: num [1:5] 3.92 3.92 3.91 3.89 3.87
## .. ..$ 2556129: num [1:5] 4.29 4.15 4.07 4 4
## .. ..$ 1737824: num [1:5] 5 4.75 4.7 4.63 4.6
## .. ..$ 1638551: num [1:5] 5 5 5 5 5
## .. ..$ 2260472: num [1:5] 5 5 5 4.9 4.89
## .. ..$ 2042756: num [1:5] 5 4.5 4.25 4.2 4.2
## .. ..$ 2203182: num [1:5] 4.28 4.27 4.25 4.2 4.2
## .. ..$ 252054 : num [1:5] 4.25 4.2 4.18 4.11 4.1
## .. ..$ 1213065: num [1:5] 5 4.83 4.75 4.71 4.64
## .. ..$ 1572525: num [1:5] 5 5 5 5 5
## .. ..$ 2430356: num [1:5] 5 5 5 5 4.75
## .. ..$ 2596404: num [1:5] 4.33 4.33 4.33 4.33 4.25
## .. ..$ 104237 : num [1:5] 5 5 5 5 5
## .. ..$ 1516350: num [1:5] 4 4 3.74 3.66 3.62
## .. ..$ 1930074: num [1:5] 4 4 4 4 4
## .. ..$ 667438 : num [1:5] 5 5 5 5 5
## .. ..$ 795665 : num [1:5] 4.25 4.2 4.08 4.08 4
## .. ..$ 1930443: num [1:5] 5 4.25 4.25 4.21 4.2
## .. ..$ 2397057: num [1:5] 5 4.67 4.33 4.31 4
## .. ..$ 561700 : num [1:5] 4.08 4.08 4 4 4
## .. ..$ 2643082: num [1:5] 5 5 4.67 4.5 4.5
## .. ..$ 1181609: num [1:5] 4.27 4.19 4.18 4.13 4.12
## .. ..$ 2396038: num [1:5] 4.6 4.5 4.5 4.5 4.5
## .. ..$ 1027371: num [1:5] 5 4.38 4.33 4.25 4.25
## .. ..$ 1360897: num [1:5] 5 5 5 4.67 4.67
## .. ..$ 341468 : num [1:5] 4 4 4 3.83 3.8
## .. ..$ 82577 : num [1:5] 5 5 5 5 5
## .. .. [list output truncated]
## ..@ itemLabels: chr [1:500] "user_id" "3" "45" "148" ...
## ..@ n : int 5
Рекомендации для пользователя c user_id= 1360897:
recc_user_1 <- recc_predicted@items[["1360897"]]
movies_user_1 <- recc_predicted@itemLabels[recc_user_1]#вытащим id фильма
names_movies_user_1 <- mn$title[match(movies_user_1, mn$movie_id)]#посмотрим на названия фильмов
names_movies_user_1
## [1] "Tumbleweeds" "Major Dundee"
## [3] "The Work and the Glory" "Oldboy"
## [5] "Manito"
А теперь попробуем метод UBCF (основан на схожести пользователей) и посмотрим, что в этот раз нам порекомендует системадля десятого пользователя:
recc_model_ubcf <- Recommender(data = recc_data_train, method = "UBCF",parameter = list(nn =
25))
recc_model_ubcf
## Recommender of type 'UBCF' for 'realRatingMatrix'
## learned using 21414 users.
#recc_predicted_ubcf <- predict(object = recc_model_ubcf, newdata = recc_data_test, n = 6)
#recc_predicted_ubcf
#recc_user_12 <- recc_predicted_ubcf@items[["1360897"]]
#movies_user_12 <- recc_predicted_ubcf@itemLabels[recc_user_12]
#names_movies_user_12 <- mn$title[match(movies_user_12, mn$movie_id)]
#names_movies_user_12
#recc_model <- Recommender(data = recc_data_train, method = "IBCF", parameter = list(k = 30))
#recc_model
#recc_predicted <- predict(object = recc_model, newdata = recc_data_test, n = 5)
#recc_predicted
#допюдатасет:
mnmean=mn%>%group_by(movie_id)%>%summarize(marks=mean(mark,na.rm=T))
new=inner_join(mnmean,movies)
## Joining, by = "movie_id"
newnewnew=new%>%dplyr::select(movie_id,title,popularity,marks)
find_filmColl=function(user_id, n=6){
recc_user_n <- recc_predicted@items[[user_id]]
if (length(recc_user_n)>0){movies_user_n <- recc_predicted@itemLabels[recc_user_n]
names_movies_user_n <- mn$title[match(movies_user_n, mn$movie_id)]
names_movies_user_n}
else {newnewnew%>%top_n(6,marks)}
}
## [1] "Tumbleweeds" "Major Dundee"
## [3] "The Work and the Glory" "Oldboy"
## [5] "Manito"
coldF <- as.data.frame(bind_rows(coldG,coldD,coldA,coldO,coll))
## Warning in bind_rows_(x, .id): binding character and factor vector,
## coercing into character vector
filter <- data.frame(c("Genre","Director","Actor","Oscar","Other users"))
names(filter)[1] <- "filters"
coldF <- cbind(coldF,filter)
coldF
## title filters
## 1 Wild Things Genre
## 2 The Wedding Planner Director
## 3 Dogma Actor
## 4 Jaws Oscar
## 5 Tumbleweeds Other users