3 数据操作
3.1 数据读写
这里先介绍一下rio包,主要用于excel和R数据框之间相互导出。如excel的表格复制粘贴到R中,以及R中的数据框复制粘贴到excel中。
剪切板中的数据复制粘贴到R中:
及R中的数据框复制到剪切板中:
3.2 数据连接
3.2.1 合并行与和并列
合并行和和并列分别用dplyr 包中的bind_rows() 和bind_cols() 实现。
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1 6.9 3.1 5.4 2.1 virginica
## 2 6.5 3.2 5.1 2.0 virginica
## 3 6.6 3.0 4.4 1.4 versicolor
## 4 6.4 2.8 5.6 2.1 virginica
## 5 7.7 2.8 6.7 2.0 virginica
## 6 5.0 3.5 1.3 0.3 setosa
## mpg cyl disp hp drat
## Mazda RX4 21.0 6 160 110 3.90
## Mazda RX4 Wag 21.0 6 160 110 3.90
## Datsun 710 22.8 4 108 93 3.85
## Hornet 4 Drive 21.4 6 258 110 3.08
3.2.3 实现R中实现stata的merge命令
|
|
|
data1 <- data.frame(
A=c("小米","华为","苹果")
)
data2 <- data.frame(
A=c("小米","小米","苹果","OPPO"),
B=c("1","2","1","1")
)
data1 %>%
mutate(C=1) %>%
full_join(data2,by="A") %>%
mutate(merge_=case_when(is.na(C)~"只在data2",
is.na(B) ~"只在data1",
TRUE~"匹配上")) %>%
select(-C)## A B merge_
## 1 小米 1 匹配上
## 2 小米 2 匹配上
## 3 华为 <NA> 只在data1
## 4 苹果 1 匹配上
## 5 OPPO 1 只在data2
3.3 数据操作
select()—— 选择列
filter()/slice()——筛选行
arrange()——对行排序
mutate()—— 修改列/创建新列
summarize()—— 汇总
相同之处是
这些函数都可以与group_by()——分组
第1 个参数是数据框,方便管道操作
根据列名访问数据框的列,且列名不用加引号
返回结果是一个新数据框,不改变原数据框
3.3.1 选择列(select)
数据
## # A tibble: 50 × 8
## class name sex chinese math english moral science
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10
## 2 六1班 黄才菊 女 95 77 75 NA 9
## 3 六1班 陈芳妹 女 79 87 66 9 10
## 4 六1班 陈学勤 男 NA 79 66 9 10
## 5 六1班 陈祝贞 女 76 79 67 8 10
## 6 六1班 何小薇 女 83 73 65 8 9
## 7 六1班 雷旺 男 NA 80 68 8 9
## 8 六1班 陈欣越 男 57 80 60 9 9
## 9 六1班 黄亦婷 女 77 NA 54 8 10
## 10 六1班 陈媚 女 68 55 66 8 9
## # ℹ 40 more rows
3.3.2 选择列语法
(1)用列名或索引选择列
## # A tibble: 50 × 3
## name sex math
## <chr> <chr> <dbl>
## 1 何娜 女 92
## 2 黄才菊 女 77
## 3 陈芳妹 女 87
## 4 陈学勤 男 79
## 5 陈祝贞 女 79
## 6 何小薇 女 73
## 7 雷旺 男 80
## 8 陈欣越 男 80
## 9 黄亦婷 女 NA
## 10 陈媚 女 55
## # ℹ 40 more rows
(2) 借助运算符选择列
用: 选择连续的若干列
用! 选择变量集合的余集(反选)
& 和| 选择变量集合的交或并
c() 合并多个选
(3) 借助选择助手函数
- 选择指定列:
- everything(): 选择所有列
- last_col(): 选择最后一列,可以带参数,如last_col(5) 选择倒数第6 列
- 选择列名匹配的列:
- starts_with(): 以某前缀开头的列名
- ends_with(): 以某后缀结尾的列名
- contains(): 包含某字符串的列名
- matches(): 匹配正则表达式的列名
- num_range(): 匹配数值范围的列名,如num_range(“x”, 1:3) 匹配x1, x2, x3
- 结合函数选择列:
- where(): 应用一个函数到所有列,选择返回结果为TRUE 的列,比如与is.numeric 等函数连用。
3.3.3 选择列的例子
## # A tibble: 50 × 2
## math moral
## <dbl> <dbl>
## 1 92 9
## 2 77 NA
## 3 87 9
## 4 79 9
## 5 79 8
## 6 73 8
## 7 80 8
## 8 80 9
## 9 NA 8
## 10 55 8
## # ℹ 40 more rows
## # A tibble: 50 × 3
## name chinese science
## <chr> <dbl> <dbl>
## 1 何娜 87 10
## 2 黄才菊 95 9
## 3 陈芳妹 79 10
## 4 陈学勤 NA 10
## 5 陈祝贞 76 10
## 6 何小薇 83 9
## 7 雷旺 NA 9
## 8 陈欣越 57 9
## 9 黄亦婷 77 10
## 10 陈媚 68 9
## # ℹ 40 more rows
## # A tibble: 50 × 4
## class name math moral
## <chr> <chr> <dbl> <dbl>
## 1 六1班 何娜 92 9
## 2 六1班 黄才菊 77 NA
## 3 六1班 陈芳妹 87 9
## 4 六1班 陈学勤 79 9
## 5 六1班 陈祝贞 79 8
## 6 六1班 何小薇 73 8
## 7 六1班 雷旺 80 8
## 8 六1班 陈欣越 80 9
## 9 六1班 黄亦婷 NA 8
## 10 六1班 陈媚 55 8
## # ℹ 40 more rows
根据条件(逻辑判断)选择列,例如选择所有数值型的列:
## # A tibble: 50 × 5
## chinese math english moral science
## <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 87 92 79 9 10
## 2 95 77 75 NA 9
## 3 79 87 66 9 10
## 4 NA 79 66 9 10
## 5 76 79 67 8 10
## 6 83 73 65 8 9
## 7 NA 80 68 8 9
## 8 57 80 60 9 9
## 9 77 NA 54 8 10
## 10 68 55 66 8 9
## # ℹ 40 more rows
也可以自定义返回TRUE 或FALSE 的判断函数,支持purrr 风格公式写法。例如,选择列和>3000 的列:
## # A tibble: 50 × 2
## chinese math
## <dbl> <dbl>
## 1 87 92
## 2 95 77
## 3 79 87
## 4 NA 79
## 5 76 79
## 6 83 73
## 7 NA 80
## 8 57 80
## 9 77 NA
## 10 68 55
## # ℹ 40 more rows
结合n_distinct() 选择唯一值数目< 10 的列:
## # A tibble: 50 × 4
## class sex moral science
## <chr> <chr> <dbl> <dbl>
## 1 六1班 女 9 10
## 2 六1班 女 NA 9
## 3 六1班 女 9 10
## 4 六1班 男 9 10
## 5 六1班 女 8 10
## 6 六1班 女 8 9
## 7 六1班 男 8 9
## 8 六1班 男 9 9
## 9 六1班 女 8 10
## 10 六1班 女 8 9
## # ℹ 40 more rows
3.3.4 用“-” 删除列
## # A tibble: 50 × 5
## class sex math english moral
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 六1班 女 92 79 9
## 2 六1班 女 77 75 NA
## 3 六1班 女 87 66 9
## 4 六1班 男 79 66 9
## 5 六1班 女 79 67 8
## 6 六1班 女 73 65 8
## 7 六1班 男 80 68 8
## 8 六1班 男 80 60 9
## 9 六1班 女 NA 54 8
## 10 六1班 女 55 66 8
## # ℹ 40 more rows
选择math和除了“e”结尾的其他列
## # A tibble: 50 × 5
## math class sex english moral
## <dbl> <chr> <chr> <dbl> <dbl>
## 1 92 六1班 女 79 9
## 2 77 六1班 女 75 NA
## 3 87 六1班 女 66 9
## 4 79 六1班 男 66 9
## 5 79 六1班 女 67 8
## 6 73 六1班 女 65 8
## 7 80 六1班 男 68 8
## 8 80 六1班 男 60 9
## 9 NA 六1班 女 54 8
## 10 55 六1班 女 66 8
## # ℹ 40 more rows
注意: -ends_with() 要放在everything() 后面,否则删除的列就全回来了。
3.3.5 调整列的顺序
(1)列是根据被选择的顺序排列:
## # A tibble: 50 × 6
## name chinese science math class sex
## <chr> <dbl> <dbl> <dbl> <chr> <chr>
## 1 何娜 87 10 92 六1班 女
## 2 黄才菊 95 9 77 六1班 女
## 3 陈芳妹 79 10 87 六1班 女
## 4 陈学勤 NA 10 79 六1班 男
## 5 陈祝贞 76 10 79 六1班 女
## 6 何小薇 83 9 73 六1班 女
## 7 雷旺 NA 9 80 六1班 男
## 8 陈欣越 57 9 80 六1班 男
## 9 黄亦婷 77 10 NA 六1班 女
## 10 陈媚 68 9 55 六1班 女
## # ℹ 40 more rows
(2)将数值列移到name 列的后面:
## # A tibble: 50 × 8
## math class name sex chinese english moral science
## <dbl> <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl>
## 1 92 六1班 何娜 女 87 79 9 10
## 2 77 六1班 黄才菊 女 95 75 NA 9
## 3 87 六1班 陈芳妹 女 79 66 9 10
## 4 79 六1班 陈学勤 男 NA 66 9 10
## 5 79 六1班 陈祝贞 女 76 67 8 10
## 6 73 六1班 何小薇 女 83 65 8 9
## 7 80 六1班 雷旺 男 NA 68 8 9
## 8 80 六1班 陈欣越 男 57 60 9 9
## 9 NA 六1班 黄亦婷 女 77 54 8 10
## 10 55 六1班 陈媚 女 68 66 8 9
## # ℹ 40 more rows
everything() 返回未被选择的所有列,将某一列移到第一列时很方便:
(3)将选择的列移到某列之前或之后
## # A tibble: 50 × 8
## class name chinese math english moral science sex
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <chr>
## 1 六1班 何娜 87 92 79 9 10 女
## 2 六1班 黄才菊 95 77 75 NA 9 女
## 3 六1班 陈芳妹 79 87 66 9 10 女
## 4 六1班 陈学勤 NA 79 66 9 10 男
## 5 六1班 陈祝贞 76 79 67 8 10 女
## 6 六1班 何小薇 83 73 65 8 9 女
## 7 六1班 雷旺 NA 80 68 8 9 男
## 8 六1班 陈欣越 57 80 60 9 9 男
## 9 六1班 黄亦婷 77 NA 54 8 10 女
## 10 六1班 陈媚 68 55 66 8 9 女
## # ℹ 40 more rows
3.3.6 重命名列
(1)为所有列设置新列名set_names()
## # A tibble: 50 × 8
## ` 班级` ` 姓名` ` 性别` ` 语文` ` 数学` ` 英语` ` 品德` ` 科学`
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10
## 2 六1班 黄才菊 女 95 77 75 NA 9
## 3 六1班 陈芳妹 女 79 87 66 9 10
## 4 六1班 陈学勤 男 NA 79 66 9 10
## 5 六1班 陈祝贞 女 76 79 67 8 10
## 6 六1班 何小薇 女 83 73 65 8 9
## 7 六1班 雷旺 男 NA 80 68 8 9
## 8 六1班 陈欣越 男 57 80 60 9 9
## 9 六1班 黄亦婷 女 77 NA 54 8 10
## 10 六1班 陈媚 女 68 55 66 8 9
## # ℹ 40 more rows
(2)只修改部分列名rename(),格式为:新名= 旧名
## # A tibble: 50 × 8
## class name sex chinese 数学 english moral 科学
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10
## 2 六1班 黄才菊 女 95 77 75 NA 9
## 3 六1班 陈芳妹 女 79 87 66 9 10
## 4 六1班 陈学勤 男 NA 79 66 9 10
## 5 六1班 陈祝贞 女 76 79 67 8 10
## 6 六1班 何小薇 女 83 73 65 8 9
## 7 六1班 雷旺 男 NA 80 68 8 9
## 8 六1班 陈欣越 男 57 80 60 9 9
## 9 六1班 黄亦婷 女 77 NA 54 8 10
## 10 六1班 陈媚 女 68 55 66 8 9
## # ℹ 40 more rows
(3) rename_with(.data, .fn, .cols)函数
参数.col 支持用选择列语法选择要重命名的 列,.fn 是对所选列重命名的函数,将原列名的字符向量变成新列名的字符向量。比如,将包含”m’’ 的列名,都拼接上前缀”new_“:
3.4 分组汇总
3.4.1 创建分组
用group_by() 创建分组,只是对数据框增加了分组信息(用group_keys() 查看),并不是真的将数据分割为多个数据框。
## # A tibble: 3 × 1
## Species
## <fct>
## 1 setosa
## 2 versicolor
## 3 virginica
## [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
## [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
## [75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3
## [112] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
## [149] 3 3
## <list_of<integer>[3]>
## [[1]]
## [1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## [26] 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
##
## [[2]]
## [1] 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
## [20] 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
## [39] 89 90 91 92 93 94 95 96 97 98 99 100
##
## [[3]]
## [1] 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119
## [20] 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
## [39] 139 140 141 142 143 144 145 146 147 148 149 150
3.4.2 分组汇总
对数据框做分组最主要的目的就是做分组汇总,汇总就是以某种方式组合行,用dplyr 包中的summarise() 函数实现,结果只保留分组列唯一值和新创建的汇总列。
(1) summarise()
可以与很多自带或自定义的汇总函数连用,常用的汇总函数有:
n(): 观测数
n_distinct(var): 变量var 的唯一值数目
sum(var), max(var), min(var), . . .
mean(var), median(var), sd(var), IQR(var),
df = readxl::read_xlsx("datas/ExamDatas_NAs.xlsx")
df %>%
group_by(sex) %>%
summarise(n=n(),
math_avg=mean(math,na.rm=TRUE),
math_med=median(math))## # A tibble: 3 × 4
## sex n math_avg math_med
## <chr> <int> <dbl> <dbl>
## 1 女 25 70.8 NA
## 2 男 24 64.6 NA
## 3 <NA> 1 85 85
(2)对所有列汇总
## Warning: There was 1 warning in `summarise()`.
## ℹ In argument: `across(everything(), mean, na.rm = TRUE)`.
## ℹ In group 1: `class = "六1班"`, `sex = "女"`.
## Caused by warning:
## ! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
## Supply arguments directly to `.fns` through an anonymous function instead.
##
## # Previously
## across(a:b, mean, na.rm = TRUE)
##
## # Now
## across(a:b, \(x) mean(x, na.rm = TRUE))
## # A tibble: 12 × 7
## # Groups: class [6]
## class sex chinese math english moral science
## <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 女 80.7 77.2 67.4 8.33 9.57
## 2 六1班 男 57 79.7 64.7 8.67 9.33
## 3 六2班 女 92.2 73.8 63.8 8.33 9
## 4 六2班 男 75.4 68.8 42.6 8.8 9.25
## 5 六3班 女 68.4 49.2 67.8 6.25 7.2
## 6 六3班 男 66 30.4 67.6 4.6 4.75
## 7 六4班 女 85.2 74 63.7 8.75 7.75
## 8 六4班 男 84.8 79.2 55.7 8.6 8.5
## 9 六5班 女 80.4 75.4 63.4 8.75 8.25
## 10 六5班 男 66.5 64.5 65.3 8.25 8.25
## 11 六5班 <NA> 58 85 48 9 10
## 12 <NA> 男 90 86 72 9 10
(3)对某些列汇总
计算列名中包含”h”的列的平均值
## `summarise()` has grouped output by 'class'. You can override using the
## `.groups` argument.
## # A tibble: 12 × 5
## # Groups: class [6]
## class sex chinese math english
## <chr> <chr> <dbl> <dbl> <dbl>
## 1 六1班 女 80.7 77.2 67.4
## 2 六1班 男 57 79.7 64.7
## 3 六2班 女 92.2 73.8 63.8
## 4 六2班 男 75.4 68.8 42.6
## 5 六3班 女 68.4 49.2 67.8
## 6 六3班 男 66 30.4 67.6
## 7 六4班 女 85.2 74 63.7
## 8 六4班 男 84.8 79.2 55.7
## 9 六5班 女 80.4 75.4 63.4
## 10 六5班 男 66.5 64.5 65.3
## 11 六5班 <NA> 58 85 48
## 12 <NA> 男 90 86 72
(4) 对满足条件的列做多种汇总 分别计算数值型各列的平均值和sum
library(tidyselect)
df %>%
group_by(class) %>%
summarise(across(.cols = where(is.numeric),
.fns = list(sum=sum,mean=mean),na.rm=TRUE))## # A tibble: 6 × 11
## class chinese_sum chinese_mean math_sum math_mean english_sum english_mean
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 622 77.8 702 78 666 66.6
## 2 六2班 746 82.9 570 71.2 468 52
## 3 六3班 606 67.3 349 38.8 609 67.7
## 4 六4班 850 85 771 77.1 525 58.3
## 5 六5班 726 72.6 720 72 561 62.3
## 6 <NA> 90 90 86 86 72 72
## # ℹ 4 more variables: moral_sum <dbl>, moral_mean <dbl>, science_sum <dbl>,
## # science_mean <dbl>
分组计数
用count() 按分类变量class 和sex 分组,并按分组大小排序:
## # A tibble: 12 × 3
## class sex n
## <chr> <chr> <int>
## 1 六1班 女 7
## 2 六4班 男 6
## 3 六2班 男 5
## 4 六3班 女 5
## 5 六3班 男 5
## 6 六5班 女 5
## 7 六2班 女 4
## 8 六4班 女 4
## 9 六5班 男 4
## 10 六1班 男 3
## 11 六5班 <NA> 1
## 12 <NA> 男 1
对已分组的数据框,用tally() 计数
## # A tibble: 5 × 2
## math_level n
## <fct> <int>
## 1 [0,60) 14
## 2 [60,75) 11
## 3 [75,80) 5
## 4 [80,100) 17
## 5 <NA> 3
注:count() 和tally() 都有参数wt 设置加权计数。
用add_count() 和add_tally() 可为数据集增加一列按分组变量分组的计数:
## # A tibble: 50 × 9
## class name sex chinese math english moral science n
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <int>
## 1 六1班 何娜 女 87 92 79 9 10 7
## 2 六1班 黄才菊 女 95 77 75 NA 9 7
## 3 六1班 陈芳妹 女 79 87 66 9 10 7
## 4 六1班 陈学勤 男 NA 79 66 9 10 3
## 5 六1班 陈祝贞 女 76 79 67 8 10 7
## 6 六1班 何小薇 女 83 73 65 8 9 7
## 7 六1班 雷旺 男 NA 80 68 8 9 3
## 8 六1班 陈欣越 男 57 80 60 9 9 3
## 9 六1班 黄亦婷 女 77 NA 54 8 10 7
## 10 六1班 陈媚 女 68 55 66 8 9 7
## # ℹ 40 more rows
3.5 其他数据操作
3.5.1 按行汇总
通常的数据操作逻辑都是按列方式(colwise),这使得按行汇总很困难。
dplyr 包提供了rowwise() 函数为数据框创建按行方式(rowwise),使用rowwise() 后并不是真的 改变数据框,只是创建了按行元信息,改变了数据框的操作逻辑:
按行汇总语数外的总分
df = readxl::read_xlsx("datas/ExamDatas_NAs.xlsx")
rf = df %>%
rowwise()
rf %>%
mutate(total=sum(c(chinese,math,english)))## # A tibble: 50 × 9
## # Rowwise:
## class name sex chinese math english moral science total
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10 258
## 2 六1班 黄才菊 女 95 77 75 NA 9 247
## 3 六1班 陈芳妹 女 79 87 66 9 10 232
## 4 六1班 陈学勤 男 NA 79 66 9 10 NA
## 5 六1班 陈祝贞 女 76 79 67 8 10 222
## 6 六1班 何小薇 女 83 73 65 8 9 221
## 7 六1班 雷旺 男 NA 80 68 8 9 NA
## 8 六1班 陈欣越 男 57 80 60 9 9 197
## 9 六1班 黄亦婷 女 77 NA 54 8 10 NA
## 10 六1班 陈媚 女 68 55 66 8 9 189
## # ℹ 40 more rows
函数c_across() 是为按行方式(rowwise) 在选定的列范围汇总数据而设计的,它没有提供.fns 参数,只能选择列
## # A tibble: 50 × 9
## # Rowwise:
## class name sex chinese math english moral science total
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10 277
## 2 六1班 黄才菊 女 95 77 75 NA 9 NA
## 3 六1班 陈芳妹 女 79 87 66 9 10 251
## 4 六1班 陈学勤 男 NA 79 66 9 10 NA
## 5 六1班 陈祝贞 女 76 79 67 8 10 240
## 6 六1班 何小薇 女 83 73 65 8 9 238
## 7 六1班 雷旺 男 NA 80 68 8 9 NA
## 8 六1班 陈欣越 男 57 80 60 9 9 215
## 9 六1班 黄亦婷 女 77 NA 54 8 10 NA
## 10 六1班 陈媚 女 68 55 66 8 9 206
## # ℹ 40 more rows
若只是做按行求和或均值,直接用rowSums() / rowMeans() 速度更快(不需要分割-汇总-合并), 这里的rowwise 行化后提供可以做更多的按行汇总的可能。
## # A tibble: 50 × 9
## class name sex chinese math english moral science total
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 六1班 何娜 女 87 92 79 9 10 277
## 2 六1班 黄才菊 女 95 77 75 NA 9 NA
## 3 六1班 陈芳妹 女 79 87 66 9 10 251
## 4 六1班 陈学勤 男 NA 79 66 9 10 NA
## 5 六1班 陈祝贞 女 76 79 67 8 10 240
## 6 六1班 何小薇 女 83 73 65 8 9 238
## 7 六1班 雷旺 男 NA 80 68 8 9 NA
## 8 六1班 陈欣越 男 57 80 60 9 9 215
## 9 六1班 黄亦婷 女 77 NA 54 8 10 NA
## 10 六1班 陈媚 女 68 55 66 8 9 206
## # ℹ 40 more rows
按行方式(rowwise) 可以理解为一种特殊的分组:每一行作为一组。为rowwise() 提供行ID,用 summarise() 做汇总更能体会这一点。要解除行化模式,用ungroup().
## Warning: Returning more (or less) than 1 row per `summarise()` group was deprecated in
## dplyr 1.1.0.
## ℹ Please use `reframe()` instead.
## ℹ When switching from `summarise()` to `reframe()`, remember that `reframe()`
## always returns an ungrouped data frame and adjust accordingly.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## `summarise()` has grouped output by 'name'. You can override using the
## `.groups` argument.
## # A tibble: 250 × 2
## # Groups: name [50]
## name total
## <chr> <dbl>
## 1 何娜 87
## 2 何娜 92
## 3 何娜 79
## 4 何娜 9
## 5 何娜 10
## 6 黄才菊 95
## 7 黄才菊 77
## 8 黄才菊 75
## 9 黄才菊 NA
## 10 黄才菊 9
## # ℹ 240 more rows
rowwise 行化操作的缺点是速度相对更慢,更建议用XXX 节讲到的pmap() 逐行迭代。
3.5.2 窗口函数
汇总函数如sum() 和mean() 接受n 个输入,返回1 个值。而窗口函数是汇总函数的变体:接受n 个输入,返回n 个值。
例如,cumsum()、cummean()、rank()、lead()、lag() 等。
(1)排名和排序函数
从小到大排名(ties.method=“min”),若要从大到小排名需要套一个desc()
安装数学成绩给每个学生生存排名
## # A tibble: 50 × 9
## class name sex chinese math english moral science ranks
## <chr> <chr> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <int>
## 1 六4班 周婵 女 92 94 77 10 9 1
## 2 六4班 陈丽丽 女 87 93 NA 8 6 2
## 3 六1班 何娜 女 87 92 79 9 10 3
## 4 六5班 符苡榕 女 85 89 76 9 NA 4
## 5 六2班 黄祖娜 女 94 88 75 10 10 5
## 6 六1班 陈芳妹 女 79 87 66 9 10 6
## 7 六4班 李小龄 男 90 87 69 10 10 6
## 8 六2班 徐雅琦 女 92 86 72 NA 9 8
## 9 <NA> 徐达政 男 90 86 72 9 10 8
## 10 六4班 杨昌晟 男 84 85 64 8 10 10
## # ℹ 40 more rows
3.6 整洁计算
tidyverse 代码之所以这么“整洁、优雅”,访问列只需要提供列名,不需要加引号,不需要加数据框环境df$, 这是因为它内部采用了一套整洁计算(tidy evaluation)框架。
如果我们也想自定义这样的“整洁、优雅”函数,即在自定义函数中页这样“整洁、优雅”地传递参数,就需要掌握一点整洁计算的技术。
3.6.1 数据屏蔽与整洁选择
整洁计算的两种基本形式是
数据屏蔽:使得可以不用带数据框(环境变量)名字,就能使用数据框内的变量(数据变量),便于在数据集内计算值
整洁选择:即各种选择列语法,便于使用数据集中的列
数据屏蔽为直接使用带来了代码简洁,但作为函数参数时的间接使用,正常是环境变量,要想作为数据变量使用,则需要用两个大括号括起来{{var}}:
var_summary = function(data, var) {
data %>%
summarise(n = n(), mean = mean({{var}}))
}
mtcars %>%
group_by(cyl) %>%
var_summary(mpg)## # A tibble: 3 × 3
## cyl n mean
## <dbl> <int> <dbl>
## 1 4 11 26.7
## 2 6 7 19.7
## 3 8 14 15.1
若是字符向量形式,想作为数据变量,则需要在函数体中使用.data[[var]],这里.data 是代替数据集的代词:
var_summary = function(data,var){
data %>%
summarise(n=n(),mean=mean(.data[[var]]))
}
mtcars %>%
group_by(cyl) %>%
var_summary("mpg")## # A tibble: 3 × 3
## cyl n mean
## <dbl> <int> <dbl>
## 1 4 11 26.7
## 2 6 7 19.7
## 3 8 14 15.1