《ggplot2:数据分析与图形艺术》--学习笔记9

数据操作

plyr包

ddply()函数能够同时在数据的多个子集上作统计汇总。该函数能够根据行的取值,把数据框分解成几个子集,分别把各个子集输入某个函数,最后把结果综合在一个数据框内。基本用法是ddply(.data, .variables, .fun, ...),其中“

  • .data 是用来作图的数据。
  • .variables是对数据取子集的分组变量,形式是.(var1,var2)。
  • .fun是要在各子集上运行的统计汇总函数。
  • .subset()用来对数据取子集的函数,选择数据中前(或后)n个(或x%的)观测值,或是在某个阈值之上或下的观测值。
library(ggplot2)
library(plyr)
## 选取各个颜色里最小的钻石
ddply(diamonds,.(color), subset, carat == min(carat))

## 选取最小的两颗钻石
ddply(diamonds,.(color), subset, order(carat) <= 2)

## 选取每组里大小为前1%的钻石
ddply(diamonds,.(color), subset, carat > quantile(carat,0.99))

## 选出所有比组平均值大的钻石
ddply(diamonds,.(color), subset, price > mean(price))
  • transform()是用来进行数据变换的函数。
## 把每个颜色组里钻石的价格标准化,使其均值为0,方差为1
ddply(diamonds,.(color),transform, price = scale(price))
## 减去组均值
ddply(diamonds,.(color),transform,price=price-mean(price))
  • colwise()用来向量化一个普通函数,即能把原本只接受向量输入的函数变成可以接受数据框输入的函数。下面例子里函数nmissing()计算向量里缺失值的数目,用colwise()向量化后,可以应用到数据框上,计算数据框各列的缺失值数目。
> nmissing <- function(x) sum(is.na(x))
> nmissing(msleep$name)
[1] 0
> nmissing(msleep$bodywt)
[1] 0
> nmissing(msleep$brainwt)
[1] 27
> nmissing_df <- colwise(nmissing)
> nmissing_df(msleep)
  name genus vore order conservation sleep_total sleep_rem
1    0     0    7     0           29           0        22
  sleep_cycle awake brainwt bodywt
1          51     0      27      0
> ## 更便捷的方法
> colwise(nmissing)(msleep)
  name genus vore order conservation sleep_total sleep_rem
1    0     0    7     0           29           0        22
  sleep_cycle awake brainwt bodywt
1          51     0      27      0

numcolwise()是colwise()的一个特殊版本,功能类似,但只对数值类型的列操作。

> msleep2 <- msleep[,-6] ##移除第六列
> numcolwise(median)(msleep2,na.rm = T)
  sleep_rem sleep_cycle awake brainwt bodywt
1       1.5   0.3333333  13.9  0.0124   1.67
> numcolwise(quantile)(msleep2,na.rm = T)
  sleep_rem sleep_cycle awake brainwt   bodywt
1       0.1   0.1166667  4.10 0.00014    0.005
2       0.9   0.1833333 10.25 0.00290    0.174
3       1.5   0.3333333 13.90 0.01240    1.670
4       2.4   0.5791667 16.15 0.12550   41.750
5       6.6   1.5000000 22.10 5.71200 6654.000
> numcolwise(quantile)(msleep2,probs=c(0.25,0.75),na.rm=T)
  sleep_rem sleep_cycle awake brainwt bodywt
1       0.9   0.1833333 10.25  0.0029  0.174
2       2.4   0.5791667 16.15  0.1255 41.750

以上这些函数与ddply一起可以对数据进行各种分组统计。

> ddply(msleep2,.(vore),numcolwise(median),na.rm = T)
     vore sleep_rem sleep_cycle awake  brainwt bodywt
1   carni      1.95   0.3833333  13.6 0.044500 20.490
2   herbi      0.95   0.2166667  13.7 0.012285  1.225
3 insecti      3.00   0.1666667   5.9 0.001200  0.075
4    omni      1.85   0.5000000  14.1 0.006600  0.950
5    <NA>      2.00   0.1833333  13.4 0.003000  0.122
  • 如果以上提供的函数不够用,可以编写自己的函数,只要它也能接收、输出数据框就可以。
