闰咄阅 发表于 前天 00:05

dplyr和tidyr用法

简介

tidyverse是一套数据分析套件包,它极大地简化和拓展了使用R语言进行数据分析的操作,涵盖了数据导入、数据处理和可视化等多方面的功能。
dplyr和tidyr是tidyverse的重要组成部分,前者主要用于数据的处理,后者则主要用于数据的格式调整。
两者的主要处理的对象是data.frame(及衍生的data.table和tibble),这是一种用于存储高度结构化数据的对象。你可以将data.frame视作一张表格,其每一行为一个条目,每一列为一项属性。同一列中的所有数据类型一致,而同一行则不一定。data.frame中的每列都可以被视为一个向量,在dplyr的许多操作中可以体会到这一点。
magrittr的pipe操作符%>%是一种可以很好地简化和美化链式函数调用的语法工具。函数表达式function(value, args)可以用pipe改写为value %>% function(args)。dplyr和tidyr的data.frame操作函数都很好地支持了pipe语法。在后文介绍dplyr和tidyr函数的参数格式时,我们默认使用pipe中的参数格式,省去函数的第一个参数,即要操作的data.frame对象。
示例数据iris   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1         5.1         3.5          1.4         0.2setosa
2         4.9         3.0          1.4         0.2setosa
3         4.7         3.2          1.3         0.2setosa
4         4.6         3.1          1.5         0.2setosa
5         5.0         3.6          1.4         0.2setosa
6         5.4         3.9          1.7         0.4setosa
7         4.6         3.4          1.4         0.3setosa
8         5.0         3.4          1.5         0.2setosa
9         4.4         2.9          1.4         0.2setosa
10          4.9         3.1          1.5         0.1setosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]storms# A tibble: 19,537 × 13
   name   year month   dayhour   latlong status       categorywind pressure tropicalstorm_force_…¹
   <chr> <dbl> <dbl> <int> <dbl> <dbl> <dbl> <fct>         <dbl> <int>    <int>                  <int>
1 Amy    1975   6    27   027.5 -79   tropical de…       NA    25   1013                     NA
2 Amy    1975   6    27   628.5 -79   tropical de…       NA    25   1013                     NA
3 Amy    1975   6    27    1229.5 -79   tropical de…       NA    25   1013                     NA
4 Amy    1975   6    27    1830.5 -79   tropical de…       NA    25   1013                     NA
5 Amy    1975   6    28   031.5 -78.8 tropical de…       NA    25   1012                     NA
6 Amy    1975   6    28   632.4 -78.7 tropical de…       NA    25   1012                     NA
7 Amy    1975   6    28    1233.3 -78   tropical de…       NA    25   1011                     NA
8 Amy    1975   6    28    1834   -77   tropical de…       NA    30   1006                     NA
9 Amy    1975   6    29   034.4 -75.8 tropical st…       NA    35   1004                     NA
10 Amy    1975   6    29   634   -74.8 tropical st…       NA    40   1002                     NA
# ℹ 19,527 more rows
# ℹ abbreviated name: ¹​tropicalstorm_force_diameter
# ℹ 1 more variable: hurricane_force_diameter <int>data.frame(Titanic)   Class    Sex   Age Survived Freq
1    1st   Male Child       No    0
2    2nd   Male Child       No    0
3    3rd   Male Child       No   35
4   Crew   Male Child       No    0
5    1st Female Child       No    0
6    2nd Female Child       No    0
7    3rd Female Child       No   17
8   Crew Female Child       No    0
9    1st   Male Adult       No118
10   2nd   Male Adult       No154
[ reached 'max' / getOption("max.print") -- omitted 22 rows ]简单操作:行列操作、连接和调整

dplyr列操作

