第 4 章 创建模型

4.1 钻石数据探索

为什么品质低的钻石,价格反而更高?

library(tidyverse)
## -- Attaching packages --------------------------------------- tidyverse 1.3.1 --
## v ggplot2 3.3.5     v purrr   0.3.4
## v tibble  3.1.6     v dplyr   1.0.7
## v tidyr   1.1.4     v stringr 1.4.0
## v readr   2.1.1     v forcats 0.5.1
## -- Conflicts ------------------------------------------ tidyverse_conflicts() --
## x dplyr::filter() masks stats::filter()
## x dplyr::lag()    masks stats::lag()
library(modelr)
ggplot(diamonds, aes(cut, price)) + geom_boxplot()

ggplot(diamonds, aes(color, price)) + geom_boxplot()

ggplot(diamonds, aes(clarity, price)) + geom_boxplot()

4.2 价格与克拉

看起来低品质钻石价格更贵的原因可能与钻石的克拉数有关。低品质的钻石好像更重.

ggplot(diamonds, aes(carat, price)) + 
  geom_hex(bins = 50)

如果把克拉变量分离出来,就很容易看出其他变量对价格的影响。先对原始数据进行处理以便建模。

  1. 筛选出小于2.5克拉的数据,样本的99.7%。
  2. 将克拉和价格取对数。
diamonds2 <- diamonds %>% 
  filter(carat <= 2.5) %>% 
  mutate(lprice = log2(price), lcarat = log2(carat))

这样处理后,更容易发现其他变量对价格的影响。

ggplot(diamonds2, aes(lcarat, lprice)) + 
  geom_hex(bins = 50)

上图可见,经对数处理后的价格和克拉呈线性相关。线性关系就比较容易处理了。先建立一个线性模型。

mod_diamond <- lm(data = diamonds2, lprice ~ lcarat)

看看这个模型告诉我们什么,

grid <- diamonds2 %>% 
  data_grid(carat = seq_range(carat, 20)) %>% 
  mutate(lcarat = log2(carat)) %>% 
  add_predictions(mod_diamond, "lprice") %>% 
  mutate(price = 2 ^ lprice)

ggplot(diamonds2, aes(carat, price)) + 
  geom_hex(bins = 50) + 
  geom_line(data = grid, colour = "red", size = 1)

看起来克拉对价格的影响并没有我们想像的那么大。我们再看看残差的分布以验证我们是否分离了克拉对价格的强线性相关。

diamonds2 <- diamonds2 %>% 
  add_residuals(mod_diamond, "lresid")

ggplot(diamonds2, aes(lcarat, lresid)) + 
  geom_hex(bins = 50)

现在可以开始实现我们最初的目的,用残差代替价格来观察其他变量对价格的影响。

ggplot(diamonds2, aes(cut, lresid)) + geom_boxplot()

ggplot(diamonds2, aes(color, lresid)) + geom_boxplot()

ggplot(diamonds2, aes(clarity, lresid)) + geom_boxplot()

现在看起来符合我们正常的逻辑了。