查看原文
其他

R数据科学|3.6内容介绍

我才是赵西西 庄闪闪的R语言手册 2023-05-11

上节我们对选择现有的列使用mutate添加新列做了介绍。现在对数据框使用summarize()进行分组摘要进行介绍。函数功能summarize()可以将数据框折叠成一行:

summarize(flights, delay = mean(dep_delay, na.rm = TRUE))
#> # A tibble: 1 × 1
#> delay
#> <dbl>
#> 1 12.6

如果想要将分析单位从整个数据集更改为单个分组,可以使用group_by()group_by()summarize()的组合构成了使用 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

3.6.1 使用管道组合多种操作

管道(%>%) 是一种强大的工具,可以清楚地表示由多个操作组成的一个操作序列。为了说明管道如此有用的原因, 我们将探究同一段代码的不同编写方式。现在我们使用代码来讲述小兔福福的故事:

一只小兔叫福福
蹦蹦跳跳过森林
抓起一窝小田鼠
每只头上打一下
首先,我们定义一个对象来表示小兔福福:foo_foo <- little_bunny()

然后,我们使用函数来表示每个动作:hop()scoop()bop()
于是这首童谣可以如下表示,这种方法的最大缺点是,你必须为每个中间结果建立一个变量,在很多情况下,比如在本例中,这些变量其实是没有什么实际意义的,你还必须使用数字后缀来区分这些变量:

foo_foo_1 <- hop(foo_foo, through = forest)
foo_foo_2 <- scoop(foo_foo_1, up = field_mice)
foo_foo_3 <- bop(foo_foo_2, on = head)

另一种方法是将多个函数组合在一起,这样可以避免赋值语句,这种方法的缺点是,必须按照从内向外和从右向左的顺序阅读代码,而且参数太分散了:

bop(
 scoop(
 hop(foo_foo, through = forest),
 up = field_mice
 ),
 on = head
)

使用管道可以很好解决代码冗杂的问题,它的重点在于动词,而不是名词。在阅读这一串函数组合时,你可以将它们当成一系列规定动作。福福蹦跳着,然后抓田鼠,接着打田鼠:

foo_foo %>%
 hop(through = forest) %>%
 scoop(up = field_mouse) %>%
 bop(on = head)

掌握管道的用法后,可以显著提高代码的可读性,代码的编写也将更加容易。

3.6.2 缺失值

聚合函数遵循缺失值的一般规则:如果输入中有缺失值,那么输出也会是缺失值。好在所有聚合函数都有一个 na.rm参数,只需设置na.rm =TRUE,即可在计算前除去缺失值。

3.6.3 计数

聚合操作中常用的计数操作:

  • n():给出当前分组的个数
  • sum(!is_na()):对非缺失值的计数
  • n_distinct():计算出唯一值的数量
  • count():一个简单的辅助函数,用于只需要计数的情况

3.6.4 常用的摘要函数

  • 位置度量median(x),mean(x)
    均值是总数除以个数;中位数则是这样一个值:50% 的 x 大于它,同时 50% 的 x 小于它。
  • 分散程度度量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% 的值:
  • 定位度量first(x)nth(x, 2)last(x)
    这几个函数的作用与 x[1]、x[2] 和 x[length(x)] 相同,只是当定位不存在时(比如尝试从只有两个元素的分组中得到第三个元素),前者允许你设置一个默认值。

3.6.5 按多个变量分组

当使用多个变量进行分组时,每次的摘要统计会用掉一个分组变量。这样就可以轻松地对数据集进行循序渐进的分析:

#统计每天的航班数
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

注意:在循序渐进地进行摘要分析时,使用求和与计数操作是没问题的,但如果想要使用加权平均和方差的话,就要仔细考虑一下,在基于秩的统计数据(如中位数)上是无法进行这些操作的。换句话说,对分组求和的结果再求和就是对整体求和,但分组中位数的中位数可不是整体的中位数

3.6.6 取消分组

如果想要取消分组,并回到未分组的数据继续操作,那么可以使用ungroup()函数:

daily %>%
 ungroup() %>% # 不再按日期分组
 summarize(flights = n()) # 所有航班
#> # A tibble: 1 × 1
#> flights
#> <int>
#> 1 336776

往期推荐


R数据科学|3.5内容介绍及习题解答

R数据科学|3.3课后习题

R数据科学|3.2.4课后习题


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存