3.5 字符处理

有时候我们要将多个变量合并到一列中,或者分离为单独的列。tidyr 中提供了一组函数实现该部分功能。

3.5.1 新列提取

extract()函数将字符列提取为多列。所以该函数能实现的功能,大部分基于对正则表达式的使用。和 Excel 中的 Ctrl + E用法类似。

3.5.1.1 参数

extract(
  data,
  col,
  into,
  regex = "([[:alnum:]]+)",
  remove = TRUE,
  convert = FALSE,
  ...
)

data : 一个数据框

col : 被提取的列

into : 新列名

regex : 提取所需值的正则表达式

remove : 默认为 FALSE ,如果为TRUE,将从输出的数据框中删除输入列

3.5.1.2 案例

df <- data.frame(x = c(NA, "a-b", "a-d", "b-c", "d-e"))
df %>% extract(x, "A")
#>      A
#> 1 <NA>
#> 2    a
#> 3    a
#> 4    b
#> 5    d
df %>% extract(x, c("A", "B"), "([[:alnum:]]+)-([[:alnum:]]+)")
#>      A    B
#> 1 <NA> <NA>
#> 2    a    b
#> 3    a    d
#> 4    b    c
#> 5    d    e

[:alnum:] 匹配任何字母,[:alpha:] 匹配任何字母和数字

df <- data.frame(x = c("1992-04", "1992-05", "1992-06", "1992-07", "1992-08", "1992-09", "1992-10", "1992-11", "1992-12"))

df %>% 
    extract(col = x,into = c('年','月'),regex = "([1-9]{4})-([0-9]{2})")
#>     年 月
#> 1 1992 04
#> 2 1992 05
#> 3 1992 06
#> 4 1992 07
#> 5 1992 08
#> 6 1992 09
#> 7 1992 10
#> 8 1992 11
#> 9 1992 12

# 字符转化为数字
df %>% 
    extract(col = x,into = c('年','月'),regex = "([1-9]{4})-([0-9]{2})",convert = TRUE)
#>     年 月
#> 1 1992  4
#> 2 1992  5
#> 3 1992  6
#> 4 1992  7
#> 5 1992  8
#> 6 1992  9
#> 7 1992 10
#> 8 1992 11
#> 9 1992 12

正则表达式([1-9]{4})-([0-9]{2})代表:字符分为两部分,中间用“-”连接,前半部分匹配1-9中的任意4位数,后半部分匹配0-9中任意两位数。

3.5.2 拆分

有时我们需要将一列拆分为多列,使用separate()函数。

3.5.2.1 参数

separate(
  data,
  col,
  into,
  sep = "[^[:alnum:]]+",
  remove = TRUE,
  convert = FALSE,
  extra = "warn",
  fill = "warn",
  ...
)

参数 sep 指定列之间的分隔符,sep 参数为字符时被解释为正则表达式,默认值是匹配任何非字母数字的正则表达式

df <- data.frame(x = c(NA, "a.b", "a.d", "b.c"))
df %>% separate(col = x, into = c("A", "B"))
#>      A    B
#> 1 <NA> <NA>
#> 2    a    b
#> 3    a    d
#> 4    b    c

3.5.2.2 案例

#sep 参数为字符时被解释为正则表达式,默认值是匹配任何非字母数字的正则表达式
df %>% separate(col = x, into = c("A", "B"))
#>      A    B
#> 1 <NA> <NA>
#> 2    a    b
#> 3    a    d
#> 4    b    c

# 同上
df %>% separate(x, c("A", "B"),sep = '\\.')  
#>      A    B
#> 1 <NA> <NA>
#> 2    a    b
#> 3    a    d
#> 4    b    c

# 只要第二个变量
df %>% separate(x, c(NA, "B"))
#>      B
#> 1 <NA>
#> 2    b
#> 3    d
#> 4    c

#sep 参数为数字时被解释为要拆分的字符位置
df %>% separate(x, c("A", "B"),sep = 2) 
#>      A    B
#> 1 <NA> <NA>
#> 2   a.    b
#> 3   a.    d
#> 4   b.    c

拆分时,多列或少列时用NA补齐:

df <- data.frame(x = c("x", "x y", "x y z", NA))
df %>% separate(x, c("a", "b"))
#> Warning: Expected 2 pieces. Additional pieces discarded in 1 rows [3].
#> Warning: Expected 2 pieces. Missing pieces filled with `NA` in 1 rows [1].
#>      a    b
#> 1    x <NA>
#> 2    x    y
#> 3    x    y
#> 4 <NA> <NA>

多余的部分舍弃,缺失填充在左边还是右边:

df %>% separate(x, c("a", "b"), extra = "drop", fill = "right")
#>      a    b
#> 1    x <NA>
#> 2    x    y
#> 3    x    y
#> 4 <NA> <NA>

多余部分合并,缺失填充在左边

df %>% separate(x, c("a", "b"), extra = "merge", fill = "left")
#>      a    b
#> 1 <NA>    x
#> 2    x    y
#> 3    x  y z
#> 4 <NA> <NA>

或者全部保留

df %>% separate(x, c("a", "b", "c"))
#> Warning: Expected 3 pieces. Missing pieces filled with `NA` in 2 rows [1, 2].
#>      a    b    c
#> 1    x <NA> <NA>
#> 2    x    y <NA>
#> 3    x    y    z
#> 4 <NA> <NA> <NA>

指定分隔符

df %>% separate(x, c("key", "value"), sep = ": ", extra = "merge")
#> Warning: Expected 2 pieces. Missing pieces filled with `NA` in 3 rows [1, 2, 3].
#>     key value
#> 1     x  <NA>
#> 2   x y  <NA>
#> 3 x y z  <NA>
#> 4  <NA>  <NA>

使用正则表达式

# Use regular expressions to separate on multiple characters:
df <- data.frame(x = c(NA, "a?b", "a.d", "b:c"))
df %>% separate(x, c("A","B"), sep = "([.?:])")
#>      A    B
#> 1 <NA> <NA>
#> 2    a    b
#> 3    a    d
#> 4    b    c

3.5.3 列拆分行

separate_rows(data, ..., sep = "[^[:alnum:].]+", convert = FALSE)
df <- tibble(
  x = 1:3,
  y = c("a", "d,e,f", "g,h"),
  z = c("1", "2,3,4", "5,6")
)
separate_rows(df, y, z, convert = TRUE)
#> # A tibble: 6 x 3
#>       x y         z
#>   <int> <chr> <int>
#> 1     1 a         1
#> 2     2 d         2
#> 3     2 e         3
#> 4     2 f         4
#> 5     3 g         5
#> 6     3 h         6

3.5.4 合并多列

unite()方便将多列合并一列。

用法

unite(data, col, ..., sep = "_", remove = TRUE, na.rm = FALSE)
df <- data.frame(x = letters[1:6],y = LETTERS[1:6])
df %>% unite("z",x:y,sep="_")
#>     z
#> 1 a_A
#> 2 b_B
#> 3 c_C
#> 4 d_D
#> 5 e_E
#> 6 f_F
df %>% unite("z",x:y,sep="_",remove = FALSE)
#>     z x y
#> 1 a_A a A
#> 2 b_B b B
#> 3 c_C c C
#> 4 d_D d D
#> 5 e_E e E
#> 6 f_F f F

df %>% 
  unite("z",x:y,sep="_") %>% 
  separate(col = z,into = c('x','y'),sep = "_")
#>   x y
#> 1 a A
#> 2 b B
#> 3 c C
#> 4 d D
#> 5 e E
#> 6 f F