列操作包括选取(select)、排序(relocate)、重命名(rename)和编辑(mutate),列操作不会改变行的数量或顺序。
select用于从表中选取部分列。其参数格式为select(colname)或select(new_name=old_name),只有参数中指定的列会被保留。
iris %>% select(Species, Width = Petal.Width, Length = Petal.Length)   Species Width Length
1   setosa   0.2    1.4
2   setosa   0.2    1.4
3   setosa   0.2    1.3
4   setosa   0.2    1.5
5   setosa   0.2    1.4
6   setosa   0.4    1.7
7   setosa   0.3    1.4
8   setosa   0.2    1.5
9   setosa   0.2    1.4
10setosa   0.1    1.5
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]relocate用于改变列的顺序,而不改变列的数目。其参数格式和select类似,为relocate(colname)或relocate(new_name=old_name)。.before/.after参数可以指定要移动到的位置,如果没有指定,参数中指定的列将会被移动到表的最前面(左侧)。
iris %>% relocate(epithet=Species)   epithet Sepal.Length Sepal.Width Petal.Length Petal.Width
1   setosa          5.1         3.5          1.4         0.2
2   setosa          4.9         3.0          1.4         0.2
3   setosa          4.7         3.2          1.3         0.2
4   setosa          4.6         3.1          1.5         0.2
5   setosa          5.0         3.6          1.4         0.2
6   setosa          5.4         3.9          1.7         0.4
7   setosa          4.6         3.4          1.4         0.3
8   setosa          5.0         3.4          1.5         0.2
9   setosa          4.4         2.9          1.4         0.2
10setosa          4.9         3.1          1.5         0.1
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]rename用于对列进行重命名,而不会改变列的数量和位置,其参数格式为rename(new_name=old_name)。
iris %>% rename(V1=Sepal.Length, V2=Sepal.Width)    V1V2 Petal.Length Petal.Width Species
15.1 3.5          1.4         0.2setosa
24.9 3.0          1.4         0.2setosa
34.7 3.2          1.3         0.2setosa
44.6 3.1          1.5         0.2setosa
55.0 3.6          1.4         0.2setosa
65.4 3.9          1.7         0.4setosa
74.6 3.4          1.4         0.3setosa
85.0 3.4          1.5         0.2setosa
94.4 2.9          1.4         0.2setosa
10 4.9 3.1          1.5         0.1setosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]mutate用于创建新列,也可以用来修改或移除已有的列。其参数格式为mutate(new_col=fn(old_col1, old_col2,...)),其中old_col是列名,其值会作为向量传入函数fn,fn的计算结果则作为新列new_col的值。fn结果向量的长度应当与表的行数一致或为1。如果新列名new_col已存在,那么列值会被覆盖。值被赋为NULL的列会则被移除。
iris %>% mutate(Genus="Iris", epithet=Species, Species=paste(Genus, epithet))   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species Genus epithet
1         5.1         3.5          1.4         0.2 Iris setosaIrissetosa
2         4.9         3.0          1.4         0.2 Iris setosaIrissetosa
3         4.7         3.2          1.3         0.2 Iris setosaIrissetosa
4         4.6         3.1          1.5         0.2 Iris setosaIrissetosa
5         5.0         3.6          1.4         0.2 Iris setosaIrissetosa
6         5.4         3.9          1.7         0.4 Iris setosaIrissetosa
7         4.6         3.4          1.4         0.3 Iris setosaIrissetosa
8         5.0         3.4          1.5         0.2 Iris setosaIrissetosa
9         4.4         2.9          1.4         0.2 Iris setosaIrissetosa
10          4.9         3.1          1.5         0.1 Iris setosaIrissetosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]dplyr行操作

行操作包括筛选(filter)、排序(arrange)、分片(slice)、汇总(summarize)和重构(reframe),以及简写操作计数(count和tally)和去重(distinct)
filter用于筛选满足指定条件的列。其参数为filter(fn(col1,col2,...)),其中col是列名,其值会作为向量传入函数fn,只有fn的计算结果为TRUE的列会被保留。
iris %>% filter(Species=="virginica")   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
1         6.3         3.3          6.0         2.5 virginica
2         5.8         2.7          5.1         1.9 virginica
3         7.1         3.0          5.9         2.1 virginica
4         6.3         2.9          5.6         1.8 virginica
5         6.5         3.0          5.8         2.2 virginica
6         7.6         3.0          6.6         2.1 virginica
7         4.9         2.5          4.5         1.7 virginica
8         7.3         2.9          6.3         1.8 virginica
9         6.7         2.5          5.8         1.8 virginica
10          7.2         3.6          6.1         2.5 virginica
[ reached 'max' / getOption("max.print") -- omitted 40 rows ]arrange用于按指定条件排序行。其参数格式为arrange(fn(...)),fn的计算结果将作为排序的依据。
iris %>% arrange(desc(Species), -Sepal.Length)   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
1         7.9         3.8          6.4         2.0 virginica
2         7.7         3.8          6.7         2.2 virginica
3         7.7         2.6          6.9         2.3 virginica
4         7.7         2.8          6.7         2.0 virginica
5         7.7         3.0          6.1         2.3 virginica
6         7.6         3.0          6.6         2.1 virginica
7         7.4         2.8          6.1         1.9 virginica
8         7.3         2.9          6.3         1.8 virginica
9         7.2         3.6          6.1         2.5 virginica
10          7.2         3.2          6.0         1.8 virginica
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]slice用于选取指定的行,参数格式为slice(fn(...)),fn的计算结果应当为一个整数向量,对应行数的行将会被保留。除了slice外,还有取首行(slice_head)、取尾行(slice_tail)、取随机行(slice_sample)、取最大行(slice_max)和取最小行(slice_min)几个常用的辅助函数
iris %>% slice_max(Petal.Width, n=10)   Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
1         6.3         3.3          6.0         2.5 virginica
2         7.2         3.6          6.1         2.5 virginica
3         6.7         3.3          5.7         2.5 virginica
4         5.8         2.8          5.1         2.4 virginica
5         6.3         3.4          5.6         2.4 virginica
6         6.7         3.1          5.6         2.4 virginica
7         6.4         3.2          5.3         2.3 virginica
8         7.7         2.6          6.9         2.3 virginica
9         6.9         3.2          5.7         2.3 virginica
10          7.7         3.0          6.1         2.3 virginica
[ reached 'max' / getOption("max.print") -- omitted 4 rows ]summarise用于将多行汇总为一行。其参数格式为summarise(col_name=fn(col1,col2,...)),其中col是原表格中的列名,函数fn的计算结果应当是一个长度为1的向量,col_name是汇总后的列名。
iris %>% summarise(Petal.Width.Max=max(Petal.Width),Petal.Width.Min=min(Petal.Width))Petal.Width.Max Petal.Width.Min
1             2.5             0.1reframe与summarise类似,但是不限定fn计算结果的长度。如果fn计算结果的长度超过1,那么会生成多行。
iris %>% reframe(Petal.Width=quantile(Petal.Width),Petal.Length=quantile(Petal.Length))Petal.Width Petal.Length
1         0.1         1.00
2         0.3         1.60
3         1.3         4.35
4         1.8         5.10
5         2.5         6.90dplyr表连接