> my_summary <- function(df){
+   with(df,data.frame(
+     pc_cor = cor(price,carat,method = "spearman"),
+     lpc_cor = cor(log(price),log(carat))
+   ))
+ }
> ddply(diamonds,.(cut),my_summary)
        cut    pc_cor   lpc_cor
1      Fair 0.9056144 0.9085131
2      Good 0.9599684 0.9687510
3 Very Good 0.9688534 0.9716746
4   Premium 0.9605332 0.9697578
5     Ideal 0.9537275 0.9661884
> ddply(diamonds,.(color),my_summary)
  color    pc_cor   lpc_cor
1     D 0.9561208 0.9606617
2     E 0.9600994 0.9643845
3     F 0.9641572 0.9623876
4     G 0.9633681 0.9696785
5     H 0.9730390 0.9801569
6     I 0.9834392 0.9865118
7     J 0.9846710 0.9879449

注意,上面例子里的函数my_summary()里没有输出分组变量cut和color,但是最终输出里却自动包含了这些分组变量。

拟合多个模型

怎么用plyr完成ggplot2内置的统计功能?

p1<-qplot(carat,price,data = diamonds,geom = "smooth",colour = color)
dense <- subset(diamonds,carat < 2)
p2<-qplot(carat,price,data = dense,geom = "smooth",colour = color,fullrange = T)

在这里插入图片描述如何用plyr生成一模一样的图呢?首先赌侠stat_smooth()的文档,看看它内部用的是什么模型:对于大数据用的是gam(y ~ s(x,bs = “cs”))。为了得到与stat_smooth同样的结果,先拟合这个模型,然后在一系列等距的点上求模型的预测值。

library(mgcv)
smooth <- function(df){
  mod  <- gam(price ~ s(carat, bs = "cs"), data = df)
  grid <- data.frame(carat = seq(0.2,2,length=50))
  pred <- predict(mod,grid,se=T)
  grid$price <- pred$fit
  grid$se    <- pred$se.fit
  grid
}
smoothes <- ddply(dense,.(color),smooth)
qplot(carat,price,data = smoothes,colour = color,geom = "line")
qplot(carat,price,data = smoothes,colour = color,geom = "smooth",
      ymax = price+2*se,ymin=price-2*se)

在这里插入图片描述如果分组变量也被纳入了平滑模型的话,那么用plyr完成这个过程可以更灵活些。

mod <- gam(price ~ s(carat, bs = "cs") + color, data = dense)
grid <- with(diamonds,expand.grid(
  carat = seq(0.2, 2, length = 50),
  color = levels(color)
))
grid$pred <- predict(mod,grid)
qplot(carat, pred, data = grid, colour = color, geom = "line")

在这里插入图片描述

把数据的“宽”变为“长”

ggplot2进行数据分组时必须根据行,而不能根据列。例如可以把钻石根据颜色分组,却不能把钻石的克拉数和价格变量分成两组。
本节将会用到reshape2包的melt()函数和cast()函数。
melt()函数有三个参数:

  • data: 待变形的数据。
  • id.vars:依旧放在列上、位置保持不变的变量。即数据表的主键。
  • measure.vars:需要被放进同一列的变量。不同的变量放在同一列后,根据原变量名来分组。

多重时间序列

时间序列值存在value变量里,然后用vairable变量来区分。

ggplot(economics,aes(date))+
  geom_line(aes(y=unemploy,colour = "unemploy")) +
  geom_line(aes(y=uempmed,colour = "uempemed")) +
  scale_colour_hue("variable")

require(reshape2)
emp <- melt(economics,id="date",measure = c("unemploy","uempmed"))
qplot(date,value,data = emp,geom="line",colour = variable)

在这里插入图片描述有一个问题:两个变量取值差异太大。ggplot2不允许画带两个不同坐标轴的图,它认为这样的图具有误导性,并给出两个比较直观的改进方法:把数据标度调整到相同的范围(比如:归一化)或使用自由标度的分面。

range01 <- function(x){
  rng <- range(x,na.rm = T)
  (x - rng[1]) / diff(rng)
}
# 将数据框,根据variable分类,对value做归一化变形
emp2 <- ddply(emp, .(variable),transform,value = range01(value))
qplot(date,value,data = emp2,geom = "line",colour = variable,linetype = variable)

在这里插入图片描述

