set.seed(1)
train <- vienna |> slice_sample(prop = 0.8)
test <- vienna |> anti_join(train, by = "hotel_id")Exercise: explain it, then predict it
Session 8 — Applied Data Science 2026
The board has two questions about Vienna. Does guest rating change the picture of the location premium? And what price could a new four-star hotel, two kilometres from the centre and rated 4.2 by its guests, charge?
Alone or in pairs. Two parts: Part A and Part B.
Create session08.qmd in your project. Nothing new to install: broom comes with the tidyverse.
```{r}
#| label: setup
#| include: false
library(tidyverse)
library(broom)
library(here)
i_am("session08.qmd")
prices <- read_csv(here("data", "hotels-europe_price.csv"))
features <- read_csv(here("data", "hotels-europe_features.csv"))
vienna <- prices |>
filter(year == 2017, month == 11, weekend == 0) |>
inner_join(features, by = "hotel_id") |>
filter(city == "Vienna", city_actual == "Vienna",
accommodation_type == "Hotel",
price < 1000, stars >= 1.5,
!is.na(rating)) |>
mutate(
star_tier = factor(paste(floor(stars + 0.5), "stars")),
star_tier = relevel(star_tier, ref = "3 stars"),
central = distance <= 1,
ln_price = log(price)
)
rmse <- function(actual, predicted) {
sqrt(mean((actual - predicted)^2))
}
```One difference from the live coding: hotels without a guest rating are dropped, so that every model in Part B is fitted on the same hotels.
Part A — Explaining
A1 · Add the rating
Fit ln_price ~ distance + star_tier + rating. Then write two sentences, one for rating and one for distance, in this form:
Holding … constant, the model estimates an average association of about …% higher/lower prices per additional …
Each part of the sentence matters: holding … constant (the other variables in the model — ceteris paribus), the model estimates (it is a property of this model, not a law of nature), on average (individual hotels deviate), association (not an effect).
Did the distance coefficient change compared with the model without rating? In which direction, and why might that be?
tidy(model) gives the coefficients. On the log scale, a coefficient b multiplies the price by exp(b): exp(b) - 1 is the percentage change.
Part B — Predicting
B1 · Four models, one test
Split the data:
Fit these four models on train and compute the RMSE on train and on test for each:
| Model | Formula |
|---|---|
| m1 | ln_price ~ distance |
| m2 | ln_price ~ distance + star_tier |
| m3 | ln_price ~ distance + star_tier + rating |
| m4 | ln_price ~ poly(distance, 5) + star_tier + poly(rating, 3) |
Put the results in one table. Which model fits the training data best? Which predicts the test data best?
For one model:
m1 <- lm(ln_price ~ distance, data = train)
rmse(train$ln_price, predict(m1, newdata = train))
rmse(test$ln_price, predict(m1, newdata = test))Four times — or write a small function that takes a formula and returns both numbers, and apply it to all four formulas with purrr::map(), as in the live coding.
B2 · Price the new hotel
Use the model that predicts best to price the board’s hotel: two kilometres, four stars, rating 4.2.
new_hotel <- tibble(distance = 2, rating = 4.2,
star_tier = factor("4 stars", levels = levels(vienna$star_tier)))Give the predicted median price in euros, and say how far off a prediction from this model typically is, using its test RMSE: between which two prices does the actual price typically lie?
exp(predict(model, newdata = new_hotel)) gives the median price. A test RMSE of r on the log scale means a typical error by a factor of exp(r) — up and down: the typical range runs from the prediction divided by exp(r) to the prediction multiplied by exp(r).
B3 · Change one number
Run B1 again with set.seed(2026) instead of set.seed(1). Does the same model win? What does that tell you about choosing a model with one train/test split?
If you finish early
a) Overfit on purpose
Repeat the polynomial experiment from the live coding for rating instead of distance: ln_price ~ distance + star_tier + poly(rating, d) for d from 1 to 8. Plot training and test RMSE.
b) Explain or predict?
For each, decide whether it is an explaining or a predicting question, and which number you would look at:
- What should the group charge for its new hotel?
- Do guests pay for good reviews, or only for stars?
- Which hotels in the data are priced unusually high for what they offer?