dplyr | 提高数据处理效率!数据框的colwise和rowwise操作

前置推文:dplyr | 数据导入和预处理的常用函数

前面介绍了dplyr工具包中一些用于数据处理的常用函数,在处理的变量较少时,可以在相应的函数中逐个写入变量名,但当变量过多时,就需要寻求更加有效率的方式进行批量处理了。本篇介绍的colwise和rowwise操作就是一种对数据框更加省力的处理方式。

示例数据为mtcars

library(dplyr)
data <- mtcars
head(data)

##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1

1 colwise

colwise这个概念来自dplyr工具包,其本身并不是一个函数,具体操作函数包括acrossif_anyif_all

1.1 across函数

across函数的语法结构如下:

across(.cols = everything(), .fns = NULL, ...,
       .names = NULL)
  • .cols:数据框中的变量名,默认为所有变量;

  • .fns:处理函数;

  • .names:处理后输出的变量名称。

.names参数使用胶水函数对变量进行命名:

  • {.col}代表输入变量的列名,{.fn}代表处理函数名;

  • 默认输出变量名同输入变量名,当有多个处理函数时,默认使用下划线加函数名进行命名。

该函数常用于分类汇总。比如要统计mtcars中各变量的平均数,在不使用colwise操作的情况下,程序书写会很繁琐:

data %>%
  group_by(cyl) %>%
  summarise(v1 = mean(mpg),
            v2 = mean(wt),
            v3 = mean(qsec))

## # A tibble: 3 x 4
##     cyl    v1    v2    v3
## * <dbl> <dbl> <dbl> <dbl>
## 1     4  26.7  2.29  19.1
## 2     6  19.7  3.12  18.0
## 3     8  15.1  4.00  16.8
  • 这里仅以三个变量为例。

使用colwise操作的程序如下:

data %>%
  group_by(cyl) %>%
  summarise(across(everything(), mean,
                   .names = "mean_{.col}"))

## # A tibble: 3 x 11
##     cyl mean_mpg mean_disp mean_hp mean_drat mean_wt mean_qsec mean_vs mean_am
## * <dbl>    <dbl>     <dbl>   <dbl>     <dbl>   <dbl>     <dbl>   <dbl>   <dbl>
## 1     4     26.7      105.    82.6      4.07    2.29      19.1   0.909   0.727
## 2     6     19.7      183.   122.       3.59    3.12      18.0   0.571   0.429
## 3     8     15.1      353.   209.       3.23    4.00      16.8   0       0.143
## # ... with 2 more variables: mean_gear <dbl>, mean_carb <dbl>

这里还使用了辅助函数everything,表示选择所有变量。如果只针对个别变量,程序如下:

data %>%
  group_by(cyl) %>%
  summarise(across(c(mpg, disp, hp), mean,
                   .names = "mean_{.col}"))

## # A tibble: 3 x 4
##     cyl mean_mpg mean_disp mean_hp
## * <dbl>    <dbl>     <dbl>   <dbl>
## 1     4     26.7      105.    82.6
## 2     6     19.7      183.   122. 
## 3     8     15.1      353.   209.

当变量的列序号是相连的时,还可以使用冒号:进行简写:

data %>%
  group_by(cyl) %>%
  summarise(across(c(mpg:hp), mean,
                   .names = "mean_{.col}"))

## # A tibble: 3 x 4
##     cyl mean_mpg mean_disp mean_hp
## * <dbl>    <dbl>     <dbl>   <dbl>
## 1     4     26.7      105.    82.6
## 2     6     19.7      183.   122. 
## 3     8     15.1      353.   209.

处理函数有多个时,使用list函数储存相应的函数:

data %>%
  group_by(cyl) %>%
  summarise(across(c(mpg:hp), list(mean, var),
                   .names = "{.fn}_{.col}"))

## # A tibble: 3 x 7
##     cyl `1_mpg` `2_mpg` `1_disp` `2_disp` `1_hp` `2_hp`
## * <dbl>   <dbl>   <dbl>    <dbl>    <dbl>  <dbl>  <dbl>
## 1     4    26.7   20.3      105.     722.   82.6   438.
## 2     6    19.7    2.11     183.    1727.  122.    589.
## 3     8    15.1    6.55     353.    4593.  209.   2599.