# 示例数据
band_members# A tibble: 3 × 2
nameband   
<chr> <chr>
1 MickStones
2 JohnBeatles
3 PaulBeatlesband_instruments# A tibble: 3 × 2
nameplays
<chr> <chr>
1 Johnguitar
2 Paulbass
3 Keith guitar表连接函数包括根据指定列合并表的inner_join、left_join、right_join、full_join和生成所有条目对枚举(笛卡尔积)的cross_join,以及用于筛选数据的semi_join和anti_join。
band_members %>% inner_join(band_instruments)# A tibble: 2 × 3
nameband    plays
<chr> <chr>   <chr>
1 JohnBeatles guitar
2 PaulBeatles bassband_members %>% left_join(band_instruments)# A tibble: 3 × 3
nameband    plays
<chr> <chr>   <chr>
1 MickStones<NA>
2 JohnBeatles guitar
3 PaulBeatles bassband_members %>% right_join(band_instruments)# A tibble: 3 × 3
nameband    plays
<chr> <chr>   <chr>
1 JohnBeatles guitar
2 PaulBeatles bass
3 Keith <NA>    guitarband_members %>% full_join(band_instruments)# A tibble: 4 × 3
nameband    plays
<chr> <chr>   <chr>
1 MickStones<NA>
2 JohnBeatles guitar
3 PaulBeatles bass
4 Keith <NA>    guitarband_members %>% cross_join(band_instruments)# A tibble: 9 × 4
name.x band    name.y plays
<chr><chr>   <chr><chr>
1 Mick   StonesJohn   guitar
2 Mick   StonesPaul   bass
3 Mick   StonesKeithguitar
4 John   Beatles John   guitar
5 John   Beatles Paul   bass
6 John   Beatles Keithguitar
7 Paul   Beatles John   guitar
8 Paul   Beatles Paul   bass
9 Paul   Beatles Keithguitarband_members %>% semi_join(band_instruments)# A tibble: 2 × 2
nameband   
<chr> <chr>
1 JohnBeatles
2 PaulBeatlesband_members %>% anti_join(band_instruments)# A tibble: 1 × 2
nameband
<chr> <chr>
1 MickStonestidyr表调整

基础的表调整包括多列转单列的gather和单列转多列的spread。
gather可以将表格的列名转换为独立的列,同时保留列值和其他列数据的对应关系。其参数格式为gather("name_of_key_col", "name_of_value_col", cols_to_gather)
iris %>% gather("measurement","value",Sepal.Length:Petal.Width)   Speciesmeasurement value
1   setosa Sepal.Length   5.1
2   setosa Sepal.Length   4.9
3   setosa Sepal.Length   4.7
4   setosa Sepal.Length   4.6
5   setosa Sepal.Length   5.0
6   setosa Sepal.Length   5.4
7   setosa Sepal.Length   4.6
8   setosa Sepal.Length   5.0
9   setosa Sepal.Length   4.4
10setosa Sepal.Length   4.9
[ reached 'max' / getOption("max.print") -- omitted 590 rows ]spread是gather的逆操作,能够根据指定的索引列,将一列数据转换为以索引列的值为列名的多列数据。其参数格式为spread(key_col, value_col)。spread不支持多列key_col或value_col,对于更高级的操作,参见pivot_wider
data.frame(Titanic) %>% spread(Class, Freq)   Sex   Age Survived 1st 2nd 3rd Crew
1   Male Child       No   0   035    0
2   Male Child      Yes   51113    0
3   Male Adult       No 118 154 387670
4   Male Adult      Yes571475192
5 Female Child       No   0   017    0
6 Female Child      Yes   11314    0
7 Female Adult       No   41389    3
8 Female Adult      Yes 1408076   20进阶操作:分组和批处理

