在R for Data Science(四)中我们学到了第三章,有以下知识点
复习了以上知识点,虽然也没法一次都记住,起码将来需要用到的时候知道在哪里找。下面我们继续
最后一个核心函数是 summarize(),它可以将数据框折叠成一行
summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
#> # A tibble: 1 × 1
#> delay
#> <dbl>
#> 1 12.6
如果不与 group_by() 一起使用,那么 summarize() 也就没什么大用。group_by() 可以将分析单位从整个数据集更改为单个分组。接下来,在分组后的数据框上使用 dplyr 函数时,它们会自动地应用到每个分组。例如,如果对按日期分组的一个数据框应用与上面完全相同的代码,那么我们就可以得到每日平均延误时间
by_day <- group_by(flights, year, month, day)
summarize(by_day, delay = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day delay
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.55
#> 2 2013 1 2 13.86
#> 3 2013 1 3 10.99
#> 4 2013 1 4 8.95
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
group_by()和summarize() 的组合构成了使用 dplyr 包时最常用的操作之一
%>%叫做管道符,在阅读代码时, %>%最好读作“然后”。
使用这种方法时, x %>% f(y) 会转换为 f(x, y), x %>% f(y) %>% g(z) 会转换为 g(f(x,y), z),以此类推。你可以使用管道重写多种操作,将其变为能够从左到右或从上到下阅读。
我们在前面使用了参数 na.rm,你应该非常想要知道其含义。如果没有设置这个参数,会发生什么情况呢?
flights %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 NA
#> 2 2013 1 2 NA
#> 3 2013 1 3 NA
#> 4 2013 1 4 NA
#> 5 2013 1 5 NA
#> 6 2013 1 6 NA
#> # ... with 359 more rows
我们会得到很多缺失值!这是因为聚合函数遵循缺失值的一般规则:如果输入中有缺失值,那么输出也会是缺失值。好在所有聚合函数都有一个 na.rm 参数,它可以在计算前除去缺失值:
flights %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay, na.rm = TRUE))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.55
#> 2 2013 1 2 13.86
#> 3 2013 1 3 10.99
#> 4 2013 1 4 8.95
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
在这个示例中,缺失值表示取消的航班,我们也可以通过先去除取消的航班来解决缺失值问题。保存这个数据集,以便我们可以在接下来的几个示例中继续使用
not_cancelled <- flights %>%
filter(!is.na(dep_delay), !is.na(arr_delay))
not_cancelled %>%
group_by(year, month, day) %>%
summarize(mean = mean(dep_delay))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day mean
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 11.44
#> 2 2013 1 2 13.68
#> 3 2013 1 3 10.91
#> 4 2013 1 4 8.97
#> 5 2013 1 5 5.73
#> 6 2013 1 6 7.15
#> # ... with 359 more rows
聚合操作中包括一个计数(n())或非缺失值的计数(sum(!is_na()))是个好主意。这样你就可以检查一下,以确保自己没有基于非常少量的数据作出结论。例如,我们查看一下具有最长平均延误时间的飞机(通过机尾编号进行识别):
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarize(
delay = mean(arr_delay)
)
ggplot(data = delays, mapping = aes(x = delay)) +
geom_freqpoly(binwidth = 10)
有些飞机的平均延误时间长达 5 小时
我们可以画一张航班数量和平均延误时间的散点图,以便获得更深刻的理解:
delays <- not_cancelled %>%
group_by(tailnum) %>%
summarize(
delay = mean(arr_delay, na.rm = TRUE),
n = n()
)
ggplot(data = delays, mapping = aes(x = n, y = delay)) +
geom_point(alpha = 1/10)
结果并不出乎意料,当航班数量非常少时,平均延误时间的变动特别大。
查看此类图形时,通常应该筛选掉那些观测数量非常少的分组,这样你就可以避免受到特别小的分组中的极端变动的影响,进而更好地发现数据模式
只使用均值、计数和求和是远远不够的, R 中还提供了很多其他的常用的摘要函数
位置度量
我们已经使用过 mean(x),但 median(x) 也非常有用。均值是总数除以个数;中位数则是这样一个值:50% 的 x 大于它,同时 50% 的 x 小于它
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
# 平均延误时间:
avg_delay1 = mean(arr_delay),
# 平均正延误时间:
avg_delay2 = mean(arr_delay[arr_delay > 0])
)
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#>
#> year month day avg_delay1 avg_delay2
#> <int> <int> <int> <dbl> <dbl>
#> 1 2013 1 1 12.65 32.5
#> 2 2013 1 2 12.69 32.0
#> 3 2013 1 3 5.73 27.7
#> 4 2013 1 4 -1.93 28.3
#> 5 2013 1 5 -1.53 22.6
#> 6 2013 1 6 4.24 24.4
#> # ... with 359 more rows
分散程度度量:sd(x)、 IQR(x) 和 mad(x)
均方误差(又称标准误差, standard deviation, sd)是分散程度的标准度量方式。四分位距 IQR() 和绝对中位差 mad(x) 基本等价,更适合有离群点的情况
秩的度量:min(x)、 quantile(x, 0.25) 和 max(x)
分位数是中位数的扩展。例如, quantile(x, 0.25) 会找出 x 中按从小到大顺序大于前25% 而小于后 75% 的值
每天最早和最晚的航班何时出发?
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
first = min(dep_time),
last = max(dep_time)
)
#> Source: local data frame [365 x 5]
#> Groups: year, month [?]
#>
#> year month day first last
#> <int> <int> <int> <int> <int>
#> 1 2013 1 1 517 2356
#> 2 2013 1 2 42 2354
#> 3 2013 1 3 32 2349
#> 4 2013 1 4 25 2358
#> 5 2013 1 5 14 2357
#> 6 2013 1 6 16 2355
#> # ... with 359 more rows
定位度量:first(x)、 nth(x, 2) 和 last(x)
这几个函数的作用与 x[1]、 x[2] 和 x[length(x)] 相同,只是当定位不存在时(比如尝试从只有两个元素的分组中得到第三个元素),前者允许你设置一个默认值。例如,我们可以找出每天最早和最晚出发的航班
not_cancelled %>%
group_by(year, month, day) %>%
summarize(
first_dep = first(dep_time),
last_dep = last(dep_time)
)
计数
n(),它不需要任何参数,并返回当前分组的大小。如果想要计算出非缺失值的数量,可以使用 sum(!is.na(x))。要想计算出唯一值的数量,可以使用 n_
distinct(x)
哪个目的地具有最多的航空公司?
not_cancelled %>%
group_by(dest) %>%
summarize(carriers = n_distinct(carrier)) %>%
arrange(desc(carriers))
因为计数太常用了,所以 dplyr 提供了一个简单的辅助函数,用于只需要计数的情况
not_cancelled %>%
count(dest)
#> # A tibble: 104 × 2
#> dest n
#> <chr> <int>
#> 1 ABQ 254
#> 2 ACK 264
#> 3 ALB 418
#> 4 ANC 8
#> 5 ATL 16837
#> 6 AUS 2411
#> # ... with 98 more rows
你还可以选择提供一个加权变量。例如,你可以使用以下代码算出每架飞机飞行的总里程数(实际上就是求和):
not_cancelled %>%
count(tailnum, wt = distance)
#> # A tibble: 4,037 × 2
#> tailnum n
#> <chr> <dbl>
#> 1 D942DN 3418
#> 2 N0EGMQ 239143
#> 3 N10156 109664
#> 4 N102UW 25722
#> 5 N103US 24619
#> 6 N104UW 24616
#> # ... with 4,031 more rows
逻辑值的计数和比例:sum(x > 10) 和 mean(y == 0)
当与数值型函数一同使用时, TRUE 会转换为 1, FALSE 会转换为 0。这使得 sum() 和 mean()非常适用于逻辑值:sum(x) 可以找出 x 中 TRUE 的数量, mean(x) 则可以找出比例
多少架航班是在早上5点前出发的?
not_cancelled %>%
group_by(year, month, day) %>%
summarize(n_early = sum(dep_time < 500))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day n_early
#> <int> <int> <int> <int>
#> 1 2013 1 1 0
#> 2 2013 1 2 3
#> 3 2013 1 3 4
#> 4 2013 1 4 3
#> 5 2013 1 5 3
#> 6 2013 1 6 2
#> # ... with 359 more rows
延误超过1小时的航班比例是多少?
not_cancelled %>%
group_by(year, month, day) %>%
summarize(hour_perc = mean(arr_delay > 60))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day hour_perc
#> <int> <int> <int> <dbl>
#> 1 2013 1 1 0.0722
#> 2 2013 1 2 0.0851
#> 3 2013 1 3 0.0567
#> 4 2013 1 4 0.0396
#> 5 2013 1 5 0.0349
#> 6 2013 1 6 0.0470
#> # ... with 359 more rows
使用多个变量进行分组时,每次的摘要统计会用掉一个分组变量。这样就可以轻松地对数据集进行循序渐进的分析:
daily <- group_by(flights, year, month, day)
(per_day <- summarize(daily, flights = n()))
#> Source: local data frame [365 x 4]
#> Groups: year, month [?]
#>
#> year month day flights
#> <int> <int> <int> <int>
#> 1 2013 1 1 842
#> 2 2013 1 2 943
#> 3 2013 1 3 914
#> 4 2013 1 4 915
#> 5 2013 1 5 720
#> 6 2013 1 6 832
#> # ... with 359 more rows
(per_month <- summarize(per_day, flights = sum(flights)))
#> Source: local data frame [12 x 3]
#> Groups: year [?]
#>
#> year month flights
#> <int> <int> <int>
#> 1 2013 1 27004
#> 2 2013 2 24951
#> 3 2013 3 28834
#> 4 2013 4 28330
#> 5 2013 5 28796
#> 6 2013 6 28243
#> # ... with 6 more rows
(per_year <- summarize(per_month, flights = sum(flights)))
#> # A tibble: 1 × 2
#> year flights
#> <int> <int>
#> 1 2013 336776
在循序渐进地进行摘要分析时,需要小心:使用求和与计数操作是没问题的,但如果想要使用加权平均和方差的话,就要仔细考虑一下,在基于秩的统计数据(如中位数)上是无法进行这些操作的。换句话说,对分组求和的结果再求和就是对整体求和,但分组中位数的中位数可不是整体的中位数。
如果想要取消分组,并回到未分组的数据继续操作,那么可以使用ungroup() 函数
daily %>%
ungroup() %>% # 不再按日期分组
summarize(flights = n()) # 所有航班
#> # A tibble: 1 × 1
#> flights
#> <int>
#> 1 336776
好了,这一章我们就学习完了,虽然很枯燥乏味,不过还是很实用的。
下面是福利专用贴链接,有最近收集的资源,可以打开看看有没有想要的
联系客服