统计变换+位置调整+整合
统计变换
统计变换可将输入的数据集看做输入,将返回的数据集作为输出,因此统计变换可以向原数据集中插入新的变量。例如,常被用来绘制直方图的stat_bin
统计变换会生成如下变量:
count
,每个组里观测值的数目;density
,每个组里观测值的密度(占整体的百分数/组宽);x
,组的中心位置。
这些生成变量可以被直接调用。
例如,直方图默认将条形的高度赋值为观测值的频数(count
),如果你更喜欢传统的直方图,你可以用密度(density
)来代替。下
面的例子给出了钻石数据集中的克拉(carat
)的密度直方图。
ggplot(diamonds, aes(carat)) +
geom_histogram(aes(y = ..density..), binwidth = 0.1)
#或
qplot(carat, ..density.., data = diamonds, geom = "histogram", binwidth = 0.1)
位置调整
应用于条形图的三种位置调整
从上到下次是:堆叠(stacking
),填充(filling
)和并列(dodging
)
dplot <- ggplot(diamonds, aes(clarity, fill = cut))
dplot + geom_bar(position = "stack")
dplot + geom_bar(position = "fill")
dplot + geom_bar(position = "dodge")
整合
集合集合对象和统计变换
频率多边形(frequency polygon)(上);
散点图,点的大小和高度都映射给了频率(下)
d <- ggplot(diamonds, aes(carat)) + xlim(0, 3)
d + stat_bin(aes(ymax = ..count..), binwidth = 0.1, geom = "area")
d + stat_bin(aes(size = ..density..), binwidth = 0.1, geom = "point", position = "identity")
改变图形属性和数据集
例:nlme包的Oxboys数据集
首先我们读入nlme包,然后拟合一个截距和斜率都包含随机效应的混合模型。(通过对个体模型的探索得知这个模型是合理的。)我们仍然要先建一个图形对象作为模板,这一步和之前做法一致,然后我们利用从模型中导出的数据对模型进行渲染。
require(nlme, quiet = TRUE, warn.conflicts = FALSE)
model <- lme(height ~ age, data = Oxboys, random = ~1 + age | Subject)
oplot <- ggplot(Oxboys, aes(age, height, group = Subject)) + geom_line()
随后,我们对预测的生长轨迹和实际的生长轨迹进行对比。我们先建立一个包含所有年龄(age)和个体(subjects)组合的网格数据框。对于这个简单的线性模型这么做虽然显得有点小题大做,但是仍作为例子放到这里,为以后处理更加复杂的模型提供参考。接下来我们把模型的预测值添加到刚刚生成的数据集中,变量名叫height。
age_grid <- seq(-1, 1, length = 10)
subjects <- unique(Oxboys$Subject)
preds <- expand.grid(age = age_grid, Subject = subjects)
preds$height <- predict(model, preds)
得到预测值后,我们把它和原始数据绘制到同一张图上。因为在新数据集preds里,我们使用了与原始数据0xboys相同的变量名,并且我们想使用相同的分组图形属性,所以我们不用修改任何图形属性,只需要修改默认的数据集即可。我们还设定了颜色和大小两个图形属性参数以便于图形的比较。
oplot + geom_line(data = preds, colour = "#3366FF", size = 0.4)
从图形上看,这个模型似乎很好地拟合了该数据更深层次的结构,但是仍然很难分辨细节。另一种比较模型拟合好坏的方法是观察残差,所以我们也演示一下这种方法。首先我们把拟合值(fitted)和残差(resid)都添加到原数据里去,然后更新数据集(用%+%
),将默认的y图形属性改成resid
,最后对整个数据添加一条光滑曲线。
Oxboys$fitted <- predict(model)
Oxboys$resid <- with(Oxboys, fitted - height)
oplot %+% Oxboys + aes(y = resid) + geom_smooth(aes(group = 1))
从图形可以看到残差并不是随机分布的,因此所建立的模型有缺陷。我们向模型中添加一个二次项,再次计算拟合值和残差并重新绘制残差图。这次没有明显的证据表明模型拟合得不好。
model2 <- update(model, height ~ age + I(age^2))
Oxboys$fitted2 <- predict(model2)
Oxboys$resid2 <- with(Oxboys, fitted2 - height)
oplot %+% Oxboys + aes(y = resid2) + geom_smooth(aes(group = 1))
值得注意的是,我们对图形对象的修改是非常容易的。我们更新了数据并且重新作了两次图却没有再次运行过oplot,这正是ggplot2图层功能所秉承的理念:使得反复拟合和评估模型变得轻松而自然。