批量处理

across用于在mutate、summarize和reframe中对多列应用同一函数
iris %>% mutate(across(Sepal.Length:Petal.Width, ~.x-mean(.x)))   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1    -0.74333330.44266667       -2.358-0.9993333setosa
2    -0.9433333 -0.05733333       -2.358-0.9993333setosa
3    -1.14333330.14266667       -2.458-0.9993333setosa
4    -1.24333330.04266667       -2.258-0.9993333setosa
5    -0.84333330.54266667       -2.358-0.9993333setosa
6    -0.44333330.84266667       -2.058-0.7993333setosa
7    -1.24333330.34266667       -2.358-0.8993333setosa
8    -0.84333330.34266667       -2.258-0.9993333setosa
9    -1.4433333 -0.15733333       -2.358-0.9993333setosa
10   -0.94333330.04266667       -2.258-1.0993333setosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]across默认不会修改列名,如果要修改列名可以通过.names参数指定,可以用"{.col}"和"{.fn}"指代列名和函数名。 
iris %>% reframe(q=seq(0,1,0.25),across(
Sepal.Length:Petal.Width, list(quantile=~quantile(.x,q),percentage=~quantile(range(.x),q)), .names="{.col}_{.fn}"
))   q Sepal.Length_quantile Sepal.Length_percentage Sepal.Width_quantile Sepal.Width_percentage
1 0.00                   4.3                     4.3                  2.0                  2.0
2 0.25                   5.1                     5.2                  2.8                  2.6
3 0.50                   5.8                     6.1                  3.0                  3.2
4 0.75                   6.4                     7.0                  3.3                  3.8
5 1.00                   7.9                     7.9                  4.4                  4.4
Petal.Length_quantile Petal.Length_percentage Petal.Width_quantile Petal.Width_percentage
1                  1.00                   1.000                  0.1                  0.1
2                  1.60                   2.475                  0.3                  0.7
3                  4.35                   3.950                  1.3                  1.3
4                  5.10                   5.425                  1.8                  1.9
5                  6.90                   6.900                  2.5                  2.5if_any和if_all用于在filter中对多列应用同一函数,并对筛选结果取并集或交集
iris %>% filter(if_any(Sepal.Length:Petal.Width,~.x>median(.x)))   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1         5.1         3.5          1.4         0.2setosa
2         4.7         3.2          1.3         0.2setosa
3         4.6         3.1          1.5         0.2setosa
4         5.0         3.6          1.4         0.2setosa
5         5.4         3.9          1.7         0.4setosa
6         4.6         3.4          1.4         0.3setosa
7         5.0         3.4          1.5         0.2setosa
8         4.9         3.1          1.5         0.1setosa
9         5.4         3.7          1.5         0.2setosa
10          4.8         3.4          1.6         0.2setosa
[ reached 'max' / getOption("max.print") -- omitted 113 rows ]iris %>% filter(if_all(Sepal.Length:Petal.Width,~.x>median(.x)))   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1         7.0         3.2          4.7         1.4 versicolor
2         6.4         3.2          4.5         1.5 versicolor
3         6.9         3.1          4.9         1.5 versicolor
4         6.3         3.3          4.7         1.6 versicolor
5         6.7         3.1          4.4         1.4 versicolor
6         5.9         3.2          4.8         1.8 versicolor
7         6.0         3.4          4.5         1.6 versicolor
8         6.7         3.1          4.7         1.5 versicolor
9         6.3         3.3          6.0         2.5virginica
10          7.2         3.6          6.1         2.5virginica
[ reached 'max' / getOption("max.print") -- omitted 15 rows ]rename_with可以使用自定义函数对多列进行重命名
iris %>% rename_with(~str_replace(.x, "(.*)\\.(.).*", "\\2_\\1"))   L_Sepal W_Sepal L_Petal W_Petal Species
1      5.1   3.5   1.4   0.2setosa
2      4.9   3.0   1.4   0.2setosa
3      4.7   3.2   1.3   0.2setosa
4      4.6   3.1   1.5   0.2setosa
5      5.0   3.6   1.4   0.2setosa
6      5.4   3.9   1.7   0.4setosa
7      4.6   3.4   1.4   0.3setosa
8      5.0   3.4   1.5   0.2setosa
9      4.4   2.9   1.4   0.2setosa
10   4.9   3.1   1.5   0.1setosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]多列赋值