purrr包中的map族函数一样,across也支持匿名函数。此外,across函数也可以与summarise之外的函数配合使用,这里使用mutate函数:

data %>%
  mutate(across(c(mpg:hp), ~ .x^2)) %>%
  head()

# Mazda RX4         441.00  36  25600 12100 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag     441.00  36  25600 12100 3.90 2.875 17.02  0  1    4    4
## Datsun 710        519.84  16  11664  8649 3.85 2.320 18.61  1  1    4    1
## Hornet 4 Drive    457.96  36  66564 12100 3.08 3.215 19.44  1  0    3    1
## Hornet Sportabout 349.69  64 129600 30625 3.15 3.440 17.02  0  0    3    2
## Valiant           327.61  36  50625 11025 2.76 3.460 20.22  1  0    3    1

1.2 辅助函数

当待处理的变量的命名具有一定规律时,可以借助一些辅助函数来简化程序。

  • 变量名具有相同前缀时,可以使用starts_with函数

如计算名称以d开头的变量的平均值:

data %>%
  group_by(cyl) %>%
  summarise(across(starts_with("d"), mean))

## # A tibble: 3 x 3
##     cyl  disp  drat
## * <dbl> <dbl> <dbl>
## 1     4  105.  4.07
## 2     6  183.  3.59
## 3     8  353.  3.23
  • 变量名具有相同后缀时,可以使用ends_with函数

data %>%
  group_by(cyl) %>%
  summarise(across(ends_with("p"), mean))

## # A tibble: 3 x 3
##     cyl  disp    hp
## * <dbl> <dbl> <dbl>
## 1     4  105.  82.6
## 2     6  183. 122. 
## 3     8  353. 209.
  • 变量满足一定条件,可以使用where函数

where函数来自tidyselect工具包。

data %>%
  mutate(across(mpg:drat, as.factor)) %>%
  group_by(cyl) %>%
  summarise(across(where(is.numeric), mean))

## # A tibble: 3 x 7
##   cyl      wt  qsec    vs    am  gear  carb
## * <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 4      2.29  19.1 0.909 0.727  4.09  1.55
## 2 6      3.12  18.0 0.571 0.429  3.86  3.43
## 3 8      4.00  16.8 0     0.143  3.29  3.5
  • mtcar中的变量原本均为数值类型,这里先将mpg:drat之间的变量转为因子类型后,再在across函数中使用where函数判断变量是否为数值类型,则已被转为因子类型的变量就不在此列了。

1.3 if_anyif_all函数

这两个函数主要与行筛选函数filter配合使用。语法结构与across函数类似,但.fns参数对应的处理函数的返回值应为逻辑类型:

  • if_any:该行任意一个选中的列的元素在.fns函数中返回值为TRUE,则该行就会被filter函数筛选出来;

  • if_any:该行所有被选中的列的元素在.fns函数中返回值为TRUE,则该行才会被filter函数筛选出来。

data %>%
  filter(if_any(c(mpg, cyl), ~ (.x %% 3 == 0)))

##                 mpg cyl  disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4      21.0   6 160.0 110 3.90 2.620 16.46  0  1    4    4
## Mazda RX4 Wag  21.0   6 160.0 110 3.90 2.875 17.02  0  1    4    4
## Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3    1
## Valiant        18.1   6 225.0 105 2.76 3.460 20.22  1  0    3    1
## Merc 280       19.2   6 167.6 123 3.92 3.440 18.30  1  0    4    4
## Merc 280C      17.8   6 167.6 123 3.92 3.440 18.90  1  0    4    4
## Ferrari Dino   19.7   6 145.0 175 3.62 2.770 15.50  0  1    5    6
## Maserati Bora  15.0   8 301.0 335 3.54 3.570 14.60  0  1    5    8
data %>%
  filter(if_all(c(mpg, cyl), ~ (.x %% 3 == 0)))

##               mpg cyl disp  hp drat    wt  qsec vs am gear carb
## Mazda RX4      21   6  160 110  3.9 2.620 16.46  0  1    4    4
## Mazda RX4 Wag  21   6  160 110  3.9 2.875 17.02  0  1    4    4

