ggplot2-数据变换3

有用的工具

summarise()有时需要和别的函数一起协作,这类函数可以对n个值的向量进行计算并返回一个单值,比如:

  • 计数 n() n_distinct(x)
  • 中间值 mean(x) median(x)
  • 离散程度 sd(x) mad(x) IQR(x)
  • 极端值 quartile(x) min(x) max(x)
  • 位置 first(x) last(x) nth(x, 2)

另外一个十分有用的方法是对逻辑向量使用sum()或mean()。当逻辑向量作为数值处理时,TRUE计为1,FALSE计为0,所以sum()表示TRUE的数量而mean()则可表示TRUE的比例。比如下面的代码就计算了克拉数大于等于4的钻石个数和$1000以下钻石所占的比例

summarise(diamonds, 
	n_big = sum(carat >= 4),
	prop_cheap = mean(price < 1000))

大多数汇总函数都包含na.rm的参数,na.rm = TRUE意味着在汇总前删去缺失值。这是个很好用的缺失值,不必再手动删除缺失值再汇总,而可以一步到位

统计上的考虑

当利用均值或中位数进行汇总时,顺手记一下数并衡量一下离散程度,往往可以帮助做出结论——如果不计算它们,可能会低估数据的波动性,从而有可能得出极不可靠的结论

下面对刚才的分净度平均价格的汇总做一个补充:增加每组的计数和上下四分位点。这显示出均值对这个数据的汇总效果并不好——价格的分布时严重偏态的:在某些组内,均值甚至比上四分位点还高!

by_clarity <- diamonds %>%
	group_by(clarity) %>%
	summarise(
		n = n(), mean = mean(price),
		lq = quantile(price, 0.25, uq = quantile(price, 0.75)))

by_clarity
ggplot(by_clarity, aes(clarity, mean)) +
	geom_linerange(aes(ymin = lq, ymax = uq)) +
	geom_line(aes(group = 1), color = "grey50") +
	geom_point(aes(size = n))

下面的例子来自棒球比赛。计算一下安打率:安打(击球上垒)的次数除以在棒数。在这个标准下,谁是最好的击球手?

data(Batting, package = "Lahman")
batters <- filter(Batting, AB > 0)
per_player <- group_by(batters, palyerID)
ba <- summarise(per_player,
	ba = sum(H, na.rm = TRUE) / sum(AB, na.rm = TRUE))
ggplot(ba, aes(ba)) +
	geom_histogram(binwidth = 0.01)

有些球员几乎次次命中!通过计算一下在棒数,再仔细确认一遍他们是否真的那么好

ba <- summarise(per_player,
	ba = sum(H, na.rm = TRUE)/ sum(AB, na.rm = TRUE),
	ab = sum(AB, na.rm = TRUE))
ggplot(ba, aes(ab, ba)) +
	geom_bin2d(bins = 100) +
	geom_smooth()

安打率最高的球员就是那些在棒最少的球员——如果仅有一两次击球机会,每次都命中当然不难。如果去掉那些在棒补足10次的球员,可以看到更清晰的规律

ggplot(filter(ba, ab >= 10), aes(ab, ba)) +
	geom_bin2d() + geom_smooth()

当比较观测数对平均值的图时,总是会发现类似的情况。所以一定要谨慎

管道操作

多数实际操作中,需要用一连串的mutate()、filter()、group_by()和summarise()。比如之前就组合了全部四个函数手动创造了频率多边形

# 通过中介变量
cut_depth <- group_by(diamonds, cut, depth)
cut_depth <- summarise(cut_depth, n = n())
cut_depth <- filter(cut_depth, depth > 55, depth < 70)
cut_depth <- mutate(cut_depth, prop = n / sum(n))

这一系列操作略显繁琐,因为需要多次重复数据框的名称,一个代替方法是用函数调用序列来完成它

# 通过“组合”函数
mutate(filter(summarise(group_by(diamonds, cut, depth),
	n = n()), depth > 55, depth < 70), prop = n / sum(n)))

但是这个方法会增加代码阅读的难度,因为操作顺序是由内而外的,且各个函数的参数设置可能相去甚远。dplyr提供了另一种替代方案:利用管道函数%>%。通过这种方法,可以将上述一系列操作写为:

cut_depth <- diamonds %>%
	group_by(cut, depth) %>%
	summarise(n = n()) %>%
	filter(depth > 55, depth < 70) %>%
	mutate(prop = n / sum(n))

现在要理解做了什么事就很容易了,就和对一个句子一样:首先分组,再汇总,然后筛选,最后建立新的变量。事实上,读代码序列时,%>%符号最好的读法就是“然后”。%>% 来时Stefan Milton Bache的magrittr包,它还提供了许多dplyr默认情况下不显示的其它工具,所以强烈推荐参阅magrittr的官方网站
%>%的运作原理是将其左边(left hand side, LHS)的内容作为其右边(right hand side, RHS)函数的第一个参数。以下的表达是等价的:

f(x, y)
# 等价于
x %>% f(x)

g(f(x, y), z)
# 等价于
x %>% f(y) %>% g(z)

了解更多

dplyr包提供了很多其它函数,它们虽然再可视化中不如之前几个常用,但也十分重要

  • arrange() 函数可以将观测依据某(些)变量排序。当从控制台(console)看数据时,这个函数是最有用的。在绘图时,它还可以帮助控制哪些带你绘制在最上面
  • select()函数可以基于变量名选择变量,当希望从大量变量中只选取几个作分析时尤其有用
  • rename()函数可以更改变量名
  • 分组建立变量和分组筛选也是有用的,并且更为高级。详情见vignette(“window-functions”, package = “dplyr”)
  • 还有一些用于同时处理两套数据的函数。它们包含了SQL接口(如R自导的mergge()函数)和集合操作。详情见vignette(“two-table”, package = “dplyr”)
  • dplyr可以直接对数据库中的数据进行操作——用和本地操作时一样的R代码,然后dplyr能处理成SQL语言并发送至数据库。详情见vignette(“databases”, package = “dplyr”)
    最后RStudio还提供了一个便捷的dplyr备忘录
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值