通常,mutate函数的一个参数一次只能返回一列。如果想要一次返回多列,可以向将表转换为tibble对象,然后让fn返回一个data.frame:
as_tibble(iris) %>%
mutate(as.data.frame(prcomp(t(pick(Sepal.Length:Petal.Width)))$rotation))# A tibble: 150 × 9
   Sepal.Length Sepal.Width Petal.Length Petal.Width Species   PC1   PC2      PC3      PC4
          <dbl>       <dbl>      <dbl>       <dbl> <fct>   <dbl>   <dbl>    <dbl>    <dbl>
1          5.1         3.5          1.4         0.2 setosa-0.0771 -0.121   0.00327 -0.757
2          4.9         3            1.4         0.2 setosa-0.0754 -0.09950.0824-0.282
3          4.7         3.2          1.3         0.2 setosa-0.0709 -0.110   0.0110-0.0304
4          4.6         3.1          1.5         0.2 setosa-0.0701 -0.0968 -0.0312-0.0110
5          5         3.6          1.4         0.2 setosa-0.0751 -0.124-0.0436   0.0337
6          5.4         3.9          1.7         0.4 setosa-0.0785 -0.126-0.0463   0.00279
7          4.6         3.4          1.4         0.3 setosa-0.0671 -0.112-0.0580   0.00412
8          5         3.4          1.5         0.2 setosa-0.0760 -0.112-0.0166   0.0501
9          4.4         2.9          1.4         0.2 setosa-0.0670 -0.0914 -0.003830.00380
10          4.9         3.1          1.5         0.1 setosa-0.0769 -0.09990.0104   0.0773
# ℹ 140 more rows分组操作

mutate和行操作支持按特定列分组(group_by和rowwise,或by/.by参数),分组后每组会独立应用函数。
可以使用group_by将表格转换为grouped_df,对grouped_df的所有操作均会自动按组进行。ungroup可以取消分组。
iris %>% group_by(Species) %>%
summarize(mean.L_Sepal=mean(Sepal.Length), mean.L_Petal=mean(Petal.Length), n.Sample=n()) %>%
ungroup()# A tibble: 3 × 4
Species    mean.L_Sepal mean.L_Petal n.Sample
<fct>             <dbl>      <dbl>    <int>
1 setosa             5.01         1.46       50
2 versicolor         5.94         4.26       50
3 virginica          6.59         5.55       50也可以在操作函数中直接指定.by参数
iris %>% reframe(q=seq(0,1,0.25), L_Sepal=quantile(Sepal.Length, q), .by=Species)      Species    q L_Sepal
1      setosa 0.00   4.3
2      setosa 0.25   4.8
3      setosa 0.50   5.0
4      setosa 0.75   5.2
5      setosa 1.00   5.8
6versicolor 0.00   4.9
7versicolor 0.25   5.6
8versicolor 0.50   5.9
9versicolor 0.75   6.3
10 versicolor 1.00   7.0
[ reached 'max' / getOption("max.print") -- omitted 5 rows ]iris %>% filter(if_all(Sepal.Length:Petal.Width,~.x>median(.x)),.by=Species)   Sepal.Length Sepal.Width Petal.Length Petal.Width    Species
1         5.4         3.9          1.7         0.4   setosa
2         5.7         3.8          1.7         0.3   setosa
3         5.1         3.8          1.9         0.4   setosa
4         7.0         3.2          4.7         1.4 versicolor
5         6.4         3.2          4.5         1.5 versicolor
6         6.9         3.1          4.9         1.5 versicolor
7         6.3         3.3          4.7         1.6 versicolor
8         6.1         2.9          4.7         1.4 versicolor
9         6.7         3.1          4.4         1.4 versicolor
10          6.6         3.0          4.4         1.4 versicolor
[ reached 'max' / getOption("max.print") -- omitted 12 rows ]arrange函数默认忽略分组,且不支持.by/by参数。指定了.by_group=TRUE后,arrage会先对grouped_df的分组列进行排序,然后在各个组内分别按指定的列或计算结果进行排序。
data.frame(Titanic) %>% group_by(Class) %>% arrange(Freq, .by_group=TRUE)# A tibble: 32 × 5
# Groups:   Class
   Class Sex    Age   SurvivedFreq
   <fct> <fct><fct> <fct>    <dbl>
