R数据科学|3.7内容介绍及习题解答
3.7 分组新变量(和筛选器)
虽然与summarize()
函数结合起来使用是最有效的,但分组也可以与mutate()
和filter()
函数结合,以完成非常便捷的操作。示例如下:
找出每个分组中最差的成员:
flights_sml %>%
group_by(year, month, day) %>%
filter(rank(desc(arr_delay)) < 10)
#> Source: local data frame [3,306 x 7]
#> Groups: year, month, day [365]
#>
#> year month day dep_delay arr_delay distance
#> <int> <int> <int> <dbl> <dbl> <dbl>
#> 1 2013 1 1 853 851 184
#> 2 2013 1 1 290 338 1134
#> 3 2013 1 1 260 263 266
#> 4 2013 1 1 157 174 213
#> 5 2013 1 1 216 222 708
#> 6 2013 1 1 255 250 589
#> # ... with 3,300 more rows, and 1 more variables:
#> # air_time <dbl>
找出大于某个阈值的所有分组:
popular_dests <- flights %>%
group_by(dest) %>%
filter(n() > 365)
popular_dests
#> Source: local data frame [332,577 x 19]
#> Groups: dest [77]
#>
#> year month day dep_time sched_dep_time dep_delay
#> <int> <int> <int> <int> <int> <dbl>
#> 1 2013 1 1 517 515 2
#> 2 2013 1 1 533 529 4
#> 3 2013 1 1 542 540 2
#> 4 2013 1 1 544 545 -1
#> 5 2013 1 1 554 600 -6
#> 6 2013 1 1 554 558 -4
#> # ... with 3.326e+05 more rows, and 13 more variables:
#> # arr_time <int>, sched_arr_time <int>,
#> # arr_delay <dbl>, carrier <chr>, flight <int>,
#> # tailnum <chr>, origin <chr>, dest <chr>,
#> # air_time <dbl>, distance <dbl>, hour <dbl>,
#> # minute <dbl>, time_hour <dttm>
对数据进行标准化以计算分组指标:
popular_dests %>%
filter(arr_delay > 0) %>%
mutate(prop_delay = arr_delay / sum(arr_delay)) %>%
select(year:day, dest, arr_delay, prop_delay)
#> Source: local data frame [131,106 x 6]
#> Groups: dest [77]
#>
#> year month day dest arr_delay prop_delay
#> <int> <int> <int> <chr> <dbl> <dbl>
#> 1 2013 1 1 IAH 11 1.11e-04
#> 2 2013 1 1 IAH 20 2.01e-04
#> 3 2013 1 1 MIA 33 2.35e-04
#> 4 2013 1 1 ORD 12 4.24e-05
#> 5 2013 1 1 FLL 19 9.38e-05
#> 6 2013 1 1 ORD 8 2.83e-05
#> # ... with 1.311e+05 more rows
【注】:分组筛选器的作用相当于分组新变量加上未分组筛选器。一般不使用分组筛选器,除非是为了完成快速、粗略的数据处理,否则很难检查数据处理的结果是否正确。
在分组新变量和筛选器中最常使用的函数称为窗口函数(与用于统计的摘要函数相对)。你可以在相应的使用指南中学习到更多关于窗口函数的知识:vignette("windowfunctions")
。
习题解答
问题一
查看常用的新变量函数和筛选函数的列表。当它们与分组操作结合使用时,功能有哪些变化?
解答
受影响的有:
mean(), lead(), lag(), min_rank(), row_number(), mean(), sum(), sd()
tibble(x = 1:9,
group = rep(c("a", "b", "c"), each = 3)) %>%
mutate(x_mean = mean(x)) %>%
group_by(group) %>%
mutate(x_mean_2 = mean(x))
#> # A tibble: 9 x 4
#> # Groups: group [3]
#> x group x_mean x_mean_2
#> <int> <chr> <dbl> <dbl>
#> 1 1 a 5 2
#> 2 2 a 5 2
#> 3 3 a 5 2
#> 4 4 b 5 5
#> 5 5 b 5 5
#> 6 6 b 5 5
#> # … with 3 more rows
不受影响的有:
运算符(+,-,<,==,%%,%/%)
tibble(x = 1:9,
group = rep(c("a", "b", "c"), each = 3)) %>%
mutate(y = x + 2) %>%
group_by(group) %>%
mutate(z = x + 2)
#> # A tibble: 9 x 4
#> # Groups: group [3]
#> x group y z
#> <int> <chr> <dbl> <dbl>
#> 1 1 a 3 3
#> 2 2 a 4 4
#> 3 3 a 5 5
#> 4 4 b 6 6
#> 5 5 b 7 7
#> 6 6 b 8 8
#> # … with 3 more rows
问题二
哪一架飞机(用机尾编号来识别,tailnum)具有最差的准点记录?
解答
我筛选至少飞行了20次的飞机。选择20是因为它是接近飞机飞行次数的上四分位数。
quantile(count(flights, tailnum)$n)
#> 0% 25% 50% 75% 100%
#> 1 23 54 110 2512
将平均延误时间作为衡量标准。
flights %>%
filter(!is.na(arr_delay)) %>%
group_by(tailnum) %>%
summarise(arr_delay = mean(arr_delay), n = n()) %>%
filter(n >= 20) %>%
filter(min_rank(desc(arr_delay)) == 1)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 1 x 3
#> tailnum arr_delay n
#> <chr> <dbl> <int>
#> 1 N203FR 59.1 41
问题三
如果想要尽量避免航班延误,那么应该在一天中的哪个时间搭乘飞机?
解答
可以按飞行时间分组,航班预定的时间越早,预计延误的时间就越低,因为延误会影响之后的航班。比如,早上的航班不容易受延误影响,是因为它们之前的航班较少。
flights %>%
group_by(hour) %>%
summarise(arr_delay = mean(arr_delay, na.rm = TRUE)) %>%
arrange(arr_delay)
#> `summarise()` ungrouping output (override with `.groups` argument)
#> # A tibble: 20 x 2
#> hour arr_delay
#> <dbl> <dbl>
#> 1 7 -5.30
#> 2 5 -4.80
#> 3 6 -3.38
#> 4 9 -1.45
#> 5 8 -1.11
#> 6 10 0.954
#> # … with 14 more rows
问题四
计算每个目的地的延误总时间的分钟数,以及每架航班到每个目的地的延误时间比例。
解答
#每个目的地的延误总时间的分钟数
flights %>%
filter(arr_delay > 0) %>%
group_by(dest) %>%
mutate(
arr_delay_total = sum(arr_delay),
arr_delay_prop = arr_delay / arr_delay_total
) %>%
select(dest, month, day, dep_time, carrier, flight,
arr_delay, arr_delay_prop) %>%
arrange(dest, desc(arr_delay_prop))
#每架航班到每个目的地的延误时间比例
flights %>%
filter(arr_delay > 0) %>%
group_by(dest, origin, carrier, flight) %>%
summarise(arr_delay = sum(arr_delay)) %>%
group_by(dest) %>%
mutate(
arr_delay_prop = arr_delay / sum(arr_delay)
) %>%
arrange(dest, desc(arr_delay_prop)) %>%
select(carrier, flight, origin, dest, arr_delay_prop)
问题五
延误通常是由临时原因造成的:即使最初引起延误的问题已经解决,但因为要让前面的航班先起飞,所以后面的航班也会延误。使用 lag() 函数探究一架航班延误与前一架航班延误之间的关系。
解答
#计算同一机场前一航班的起飞延误。
lagged_delays <- flights %>%
arrange(origin, month, day, dep_time) %>%
group_by(origin) %>%
mutate(dep_delay_lag = lag(dep_delay)) %>%
filter(!is.na(dep_delay), !is.na(dep_delay_lag))
下面绘制了前一航班所有值与平均延误之间的关系。对于延误小于两小时的航班,前一航班的延误与当前航班的延误关系接近一条直线。在这之后,这种关系变得更加多变,因为长时间延误的航班与准时起飞的航班穿插在一起。大约8个小时后,一个航班延误之后可能会有一个航班准时起飞。
lagged_delays %>%
group_by(dep_delay_lag) %>%
summarise(dep_delay_mean = mean(dep_delay)) %>%
ggplot(aes(y = dep_delay_mean, x = dep_delay_lag)) +
geom_point() +
scale_x_continuous(breaks = seq(0, 1500, by = 120)) +
labs(y = "Departure Delay", x = "Previous Departure Delay")
问题六
查看每个目的地。你能否发现有些航班的速度快得可疑?(也就是说,这些航班的数据可能是错误的。)计算出到目的地的最短航线的飞行时间。哪架航班在空中的延误时间最长?
解答
先对数据进行标准化处理
standardized_flights <- flights %>%
filter(!is.na(air_time)) %>%
group_by(dest, origin) %>%
mutate(
air_time_mean = mean(air_time),
air_time_sd = sd(air_time),
n = n()
) %>%
ungroup() %>%
#加1是为了避免分母为0
mutate(air_time_standard = (air_time - air_time_mean) / (air_time_sd + 1))
查看标准化后的航班分布
standardized_flights %>%
arrange(air_time_standard) %>%
select(
carrier, flight, origin, dest, month, day,
air_time, air_time_mean, air_time_standard
) %>%
head(10) %>%
print(width = Inf)
计算出到目的地的最短航线的飞行时间
flights %>%
mutate(mph = distance / (air_time / 60)) %>%
arrange(desc(mph)) %>%
select(
origin, dest, mph, year, month, day, dep_time, flight, carrier,
dep_delay, arr_delay
)
寻找在空中的延误时间最长的航班
air_time_delayed <-
flights %>%
group_by(origin, dest) %>%
mutate(
air_time_min = min(air_time, na.rm = TRUE),
air_time_delay = air_time - air_time_min,
air_time_delay_pct = air_time_delay / air_time_min * 100
)
arrange(desc(air_time_delay)) %>%
select(
air_time_delay, carrier, flight,
origin, dest, year, month, day, dep_time,
air_time, air_time_min
) %>%
head() %>%
print(width = Inf)
问题七
找出至少有两个航空公司的所有目的地。使用数据集中的信息对航空公司进行排名。
解答
计算这个排名有两个步骤。首先,找出有两家或两家以上航空公司服务的所有机场。然后,根据运营商服务的目的地数量对它们进行排名。
flights %>%
# 找出有两家或两家以上航空公司服务的所有机场
group_by(dest) %>%
mutate(n_carriers = n_distinct(carrier)) %>%
filter(n_carriers > 1) %>%
# 根据运营商服务的目的地数量对它们进行排名
group_by(carrier) %>%
summarize(n_dest = n_distinct(dest)) %>%
arrange(desc(n_dest))
推荐阅读
往期推荐