2 rowwise

rowwise也来自dplyr包,但它本身也是一个函数,功能类似于group_by函数。

2.1 rowwise函数

在不使用rowwise操作时,对多列变量使用mean函数,其计算的是这些列所有元素的平均值,因此得到的结果对于每行是相同的:

data %>%
  mutate(M = mean(c(mpg, cyl, disp, hp))) %>%
  head()

##                    mpg cyl disp  hp drat    wt  qsec vs am gear carb        M
## Mazda RX4         21.0   6  160 110 3.90 2.620 16.46  0  1    4    4 100.9219
## Mazda RX4 Wag     21.0   6  160 110 3.90 2.875 17.02  0  1    4    4 100.9219
## Datsun 710        22.8   4  108  93 3.85 2.320 18.61  1  1    4    1 100.9219
## Hornet 4 Drive    21.4   6  258 110 3.08 3.215 19.44  1  0    3    1 100.9219
## Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2 100.9219
## Valiant           18.1   6  225 105 2.76 3.460 20.22  1  0    3    1 100.9219

使用rowwise函数后,其计算的是这些列每行的平均值:

data %>%
  rowwise() %>%
  mutate(M = mean(c(mpg, cyl, disp, hp))) %>%
  head()

## # A tibble: 6 x 12
## # Rowwise: 
##     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb     M
##   <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1  21       6   160   110  3.9   2.62  16.5     0     1     4     4  74.2
## 2  21       6   160   110  3.9   2.88  17.0     0     1     4     4  74.2
## 3  22.8     4   108    93  3.85  2.32  18.6     1     1     4     1  57.0
## 4  21.4     6   258   110  3.08  3.22  19.4     1     0     3     1  98.8
## 5  18.7     8   360   175  3.15  3.44  17.0     0     0     3     2 140. 
## 6  18.1     6   225   105  2.76  3.46  20.2     1     0     3     1  88.5

与分类汇总函数连用:

data %>%
  rowwise(mpg:hp) %>%
  summarise(M = mean(c(mpg, cyl, disp, hp)))

## # A tibble: 32 x 5
## # Groups:   mpg, cyl, disp, hp [31]
##      mpg   cyl  disp    hp     M
##    <dbl> <dbl> <dbl> <dbl> <dbl>
##  1  21       6  160    110  74.2
##  2  21       6  160    110  74.2
##  3  22.8     4  108     93  57.0
##  4  21.4     6  258    110  98.8
##  5  18.7     8  360    175 140. 
##  6  18.1     6  225    105  88.5
##  7  14.3     8  360    245 157. 
##  8  24.4     4  147.    62  59.3
##  9  22.8     4  141.    95  65.6
## 10  19.2     6  168.   123  79.0
## # ... with 22 more rows

2.2 c_across函数

c_across的功能类似于across函数,但它只有一个参数:

c_across(cols = everything())
data %>%
  rowwise() %>%
  mutate(M = mean(c_across(mpg:hp)))

## # A tibble: 32 x 12
## # Rowwise: 
##      mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb     M
##    <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
##  1  21       6  160    110  3.9   2.62  16.5     0     1     4     4  74.2
##  2  21       6  160    110  3.9   2.88  17.0     0     1     4     4  74.2
##  3  22.8     4  108     93  3.85  2.32  18.6     1     1     4     1  57.0
##  4  21.4     6  258    110  3.08  3.22  19.4     1     0     3     1  98.8
##  5  18.7     8  360    175  3.15  3.44  17.0     0     0     3     2 140. 
##  6  18.1     6  225    105  2.76  3.46  20.2     1     0     3     1  88.5
##  7  14.3     8  360    245  3.21  3.57  15.8     0     0     3     4 157. 
##  8  24.4     4  147.    62  3.69  3.19  20       1     0     4     2  59.3
##  9  22.8     4  141.    95  3.92  3.15  22.9     1     0     4     2  65.6
## 10  19.2     6  168.   123  3.92  3.44  18.3     1     0     4     4  79.0
## # ... with 22 more rows
  • 这里变量列序号是相连的,可以使用冒号:简化程序。


  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值