library(tidyverse)
data("germeval_train", package = "pradadata")
data("germeval_test", package = "pradadata")
germeval03-sent-wordvec-xgb-plain
Aufgabe
Erstellen Sie ein prädiktives Modell für Textdaten. Nutzen Sie Sentiments und TextFeatures im Rahmen von Feature-Engineering. Nutzen Sie außerdem deutsche Word-Vektoren für das Feature-Engineering.
Als Lernalgorithmus verwenden Sie XGB.
Preppen und Backen Sie das Rezept, aber führen Sie die Pipelien mit dem gebackenen Datensatz und einem “Plain-Rezept” durch.
Daten
Verwenden Sie die GermEval-2018-Daten.
Die Daten sind unter CC-BY-4.0 lizensiert. Author: Wiegand, Michael (Spoken Language Systems, Saarland University (2010-2018), Leibniz Institute for the German Language (since 2019)),
Die Daten sind auch über das R-Paket PradaData zu beziehen.
AV und UV
Die AV lautet c1
. Die (einzige) UV lautet: text
.
Hinweise
- Orientieren Sie sich im Übrigen an den allgemeinen Hinweisen des Datenwerks.
- Nutzen Sie Tidymodels.
- Nutzen Sie das
sentiws
Lexikon. - ❗ Achten Sie darauf, die Variable
c2
zu entfernen bzw. nicht zu verwenden.
Lösung
Setup
<-
d_train |>
germeval_train select(id, c1, text)
library(tictoc)
library(tidymodels)
library(syuzhet)
library(beepr)
library(lobstr) # object size
library(visdat) # Fingerprint/footprint of dataset (CSV)
data("sentiws", package = "pradadata")
Learner/Modell
<-
mod boost_tree(mode = "classification",
learn_rate = tune(),
tree_depth = tune()
)
Rezept Workvektoren
Pfad zu den Wordvektoren:
<- "/Users/sebastiansaueruser/datasets/word-embeddings/wikipedia2vec/part-0.arrow" path_wordvec
source("https://raw.githubusercontent.com/sebastiansauer/Datenwerk2/main/funs/def_recipe_wordvec_senti.R")
<- def_recipe_wordvec_senti(data_train = d_train,
rec path_wordvec = path_wordvec)
Prep/Bake Wordvektoren
tic()
<- prep(rec)
rec_prepped toc()
78.021 sec elapsed
<- bake(rec_prepped, new_data = NULL) d_rec_baked
sum(is.na(d_rec_baked))
Test-Set auch baken
<- bake(rec_prepped, new_data = germeval_test)
d_test_baked dim(d_test_baked)
write_csv(d_test_baked, "data/germeval/germeval_test_recipe_wordvec_senti.csv")
Später kann man es dann analog wieder importieren:
<- read_csv("https://raw.githubusercontent.com/sebastiansauer/Datenwerk2/main/data/germeval/germeval_test_recipe_wordvec_senti.csv") d_test_baked
Gebackenen Datensatz als neue Grundlage
Den gepreppten/gebackenen Datensatz speichern wir als Datensatz ab:
write_csv(d_rec_baked, "https://raw.githubusercontent.com/sebastiansauer/Datenwerk2/main/data/germeval/germeval_train_recipe_wordvec_senti.csv")
Später können wir den Datensatz als “neuen, frischen” Datensatz für ein “Plain-Rezept”, also ein ganz einfaches Rezept nutzen. Das hat den Vorteil (hoffentlich), das die Datenvolumina viel kleiner sind.
<-
d_train_new read_csv("https://raw.githubusercontent.com/sebastiansauer/Datenwerk2/main/data/germeval/germeval_train_recipe_wordvec_senti.csv")
vis_dat(d_train_new) +
# remove axis labels:
theme(axis.text.x=element_blank(),
axis.ticks.x=element_blank()
)
Plain-Rezept
<-
rec recipe(c1 ~ ., data = d_train_new)
Neuer Workflow mit plainem Rezept
<-
wf workflow() |>
add_recipe(rec) |>
add_model(mod)
wf
══ Workflow ════════════════════════════════════════════════════════════════════
Preprocessor: Recipe
Model: boost_tree()
── Preprocessor ────────────────────────────────────────────────────────────────
0 Recipe Steps
── Model ───────────────────────────────────────────────────────────────────────
Boosted Tree Model Specification (classification)
Main Arguments:
tree_depth = tune()
learn_rate = tune()
Computational engine: xgboost
Parallelisierung über mehrere Kerne
library(parallel)
<- detectCores(logical = FALSE)
all_cores
library(doFuture)
registerDoFuture()
<- makeCluster(2)
cl plan(cluster, workers = cl)
Achtung: Viele Kerne brauchen auch viel Speicher.
Tune/Resample/Fit
tic()
<-
fit_wordvec_senti_xgb tune_grid(
wf,grid = 50,
resamples = vfold_cv(d_train_new, v = 5))
toc()
285.723 sec elapsed
beep()
Objekt-Größe:
::obj_size(fit_wordvec_senti_xgb) lobstr
5.11 MB
Ah! Angenehm klein.
Get best performance
autoplot(fit_wordvec_senti_xgb)
show_best(fit_wordvec_senti_xgb)
# A tibble: 5 × 8
tree_depth learn_rate .metric .estimator mean n std_err .config
<int> <dbl> <chr> <chr> <dbl> <int> <dbl> <chr>
1 10 0.252 roc_auc binary 0.761 5 0.0108 Preprocessor1_Mo…
2 9 0.220 roc_auc binary 0.760 5 0.00759 Preprocessor1_Mo…
3 10 0.179 roc_auc binary 0.758 5 0.0111 Preprocessor1_Mo…
4 5 0.106 roc_auc binary 0.758 5 0.0115 Preprocessor1_Mo…
5 2 0.286 roc_auc binary 0.757 5 0.00868 Preprocessor1_Mo…
<- select_best(fit_wordvec_senti_xgb) best_params
Finalisieren
<- select_best(fit_wordvec_senti_xgb)
best_params tic()
<- finalize_workflow(wf, best_params)
wf_finalized <- fit(wf_finalized, data = d_train_new)
lastfit_xgb toc()
2.853 sec elapsed
Test-Set-Güte
tic()
<-
preds predict(lastfit_xgb, new_data = d_test_baked)
toc()
0.035 sec elapsed
<-
d_test |>
germeval_test bind_cols(preds) |>
mutate(c1 = as.factor(c1))
<- metric_set(accuracy, f_meas)
my_metrics my_metrics(d_test,
truth = c1,
estimate = .pred_class)
# A tibble: 2 × 3
.metric .estimator .estimate
<chr> <chr> <dbl>
1 accuracy binary 0.714
2 f_meas binary 0.484
Fazit
Verzichtet man auf ein Rezept mit viel Datenvolument (Wordvektoren blähen das Rezept mächtig auf), so wird das Fitten schlanker und schneller. Schneller auch deshalb, weil ggf. kein Swapping zwischen Speicher und Festplatte mehr nötig ist.