【问题标题】:split columns with delimiters and multiple categories in R在 R 中使用分隔符和多个类别拆分列
【发布时间】:2018-04-16 21:52:14
【问题描述】:

我有一个凌乱的表格,其中有一列包含多个类别标签,由几个分隔符分隔。我希望我们 R 在每个分隔符处拆分该列,并为每个类别标签创建一个新列。我见过的方法一次只能拆分一个分隔符。

我当前的表格如下所示:

my_table = read.csv("./my_table.csv")
# > my_table
#   ID       TYPE          TEXT
# 1  1          a    blue water
# 2  2      a,b,c   fresh water
# 3  3      a;b,f   cold stream
# 4  4 f, b and c lovely sunset
# 5  5        b;c      up there

我想要一个如下所示的表格:

#   ID A B C D          TEXT
# 1  1 a          blue water
# 2  2 a b c     fresh water
# 3  3 a b   d   cold stream
# 4  4   b c d lovely sunset
# 5  5   b c        up there

这是我尝试过的:

my_table1 <- my_table %>%
  separate(TYPE, c('A', 'B'), ",")
my_table1
# > docs1
#   ID   A        B          TEXT
# 1  1   a     <NA>    blue water
# 2  2   a        b   fresh water
# 3  3 a;b        f   cold stream
# 4  4   f  b and c lovely sunset
# 5  5 b;c     <NA>      up there

my_table2 <- my_table1 %>%
  separate(A, c('A', 'C' ), ";")
# > docs2
#   ID A    C        B          TEXT
# 1  1 a <NA>     <NA>    blue water
# 2  2 a <NA>        b   fresh water
# 3  3 a    b        f   cold stream
# 4  4 f <NA>  b and c lovely sunset
# 5  5 b    c     <NA>      up there

my_table3 <- my_table2 %>%
  separate(A, c('A', 'D'), "and")
# > docs3
#   ID A    D    C        B          TEXT
# 1  1 a <NA> <NA>     <NA>    blue water
# 2  2 a <NA> <NA>        b   fresh water
# 3  3 a <NA>    b        f   cold stream
# 4  4 f <NA> <NA>  b and c lovely sunset
# 5  5 b <NA>    c     <NA>      up there

这让我很接近,但列名已关闭。另外,我不想猜测字符串“b 和 c”在几次迭代后结束的位置。我有数千行,可能有五六个类别。我的猜测是有一种更简单的方法可以做到这一点。

【问题讨论】:

  • 你能给我一点dput你的桌子吗?

标签: r split multiple-columns


【解决方案1】:

作为替代方案并扩展您的tidyverse 尝试,这是使用strsplitunnest 的解决方案:

df %>%
    mutate(
        val = strsplit(as.character(TYPE), "(;|,\\s*|\\s*and\\s*)")) %>%
    unnest() %>%
    select(-TYPE) %>%
    group_by(ID, TEXT) %>%
    mutate(n = 1:n()) %>%
    spread(n, val)
## A tibble: 5 x 5
## Groups:   ID, TEXT [5]
#     ID TEXT          `1`   `2`   `3`
#  <int> <fct>         <chr> <chr> <chr>
#1     1 blue water    a     NA    NA
#2     2 fresh water   a     b     c
#3     3 cold stream   a     b     f
#4     4 lovely sunset f     b     c
#5     5 up there      b     c     NA

请注意,这与您的预期输出不完全相同。然而,它与@MKR 的输出相匹配。


样本数据

df <- read.table(text =
    "ID       TYPE          TEXT
1  1          'a'    'blue water'
2  2      'a,b,c'   'fresh water'
3  3      'a;b,f'   'cold stream'
4  4 'f, b and c' 'lovely sunset'
5  5        'b;c'      'up there'")

【讨论】:

    【解决方案2】:

    splitstackshape 包中的cSplit 函数可以使问题更容易解决。一种方法可以是:

    library(splitstackshape)
    
    # First use `gsub` to replace other delimiter and have only ',' delimiter. 
    my_table$TYPE <- gsub("and|;",",",my_table$TYPE)
    
    Mod_df <- cSplit(my_table, "TYPE", sep = ",")
    
    Mod_df
    #    ID          TEXT TYPE_1 TYPE_2 TYPE_3
    # 1:  1    blue water      a     NA     NA
    # 2:  2   fresh water      a      b      c
    # 3:  3   cold stream      a      b      f
    # 4:  4 lovely sunset      f      b      c
    # 5:  5      up there      b      c     NA
    

    tidyr::gatherspread 可用于获取 OP 提到的格式为:

    library(tidyr)
    
    gather(Mod_df, key, value, -ID,-TEXT) %>% mutate_if(is.factor, as.character) %>%
      mutate(K = toupper(value)) %>%
      select(-key) %>%
      filter(!is.na(K)) %>%
      spread(K, value)
    # ID          TEXT    A    B    C    F
    # 1  1    blue water    a <NA> <NA> <NA>
    # 2  2   fresh water    a    b    c <NA>
    # 3  3   cold stream    a    b <NA>    f
    # 4  4 lovely sunset <NA>    b    c    f
    # 5  5      up there <NA>    b    c <NA>
    

    数据

    my_table <- read.table(text = 
    "  ID       TYPE          TEXT
    1  1          a    'blue water'
    2  2      'a,b,c'   'fresh water'
    3  3      'a;b,f'   'cold stream'
    4  4 'f, b and c' 'lovely sunset'
    5  5        'b;c'      'up there'",
    header = TRUE, stringsAsFactors = FALSE)
    

    【讨论】:

    • 好的,这非常接近我的需要。使用 gsub() 很有意义。我可以使用它。谢谢@MKR
    • @TheLousyLinguist 我已将解决方案扩展为使用spreadgather。可能它会带你到你需要的格式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-07
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多