1 1st   Male   Child No         0
2 1st   Female Child No         0
3 1st   Female Child Yes          1
4 1st   Female Adult No         4
5 1st   Male   Child Yes          5
6 1st   Male   Adult Yes         57
7 1st   Male   Adult No         118
8 1st   Female Adult Yes      140
9 2nd   Male   Child No         0
10 2nd   Female Child No         0
# ℹ 22 more rows对grouped_df分组列的排序不支持自定义函数,如果要根据计算结果排列组,可以先用mutate生产索引列,或者利用ave函数:
data.frame(Titanic) %>% mutate(Class.Freq=sum(Freq),.by=Class) %>% arrange(Class.Freq)   Class    Sex   Age Survived Freq Class.Freq
1    2nd   Male Child       No    0      285
2    2nd Female Child       No    0      285
3    2nd   Male Adult       No154      285
4    2nd Female Adult       No   13      285
5    2nd   Male Child      Yes   11      285
6    2nd Female Child      Yes   13      285
7    2nd   Male Adult      Yes   14      285
8    2nd Female Adult      Yes   80      285
9    1st   Male Child       No    0      325
10   1st Female Child       No    0      325
[ reached 'max' / getOption("max.print") -- omitted 22 rows ]data.frame(Titanic) %>% arrange(ave(Freq,Class,FUN=sum))   Class    Sex   Age Survived Freq
1    2nd   Male Child       No    0
2    2nd Female Child       No    0
3    2nd   Male Adult       No154
4    2nd Female Adult       No   13
5    2nd   Male Child      Yes   11
6    2nd Female Child      Yes   13
7    2nd   Male Adult      Yes   14
8    2nd Female Adult      Yes   80
9    1st   Male Child       No    0
10   1st Female Child       No    0
[ reached 'max' / getOption("max.print") -- omitted 22 rows ]表调整

pivot_longer和pivot_wider可以实现比gather和spread更为精细和复杂的列转换操作。
pivot_longer的参数格式为pivot_longer(cols_to_gather, names_to="name_of_key_col", values_to="name_of_value_col"),另外还提供names_pattern、names_transform等可选参数对要转换的列名进行拆分和格式转换。
iris %>% pivot_longer(
Sepal.Length:Petal.Width,
names_to=c("component","measure"), names_pattern="(.*)\\.(.*)",
values_to=c("value")
)# A tibble: 600 × 4
   Species component measure value
   <fct>   <chr>   <chr>   <dbl>
1 setosaSepal   Length    5.1
2 setosaSepal   Width   3.5
3 setosaPetal   Length    1.4
4 setosaPetal   Width   0.2
5 setosaSepal   Length    4.9
6 setosaSepal   Width   3
7 setosaPetal   Length    1.4
8 setosaPetal   Width   0.2
9 setosaSepal   Length    4.7
10 setosaSepal   Width   3.2
# ℹ 590 more rows如果只想将列名中的一部分内容转移为新行,可以使用names_to中的保留字".value"。匹配该部分的内容将继续保留为列名。
iris %>% pivot_longer(
Sepal.Length:Petal.Width,
names_to=c("component",".value"), names_pattern="(.*)\\.(.*)"
)# A tibble: 300 × 4
   Species component Length Width
   <fct>   <chr>      <dbl> <dbl>
1 setosaSepal      5.1   3.5
2 setosaPetal      1.4   0.2
3 setosaSepal      4.9   3
4 setosaPetal      1.4   0.2
5 setosaSepal      4.7   3.2
6 setosaPetal      1.3   0.2
7 setosaSepal      4.6   3.1
8 setosaPetal      1.5   0.2
9 setosaSepal      5   3.6
10 setosaPetal      1.4   0.2
# ℹ 290 more rowspivot_wider的参数格式为pivot_wider(id_cols=id_col, names_from=key_col, values_from=value_col),其中id_col是转换后仍要保留的列(如果留空,则使用key_col和value_col以外所有的列),key_col是要转换为列名的列,value_col列的数据则会转换为对应列的值。可选参数names_glue可以设置列名格式,values_fill可以设置缺失值的替换值。
data.frame(Titanic) %>% pivot_wider(
names_from=c(Sex,Class), names_glue="{Sex}({Class})",
values_from=Freq
)# A tibble: 4 × 10
Age   Survived `Male(1st)` `Male(2nd)` `Male(3rd)` `Male(Crew)` `Female(1st)` `Female(2nd)`
<fct> <fct>          <dbl>       <dbl>       <dbl>      <dbl>         <dbl>         <dbl>
1 Child No               0         0          35            0             0             0
2 Adult No               118         154         387          670             4            13
3 Child Yes                5          11          13            0             1            13
4 Adult Yes               57          14          75          192         140            80
# ℹ 2 more variables: `Female(3rd)` <dbl>, `Female(Crew)` <dbl>如果一组id_col和key_col对应于多条value_col,可以通过values_fn参数指定数据的汇总方式
data.frame(Titanic) %>% pivot_wider(
id_cols=c(Sex,Survived),
names_from=Class,
values_from=Freq, values_fn=sum
)# A tibble: 4 × 6
Sex    Survived `1st` `2nd` `3rd`Crew
<fct><fct>    <dbl> <dbl> <dbl> <dbl>
1 Male   No         118   154   422   670
2 Female No         4    13   106   3
3 Male   Yes         62    25    88   192
4 Female Yes      141    93    90    20高级用法:变量替换

