数据框批量处理行列

吴诗涛 2023-09-27 [R]

tidyverse 的生态越来越完善,一直把它当超大杯的 Excel 用。这里梳理下批量处理行和列的一些方法,主要会用到:

另外,主要以 \(x) foo(x) 的方式传递匿名函数。

数据准备

library(tidyverse)
df <- tibble(
  x1 = 1:6,
  x2 = c(1:2, NA, 4:5, NA),
  x3 = c(5, 4, 3, NA, 0, NA),
  y = c("A", "C", "B", "B", "A", NA)
)

df
## # A tibble: 6 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     1     1     5 A    
## 2     2     2     4 C    
## 3     3    NA     3 B    
## 4     4     4    NA B    
## 5     5     5     0 A    
## 6     6    NA    NA <NA>

列批量处理

列筛选

全为 NA 的列

# df %>% select(where(~ all(is.na(.))))
df %>% select(where(\(x) all(is.na(x))))
## # A tibble: 6 × 0

含有 NA 的列

# df %>% select(where(~ any(is.na(.))))
df %>% select(where(\(x) any(is.na(x))))
## # A tibble: 6 × 3
##      x2    x3 y    
##   <int> <dbl> <chr>
## 1     1     5 A    
## 2     2     4 C    
## 3    NA     3 B    
## 4     4    NA B    
## 5     5     0 A    
## 6    NA    NA <NA>

也可以使用 df %>% select(where(anyNA))

不含 NA 的列

# df %>% select(where(~ all(!is.na(.))))
df %>% select(where(\(x) all(!is.na(x))))
## # A tibble: 6 × 1
##      x1
##   <int>
## 1     1
## 2     2
## 3     3
## 4     4
## 5     5
## 6     6

缺失值填充

x 开头的列缺失值填 0

df %>% mutate(across(starts_with("x"), \(x) replace_na(x, 0)))
## # A tibble: 6 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     1     1     5 A    
## 2     2     2     4 C    
## 3     3     0     3 B    
## 4     4     4     0 B    
## 5     5     5     0 A    
## 6     6     0     0 <NA>

列排序

x 开头的列全部放在 y 列后。

# 也有 .before 参数
df %>% relocate(starts_with("x"), .after = y)
## # A tibble: 6 × 4
##   y        x1    x2    x3
##   <chr> <int> <int> <dbl>
## 1 A         1     1     5
## 2 C         2     2     4
## 3 B         3    NA     3
## 4 B         4     4    NA
## 5 A         5     5     0
## 6 <NA>      6    NA    NA

列计算

行批量处理

行筛选

全为 NA 的行

df %>% filter(if_all(everything(), is.na))
## # A tibble: 0 × 4
## # ℹ 4 variables: x1 <int>, x2 <int>, x3 <dbl>, y <chr>

含有 NA 的行

df %>% filter(if_any(everything(), is.na))
## # A tibble: 3 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     3    NA     3 B    
## 2     4     4    NA B    
## 3     6    NA    NA <NA>

不含 NA 的行

df %>% filter(!if_any(everything(), is.na))
## # A tibble: 3 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     1     1     5 A    
## 2     2     2     4 C    
## 3     5     5     0 A

行排序

除了按照某些列的值进行排序外,也可以按照自定义的顺序对行排序:

order_y = c("B", "C", "A")              # 定义 order_y 的顺序
df %>% arrange(match(y, order_y), -x1)  # 按照 order_y 和 -x1 的顺序排序
## # A tibble: 6 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     4     4    NA B    
## 2     3    NA     3 B    
## 3     2     2     4 C    
## 4     5     5     0 A    
## 5     1     1     5 A    
## 6     6    NA    NA <NA>

match() 返回需要排序变量中每个元素在参照变量中的位置,返回值是长度与需要排序变量长度相等的数值变量,用 arrange() 对其排序即可。

对于不在自定义顺序中的值,可以通过 match() 函数的 nomatch 参数控制位置:

# 按照 order_y 和 x1 的顺序排序,未匹配到的 y 排在最前面
df %>% arrange(match(y, order_y, nomatch = 0), x1)
## # A tibble: 6 × 4
##      x1    x2    x3 y    
##   <int> <int> <dbl> <chr>
## 1     6    NA    NA <NA> 
## 2     3    NA     3 B    
## 3     4     4    NA B    
## 4     2     2     4 C    
## 5     1     1     5 A    
## 6     5     5     0 A

行向计算

在 R 中,数据框主要以列的方向存储数据,因此行处理时需要特别注意。

比如:对 x 开头的行求和