《R for Data Science》
常用的摘要函数
和summarize()
搭配使用
位置度量
# 前面用过mean() 求均值
# median() 求中位数
# 即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]), # 平均正延误时间
avg_delay3=median(arr_delay[arr_delay>0]) # # 正延误时间中位数
)
# 有时候需要将聚合函数和逻辑筛选组合起来 (后面再讲)
分散程度度量
# 均方误差(又称标准误差,standard deviation,sd),衡量数据离散程度
# 四分位距IDR()和绝对中位差mad()基本等价,更适合有离群点的情况
# 为什么到某些目的地的距离比到其他目的地更多变?
not_cancelled %>%
group_by(dest) %>% # 按目的地分组
summarise(distance_sd=sd(distance)) %>%
arrange(desc(distance_sd))
秩的度量
# 分位数是中位数的扩展
# 例如,quantile(x,0.25)会找出x中按从小到大顺序位于25%位置的数字
x<-c(1:10)
quantile(x,0.25) # 25% 3.25
quantile(x,0.75) # 75% 7.75
# 最小值 min()
# 最大值 max()
# 每天最早和最晚的航班何时出发
not_cancelled %>%
group_by(year,month,day) %>%
summarize(
first = min(dep_time),
last = max(dep_time)
)
定位度量
# 取第一个first(x),作用等同于 x[1]
# 取第二个nth(x,2),作用等同于 x[2] ## 当然也可以是任意数字/位置
# 取最后一个last(x),作用等同于 x[length(x)]
# 它们的优势是当定位不存在时
# 例如,从只有两个元素的分组中得到第三个元素
# 它们允许你设置一个默认值
# 找出每日最早、最晚出发的航班
not_cancelled %>%
group_by(year,month,day) %>%
summarise(
first_dep=first(dep_time),
last_dep=last(dep_time)
)
# 这些函数对筛选操作进行了排秩方面的补充
# 筛选会返回所有变量,每个观测在单独一行中
not_cancelled %>%
group_by(year,month,day) %>%
mutate(r=min_rank(desc(dep_time))) %>%
filter(r %in% range(r))
计数
# n() 不需要任何函数,并返回当前分组的大小
# 如果想要计算出非缺失值的数量,可用sum(!is.na(x))
# 想要计算出唯一值的数量,可以使用n_distinct(x)
# 哪个目的地具有最多的航空公司
not_cancelled %>%
group_by(dest) %>%
summarise(
carriers = n_distinct(carrier)
) %>%
arrange(desc(carriers))
# 除了n()之外,还有count()用于单纯计数
# count()用于统计一个或多个变量的唯一值
not_cancelled %>%
count(dest)
## df %>% count(a, b)
## 大致等同于
## df %>% group_by(a, b) %>% summarise(n = n())
# 还可以搭配一个加权变量
# count()提供 参数wt 来执行加权计数,将摘要从 n = n() 转换为 n = sum(wt)
# 例如计算出每架飞机飞行的总里程数(即求和)
not_cancelled %>%
count(tailnum,wt=distance) # 多了一列 n,即总和
## add_count 等同于 count()
## add_tally 等同于 tally()
## 但搭配 mutate() 而不是 summarise(),因此它们会添加一列新的分组计数
逻辑值的计数和比例
# 当和数值型函数一同使用时,TRUE会转换为1,FALSE会转换为0
# 那么就可以利用逻辑值进行计数
# sum(x) 可以计算出x中TRUE的数量
# mean(x) 可以得出x中TRUE的比例
# 例如
x<-1:20
sum(x>10) # 10
mean(x>10) # 0.5
# 多少架航班是在早上5点前出发的?
not_cancelled %>%
group_by(year,month,day) %>%
summarise(
n_early = sum(dep_time<500)
)
# 延误超过1h的航班比例是多少?
not_cancelled %>%
group_by(year,month,day) %>%
summarise(hour_perc=mean(arr_delay>60))
按多个变量分组
# 当使用多个变量进行分组时,每次的摘要统计会用掉一个分组变量
# 这样就可以轻松地对数据集进行循序渐进的分析
daily <- group_by(flights,year,month,day)
per_day <- summarise(daily,flights=n())
per_month <- summarise(per_day,flights=sum(flights))
per_year <- summarise(per_month,flights=sum(flights))
# 在循序渐进地进行摘要分析时,要注意:
# 使用求和和计数操作是没问题的
# 但是加权平均和方差操作容易出问题
# 因为对分组求和的结果再求和 == 对整体求和
# 但是分组中位数的中位数可不是整体的中位数
取消分组
# ungroup()函数取消分组
# 回到未分组的数据继续操作
daily %>%
ungroup() %>% # 不再按日期分组
summarise(flights=n()) # 所有航班数
练习题
# 1. 至少找出5种方法来确定一组航班的典型延误特征,思考以下场景;
# - 一架航班50%的时间会提前15分钟,50%的时间会延误15分钟
# - 一架航班总是会延误10分钟
# - 一架航班50%的时间会提前30分钟,50%的时间会延误30分钟
# - 一架航班99%的时间会准时,1%的时间会延误2小时
# 哪一种更重要,出发延误还是到达延误
# 找出另一种方法,要可以给出与not_cancelled %>% count(dest) 和 not_cancelled %>% count(tailnum,wt=distance)同样的输出
not_cancelled %>% count(dest) # 标准一
not_cancelled %>% # 仿写一
group_by(dest) %>%
summarise(n=n())
not_cancelled %>% count(tailnum,wt=distance) # 标准二
not_cancelled %>% # 仿写二
group_by(tailnum) %>%
summarise(
n=sum(distance))
# 对已取消航班的定义 (is.na(dep_delay))|(is.na(arr_delay)) 是否稍有欠佳?为什么?哪一列更重要?
not_cancelled <- flights %>% # 原定义式,327346行
filter(!is.na(dep_delay),!is.na(arr_delay))
no_airtime <- flights %>% # 如果用air_time来筛选,也是327346行
filter(!is.na(air_time))
# 从逻辑上可知没有出发就不会有到达,即dep_delay为NA则arr_delay一定为NA
# 如果有出发而没有抵达,说明飞机中途折返或者坠机
# 所以对于“取消航班”这个定义来说,是否出发更为重要
# 查看每天取消的航班数量,其中存在某种模式吗?已取消航班的比例与平均延误时间是否存在关系?
## 计数每天的航班数、取消的航班数和总延误时间
cancelled_perday <- flights %>%
group_by(year,month,day) %>%
summarise(
cancelled_count=sum(is.na(air_time)),
all_count=n(),
delay = arr_delay - dep_delay) %>%
filter(delay>0)
ggplot(cancelled_perday,aes(all_count,cancelled_count))+
geom_point()
## 查看取消航班比例和平均延误时间
percent_averagedelay <- cancelled_perday %>%
summarise(
cancelled_percent = cancelled_count/all_count,
average_delay=mean(delay,na.rm=T)
)
ggplot(percent_averagedelay,aes(average_delay,cancelled_percent))+
geom_smooth()+
geom_point()
# 哪个航空公司的延误情况最严重?
carriers_delay <- flights %>%
group_by(carrier) %>%
summarise(
n=n(), # 计算每个航空公司的总航班
delay=sum(arr_time-dep_time,na.rm = T), # 计算每个航空公司的总延误时间
average_delay=delay/n # 计算每个航空公司每一趟的平均延误时间
) %>%
arrange(desc(average_delay))
carriers_delay1 <- flights %>% # 更简洁
group_by(carrier) %>%
summarise(
average_delay=mean(arr_time-dep_time,na.rm = T) # 计算每个航空公司每一趟的平均延误时间
) %>%
arrange(desc(average_delay))
# 能否分清这是由于糟糕的机场设备,还是航空公司的问题?
flights %>%
filter(!is.na(arr_delay)) %>%
group_by(origin, dest, carrier) %>% # 按每一条航线分类后,再分每一个航空公司
summarise(
arr_delay = sum(arr_delay), # 计算每个航线内每个航空公司的总延误时间
flights = n() # 计算每个航线内每个航空公司的飞行次数
) %>%
group_by(origin, dest) %>% # 计算每个航线内
mutate(
arr_delay_total = sum(arr_delay), # 所有航班的总延误时间
flights_total = sum(flights) # 所有航班数
) %>%
ungroup() %>%
mutate( # 解除分组
arr_delay_others = (arr_delay_total - arr_delay) / # 所有航班的总延误时间-每个航线内每个航空公司的总延误时间
(flights_total - flights), # 所有航班数-每个航线内每个航空公司的飞行次数
arr_delay_mean = arr_delay / flights, # 每个航线内每个航空公司的平均延误时间
arr_delay_diff = arr_delay_mean - arr_delay_others # 每个航线内每个航空公司的平均延误时间-该航线内其他航班的平均延误时间
) %>%
filter(is.finite(arr_delay_diff)) %>%
group_by(carrier) %>%
summarise(arr_delay_diff = mean(arr_delay_diff)) %>% # 再按航空公司汇总,求得每个航空公司的每条线路平均延误时间
arrange(desc(arr_delay_diff))
分组新变量和筛选器
# 虽然group_by()与summarize()结合非常常用
# group_by()和mutate()、filter()也可以结合使用
# 找出每个分组中最多延误的
flights_sml %>%
group_by(year,month,day) %>%
filter(rank(desc(arr_delay))<10)
# 找出大于某个阈值的所有分组
popular_dest <- flights %>%
group_by(dest) %>%
filter(n()>365)
# 对数据进行标准化以计算分组指标
popular_dest %>%
filter(arr_delay>0) %>%
mutate(prop_delay = arr_delay/sum(arr_delay)) %>%
select(year:day,dest,arr_delay,prop_delay)
## 分组筛选器的作用相当于分组新变量加上未分组筛选器
## 这个用法适合快速、粗略处理数据,缺点是很难检查数据处理结果是否正确
练习题
# 哪一架飞机具有最差的准点记录
worse_flight <- flights %>%
group_by(tailnum) %>%
summarise(
average_delay = abs(mean(arr_delay))
) %>%
arrange(desc(average_delay))
# 如果想避免航班延误,应该一天内哪个时间搭乘飞机
time_flight <- flights %>%
filter(arr_delay >0) %>%
group_by(hour) %>%
summarise(
average_delay = mean(arr_delay,na.sm=T)
) %>%
arrange(average_delay)