如前文所见,dplyr函数的一大特征是:在函数中,列名可以像变量一样使用。这为简单操作带来方便的同时,也给更进一步的高级操作带来了很大的麻烦。
一个最大的问题是:如何告诉函数某个变量指代的是列名还是来自全局环境中的变量呢?
这样的操作主要通过rlang包来实现。
预备知识:和

在进一步演示之前,先指出dplyr中的两种看起来相似但又略有不同的参数类型:和。
被用于filter()、mutate()、summarize()、reframe()、arrange()、slice()、count()、tally()、distinct()等可以对列做计算的函数中,用于将列作为参数传递给函数;而则主要被用在select()、rename()、relocate()、gather()、spread()函数,以及前述函数的.by参数中,用于对列进行选取。
我们首先介绍相对简单的的用法。
选取列的语法有两种风格,一种类似于base-r中的向量操作,另一种类似于集合操作符。

[*]base-r向量操作风格

[*]:表示连续范围
[*]c()表示并集
[*]-表示排除

[*]集合操作风格

[*]&表示交集
[*]|表示并集
[*]!表示排除

这些算符/函数既接受数字,也接受列名:
storms %>% select(c(2:5, status:pressure&!category), 1, latitude = lat, longitude = long)# A tibble: 19,537 × 10
    year month   dayhour status               wind pressure namelatitude longitude
   <dbl> <dbl> <int> <dbl> <fct>               <int>    <int> <chr>    <dbl>   <dbl>