qplot(date,value,data = emp,geom = "line") +
  facet_grid(variable ~ .,scales="free_y")

在这里插入图片描述

平行坐标图

即,把原数据化为“长”数据,然后画出平行坐标图。就是以variable变量为x轴表示变量名,以value为y轴表示变量取值。此外,还需要一个分组变量来把各个观测分组。

#取经济数据子集
emp3 <- subset(economics,date>as.Date("1967-08-3"))
#去掉不需要的时间标签
emp3 <- emp3[,-1]
#用ggplot2中的rownames函数为每行加数字标签
emp3$.row <- rownames(emp3)
#对子集中的变量做归一化
emp3$pce <- range01(emp3$pce)
emp3$pop <- range01(emp3$pop)
emp3$psavert <- range01(emp3$psavert)
emp3$unemploy <- range01(emp3$unemploy)
emp3$uempmed <- range01(emp3$uempmed)
#按照rownames为主键融合
molten <- melt(emp3,id=".row")
ggplot(molten,aes(variable,value,group=.row))+geom_line()

在这里插入图片描述

透明化

ggplot(molten,aes(variable,value,group=.row))+geom_line(colour="black",alpha=1/20)

在这里插入图片描述
增加扰动

ggplot(molten,aes(variable,value,group=.row))+
geom_line(position = 
position_jitter(width = 0.25,height = 2.5))

在这里插入图片描述透明+扰动

ggplot(molten,aes(variable,value,group=.row))+
geom_line(colour="black",alpha=1/20,
position = "jitter")

在这里插入图片描述
为了更清楚地观察数据的规律,我们进行聚类,数值相近的分到一类。使用kmeans聚类把所有数值分成6类。

cl <- kmeans(emp3[1:5],6)
#把cl中的cluster按照pce的大小重新整理,并放入emp3中
emp3$cluster <- reorder(factor(cl$cluster),emp3$pce)
#对emp3中的cluster顺序排序
levels(emp3$cluster) <- seq_along(levels(emp3$cluster))
molten <- melt(emp3,id=c(".row","cluster"))
#聚类后所有数据
pcp_cl <- ggplot(molten,aes(variable,value,group=.row,colour = cluster))
pcp_cl + geom_line(position = "jitter",alpha=1/2)

在这里插入图片描述
聚类后,每类的均值

pcp_cl + stat_summary(aes(group = cluster),fun.y = mean,geom = "line")

在这里插入图片描述
分面查看每个聚类组内差异不明显,表明聚类效果很好。

pcp_cl + geom_line(position = "jitter",colour = "black",alpha=1/2)+facet_wrap( ~ cluster)

在这里插入图片描述

ggplot()方法

线性模型

fortify方法
fortify()把由模型产生的新变量极大原数据集中。为了避免与数据集中的变量名冲突,我们在变量名的前面都加了“.”

变量描述
.cooksdCook距离
.fitted拟合值
.hat帽子矩阵的对角线取值
.resid残差
.sigma当相应的观测从模型中被剔除后残差标准差的估计值
.stdresid标准化残差

一个简单的模型

qplot(displ,cty,data = mpg) + geom_smooth(method = "lm")

在这里插入图片描述
用标准化残差代替未标准化残差,让点的大小代表Cook距离。

mod <- lm(cty ~ displ,data = mpg)
p1<-basic <- ggplot(mod,aes(.fitted,.resid))+
  geom_hline(yintercept = 0,colour = "grey50",size=0.5)+
  geom_point()+
  geom_smooth(size=0.5,se=F)
p2<-basic + aes(y = .stdresid)
p3<-basic + aes(size = .cooksd) + scale_size_area("Cook's distance")

在这里插入图片描述(左)基本拟合值-残差图。(中)标准化残差。(右)点大小与Cook距离成比例。

还可以继续增补数据集,把原数据中没有被放入回归模型的变量也添加到图中。这样有助于发现哪些变量有助于改进模型。

full <- basic %+% fortify(mod,mpg)
full + aes(colour = factor(cyl))
full + aes(displ,colour = factor(cyl))

在这里插入图片描述增加了气缸数量变量cyl后,可以看到只要给定了cyl,displ与cty之间其实是呈线性关系的。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Q_M_Y_Y

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值