tmdb02

ds1
tidymodels
statlearning
tmdb
trees
num
Published

May 17, 2023

Aufgabe

Wir bearbeiten hier die Fallstudie TMDB Box Office Prediction - Can you predict a movie’s worldwide box office revenue?, ein Kaggle-Prognosewettbewerb.

Ziel ist es, genaue Vorhersagen zu machen, in diesem Fall für Filme.

Die Daten können Sie von der Kaggle-Projektseite beziehen oder so:

d_train_path <- "https://raw.githubusercontent.com/sebastiansauer/Lehre/main/data/tmdb-box-office-prediction/train.csv"
d_test_path <- "https://raw.githubusercontent.com/sebastiansauer/Lehre/main/data/tmdb-box-office-prediction/test.csv"
Aufgabe

Reichen Sie bei Kaggle eine Submission für die Fallstudie ein! Berichten Sie den Kaggle-Score

Hinweise:

  • Sie müssen sich bei Kaggle ein Konto anlegen (kostenlos und anonym möglich); alternativ können Sie sich mit einem Google-Konto anmelden.
  • Berechnen Sie einen Entscheidungsbaum und einen Random-Forest.
  • Tunen Sie nach Bedarf; verwenden Sie aber Default-Werte.
  • Verwenden Sie Tidymodels.











Lösung

Vorbereitung

library(tidyverse)
library(tidymodels)
library(tictoc)
library(doParallel)  # mehrere CPUs nutzen
library(finetune)  # Tune Anova
d_train <- read_csv(d_train_path)
d_test <- read_csv(d_test_path)

glimpse(d_train)
glimpse(d_test)

Rezept

Rezept definieren

rec1 <-
  recipe(revenue ~ ., data = d_train) %>% 
  update_role(all_predictors(), new_role = "id") %>% 
  update_role(popularity, runtime, revenue, budget) %>% 
  update_role(revenue, new_role = "outcome") %>% 
  step_mutate(budget = ifelse(budget < 10, 10, budget)) %>% 
  step_log(budget) %>% 
  step_impute_knn(all_predictors())

rec1

Check das Rezept

rec1_prepped <-
  prep(rec1, verbose = TRUE)

rec1_prepped
d_train_baked <-
  rec1_prepped %>% 
  bake(new_data = NULL) 

head(d_train_baked)

Die AV-Spalte sollte leer sein:

bake(rec1_prepped, new_data = head(d_test), all_outcomes())
d_train_baked %>% 
  map_df(~ sum(is.na(.)))

Keine fehlenden Werte mehr in den Prädiktoren.

Nach fehlenden Werten könnte man z.B. auch so suchen:

datawizard::describe_distribution(d_train_baked)

So bekommt man gleich noch ein paar Infos über die Verteilung der Variablen. Praktische Sache.

Das Test-Sample backen wir auch mal:

d_test_baked <-
  bake(rec1_prepped, new_data = d_test)

d_test_baked %>% 
  head()

Kreuzvalidierung

cv_scheme <- vfold_cv(d_train,
                      v = 5, 
                      repeats = 1)

Modelle

Baum

mod_tree <-
  decision_tree(cost_complexity = tune(),
                tree_depth = tune(),
                mode = "regression")

Random Forest

mod_rf <-
  rand_forest(mtry = tune(),
              min_n = tune(),
              trees = 1000,
              mode = "regression") %>% 
  set_engine("ranger", num.threads = 4)

Workflows

wf_tree <-
  workflow() %>% 
  add_model(mod_tree) %>% 
  add_recipe(rec1)

wf_rf <-
  workflow() %>% 
  add_model(mod_rf) %>% 
  add_recipe(rec1)

Fitten und tunen

Um Rechenzeit zu sparen, kann man den Parameter grid bei tune_grid() auf einen kleinen Wert setzen. Der Default ist 10. Um gute Vorhersagen zu erzielen, sollte man den Wert tendenziell noch über 10 erhöhen.

Tree

Parallele Verarbeitung starten:

cl <- makePSOCKcluster(4)  # Create 4 clusters
registerDoParallel(cl)
tic()
tree_fit <-
  wf_tree %>% 
  tune_race_anova(
    resamples = cv_scheme,
    #grid = 2
  )
toc()

Hilfe zu tune_grid() bekommt man hier.

tree_fit

Steht was in den .notes?

tree_fit[[".notes"]][[2]]

Nein.

collect_metrics(tree_fit)
show_best(tree_fit)

Finalisieren

best_tree_wf <-
  wf_tree %>% 
  finalize_workflow(select_best(tree_fit))

best_tree_wf
tree_last_fit <-
  fit(best_tree_wf, data = d_train)

tree_last_fit

Vorhersage Test-Sample

predict(tree_last_fit, new_data = d_test)

RF

Fitten und Tunen

Um Rechenzeit zu sparen, kann man das Objekt, wenn einmal berechnet, abspeichern unter result_obj_path auf der Festplatte und beim nächsten Mal importieren, das geht schneller als neu berechnen.

Das könnte dann z.B. so aussehen:

if (file.exists(result_obj_path)) {
  rf_fit <- read_rds(result_obj_path)
} else {
  tic()
  rf_fit <-
    wf_rf %>% 
    tune_grid(
      resamples = cv_scheme)
  toc()
}

Achtung Ein Ergebnisobjekt von der Festplatte zu laden ist gefährlich. Wenn Sie Ihr Modell verändern, aber vergessen, das Objekt auf der Festplatte zu aktualisieren, werden Ihre Ergebnisse falsch sein (da auf dem veralteten Objekt beruhend), ohne dass Sie durch eine Fehlermeldung von R gewarnt würden!

So kann man das Ergebnisobjekt auf die Festplatte schreiben:

#write_rds(rf_fit, file = "objects/tmbd_rf_fit1.rds")

Aber wir berechnen lieber neu:

tic()
rf_fit <-
  wf_rf %>% 
  tune_grid(
    resamples = cv_scheme
    #grid = 2
    )
toc()
collect_metrics(rf_fit)
select_best(rf_fit)

Finalisieren

final_wf <-
  wf_rf %>% 
  finalize_workflow(select_best(rf_fit))
final_fit <-
  fit(final_wf, data = d_train)
final_preds <- 
  final_fit %>% 
  predict(new_data = d_test) %>% 
  bind_cols(d_test)
submission <-
  final_preds %>% 
  select(id, revenue = .pred)

Abspeichern und einreichen:

write_csv(submission, file = "submission.csv")

Kaggle Score

Diese Submission erzielte einen Score von 2.7664 (RMSLE).

sol <- 2.7664

Categories:

  • ds1
  • tidymodels
  • statlearning
  • tmdb
  • trees
  • num