11975   6    27   0 tropical depression    25   1013 Amy       27.5   -79
21975   6    27   6 tropical depression    25   1013 Amy       28.5   -79
31975   6    27    12 tropical depression    25   1013 Amy       29.5   -79
41975   6    27    18 tropical depression    25   1013 Amy       30.5   -79
51975   6    28   0 tropical depression    25   1012 Amy       31.5   -78.8
61975   6    28   6 tropical depression    25   1012 Amy       32.4   -78.7
71975   6    28    12 tropical depression    25   1011 Amy       33.3   -78
81975   6    28    18 tropical depression    30   1006 Amy       34       -77
91975   6    29   0 tropical storm         35   1004 Amy       34.4   -75.8
101975   6    29   6 tropical storm         40   1002 Amy       34       -74.8
# ℹ 19,527 more rows如果以...的形式传入函数(如select()、relocate())中,,分隔项会自动用|(并)连接;如果以单个参数的形式传入函数,则需要用c()或|将各项手动连起来。另外,,支持用=修改选取列的列名,而且会保留列的顺序,因此也可以用来对列进行重命名和重排。
还支持一些函数来指定要选取的列,包括:
函数作用everything()选取所有列last_col(n)选取倒数第n+1列starts_with("pattern")列名以"pattern"开头的列ends_with("pattern")列名以"pattern"结尾的列contains("pattern")列名包含"pattern"的列matches("pattern")列名匹配正则表达式regex("pattern")的列where(fn)fn(列内容)为TRUE的列注意与其他函数不同,where可以通过列的内容而不是列名或者顺序来选取列,以下是一个where函数的使用示例:
airquality %>% select(where(~ is.integer(.x) && !any(is.na(.x))))   Temp Month Day
1    67   5   1
2    72   5   2
3    74   5   3
4    62   5   4
5    56   5   5
6    66   5   6
7    65   5   7
8    59   5   8
9    61   5   9
10   69   510
[ reached 'max' / getOption("max.print") -- omitted 143 rows ]其中~和.x是purrr匿名函数简写格式,详细可见?purrr::as_mapper。
则是一个(或多个)以列名为变量名的表达式,用于对列表进行修改或汇总。
在表达式中,列名指定的列将以向量的形式传入函数或算符中参与运算。
例如,
iris %>% mutate(LW.ratio_Petal = Petal.Length / Petal.Width)   Sepal.Length Sepal.Width Petal.Length Petal.Width Species LW.ratio_Petal
1         5.1         3.5          1.4         0.2setosa       7.000000
2         4.9         3.0          1.4         0.2setosa       7.000000
3         4.7         3.2          1.3         0.2setosa       6.500000
4         4.6         3.1          1.5         0.2setosa       7.500000
5         5.0         3.6          1.4         0.2setosa       7.000000
6         5.4         3.9          1.7         0.4setosa       4.250000
7         4.6         3.4          1.4         0.3setosa       4.666667
8         5.0         3.4          1.5         0.2setosa       7.500000
9         4.4         2.9          1.4         0.2setosa       7.000000
10          4.9         3.1          1.5         0.1setosa      15.000000
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]就是计算iris$Petal.Length/iris$Petal.Width的结果并保存到LW.ratio_Petal列中。
如果使用的是一些非向量化的函数,那么得到会得到一些非预期的结果:
iris %>% mutate(new_col=sum(Petal.Length, Petal.Width))   Sepal.Length Sepal.Width Petal.Length Petal.Width Species new_col
1         5.1         3.5          1.4         0.2setosa   743.6
2         4.9         3.0          1.4         0.2setosa   743.6
3         4.7         3.2          1.3         0.2setosa   743.6
4         4.6         3.1          1.5         0.2setosa   743.6
5         5.0         3.6          1.4         0.2setosa   743.6
6         5.4         3.9          1.7         0.4setosa   743.6
7         4.6         3.4          1.4         0.3setosa   743.6
8         5.0         3.4          1.5         0.2setosa   743.6
9         4.4         2.9          1.4         0.2setosa   743.6
10          4.9         3.1          1.5         0.1setosa   743.6
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]可以看到,new_col的值均为743.6,这是因为实际进行的运算变成了sum(iris$Petal.Length, iris$Petal.Width),得到的单一值被填充为一列,得到了全为743.6的new_col
通过辅助函数c_across()和pick()可以在中以的格式选取列,前者会选取列拼接为向量,而后者会选取列为表:
iris %>% reframe(
len_c_across=length(c_across(c(Petal.Length,Petal.Width))),
nrow_pick=nrow(pick(Petal.Length,Petal.Width)),
ncol_pick=ncol(pick(Petal.Length,Petal.Width)),
.by=Species)   Species len_c_across nrow_pick ncol_pick
1   setosa          100      50         2
2 versicolor          100      50         2
3virginica          100      50         2在中进行变量替换

通常接受“裸露”的列名作为参数(如iris %>% select(Species, Petal.Width)中的Species和Petal.Width)。如果列名存储在变量中,则需要借助辅助函数或通过“注入”的方式将变量中的内容插入到参数中。
变量可以分为普通变量(var)和函数参数(arg)两种,后者还包括值传递(f("str")中的"str")、变量传递(f(var)中的var)和字面量(“裸露”的列名)三种情况。此外还可以接受列号(数字)作为参数。分别可以通过不同的方式将这些内容插入到参数中:
var1 <- 4 # 普通变量,列号(数字)
sp <- "Species" # 普通变量,列名(字符串)

iris %>% select(any_of(var1), !!sp)   Petal.Width Species
1          0.2setosa
2          0.2setosa
3          0.2setosa
4          0.2setosa
5          0.2setosa
6          0.4setosa
7          0.3setosa
8          0.2setosa
9          0.2setosa
10         0.1setosa
[ reached 'max' / getOption("max.print") -- omitted 140 rows ]虽然看上去花样很多,但实际用到的只有三类语法,分别是:

[*]tidyselect::辅助函数any_of()和all_of()
[*]rlang引用格式sym()、ensym()、enexpr()和注入符!!

[*]以及这一格式的简写形式{{ }}

any_of()和all_of()与前面提到的starts_with()、ends_with()等函数类似,接受一个字符串向量并选取相应列名的列。如果列名不存在于表中,any_of()会忽略这些列,而all_of()则会报错。
sym()、ensym()和enexpr()都是expr()的变体,它们都属于rlang的defuse函数家族。这个函数家族主要用于以字面形式存储表达式(而不是运行后的结果)。例如,expr(1+1)返回+, 1, 1,而不是1+1的结果2。defuse后的表达式可以赋值给变量,用来传递给其他函数,或者在需要的时候运行(通过eval()函数)。

sym()的功能是将字符串转化为符号。符号是一类简单的表达式,它不包含任何运算,仅仅指代一个字面值。例如,sym("sp")的结果为sp,而sym(sp)的结果则为Species(因为之前给sp赋值了sp
页: [1]
查看完整版本: dplyr和tidyr用法